Skip to content

[debugger visualizers] Add workaround to read Rc strong/weak counts - #163098

Merged
rust-bors[bot] merged 1 commit into
rust-lang:mainfrom
Walnut356:rc_usize
Sep 28, 2026
Merged

rust-bors[bot] merged 1 commit into
rust-lang:mainfrom
Walnut356:rc_usize

Conversation

@Walnut356

Copy link
Copy Markdown
Contributor

Implements a fix with the same goal as #162725 of removing the infinite loop. Since RcInner is #[repr(C)], we can just directly read the values from their known offsets. Worth noting that LLDB fails to even populate the fields and offsets when this bug occurs, so #[repr(C)] is a required invariant to retrieve the values from addresses like this:

(lldb) script lldb.frame.var("holder").GetNonSyntheticValue().GetChildAtIndex(0).GetChildAtIndex(0).GetChildAtIndex(0).GetType().GetPointeeType()

template<> struct RcInner<unsigned int> {
private:
    unsigned int value;
}

That RcInner should have a strong and weak field, but because LLDB can't read the type node, it omits them entirely. Thankfully, the value field is still read correctly and has an accurate offset.

This change has 1 small side effect, which is that the weak count is not decremented before it is displayed to the user. We can easily do that in the summary function, but imo it feels weird to lie about the value in memory? The weak count starts at 1 because the original Rc instance "holds" both a strong and a weak reference. It's mostly an artifact of Rc's implementation, but if you're debugging, that seems like something that might matter.

@rustbot rustbot added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. labels Sep 21, 2026
@rustbot

rustbot commented Sep 21, 2026

Copy link
Copy Markdown
Collaborator

r? @Mark-Simulacrum

rustbot has assigned @Mark-Simulacrum.
They will have a look at your PR within the next two weeks and either review your PR or reassign to another reviewer.

Use r? to explicitly pick a reviewer

Why was this reviewer chosen?

The reviewer was selected based on:

  • Owners of files modified in this PR: @Mark-Simulacrum

@Mark-Simulacrum

Copy link
Copy Markdown
Member

@bors r+

I agree that visualizing with a changed count makes little sense -- if we want that we should at least use a different field name. But I'm comfortable with this.

@rust-bors

rust-bors Bot commented Sep 27, 2026

Copy link
Copy Markdown
Contributor

📌 Commit b799651 has been approved by Mark-Simulacrum

It is now in the queue for this repository.

@rust-bors rust-bors Bot added S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Sep 27, 2026
jhpratt added a commit to jhpratt/rust that referenced this pull request Sep 27, 2026
[debugger visualizers] Add workaround to read `Rc` strong/weak counts

Implements a fix with the same goal as rust-lang#162725 of removing the infinite loop. Since `RcInner` is `#[repr(C)]`, we can just directly read the values from their known offsets. Worth noting that LLDB fails to even populate the fields and offsets when this bug occurs, so `#[repr(C)]` is a required invariant to retrieve the values from addresses like this:

```
(lldb) script lldb.frame.var("holder").GetNonSyntheticValue().GetChildAtIndex(0).GetChildAtIndex(0).GetChildAtIndex(0).GetType().GetPointeeType()

template<> struct RcInner<unsigned int> {
private:
    unsigned int value;
}
```

That `RcInner` should have a `strong` and `weak` field, but because LLDB can't read the type node, it omits them entirely. Thankfully, the `value` field is still read correctly and has an accurate offset.

This change has 1 small side effect, which is that the `weak` count is not decremented before it is displayed to the user. We can easily do that in the summary function, but imo it feels weird to lie about the value in memory? The `weak` count starts at 1 because the original `Rc` instance "holds" both a strong and a weak reference. It's mostly an artifact of `Rc`'s implementation, but if you're debugging, that seems like something that might matter.
rust-bors Bot pushed a commit that referenced this pull request Sep 28, 2026
Rollup of 11 pull requests

Successful merges:

 - #163085 (Suggest similarly named modules in import paths)
 - #163098 ([debugger visualizers] Add workaround to read `Rc` strong/weak counts)
 - #163120 (ci: make musl.sh look for patches next to the script)
 - #163301 (Fix unused_must_use for scenario which may need to keep value)
 - #163307 (Less `SpanData` in diagnostics)
 - #152972 (implement PartialEq<VecDeque<U>> for Vec<T>, &[T], &mut [T], [T; N], &[T; N] and &mut [T; N])
 - #162536 (Implement Default for NumBuffer)
 - #163141 (Document safety requirements for intrinsic fallbacks)
 - #163384 (Various clean-ups around `LayoutCalculator`)
 - #163405 (Remove some #[linkage] options)
 - #163413 (mailmap: add Matilde Morrone)
rust-bors Bot pushed a commit that referenced this pull request Sep 28, 2026
Rollup of 11 pull requests

Successful merges:

 - #163085 (Suggest similarly named modules in import paths)
 - #163098 ([debugger visualizers] Add workaround to read `Rc` strong/weak counts)
 - #163120 (ci: make musl.sh look for patches next to the script)
 - #163301 (Fix unused_must_use for scenario which may need to keep value)
 - #163307 (Less `SpanData` in diagnostics)
 - #163389 (`rustc_builtin_macros` cleanup, part 7)
 - #152972 (implement PartialEq<VecDeque<U>> for Vec<T>, &[T], &mut [T], [T; N], &[T; N] and &mut [T; N])
 - #162536 (Implement Default for NumBuffer)
 - #163141 (Document safety requirements for intrinsic fallbacks)
 - #163384 (Various clean-ups around `LayoutCalculator`)
 - #163413 (mailmap: add Matilde Morrone)
@rust-bors
rust-bors Bot merged commit 682cbc4 into rust-lang:main Sep 28, 2026
13 checks passed
@rustbot rustbot added this to the 1.101.0 milestone Sep 28, 2026
rust-bors Bot pushed a commit that referenced this pull request Sep 28, 2026
Rollup merge of #163098 - Walnut356:rc_usize, r=Mark-Simulacrum

[debugger visualizers] Add workaround to read `Rc` strong/weak counts

Implements a fix with the same goal as #162725 of removing the infinite loop. Since `RcInner` is `#[repr(C)]`, we can just directly read the values from their known offsets. Worth noting that LLDB fails to even populate the fields and offsets when this bug occurs, so `#[repr(C)]` is a required invariant to retrieve the values from addresses like this:

```
(lldb) script lldb.frame.var("holder").GetNonSyntheticValue().GetChildAtIndex(0).GetChildAtIndex(0).GetChildAtIndex(0).GetType().GetPointeeType()

template<> struct RcInner<unsigned int> {
private:
    unsigned int value;
}
```

That `RcInner` should have a `strong` and `weak` field, but because LLDB can't read the type node, it omits them entirely. Thankfully, the `value` field is still read correctly and has an accurate offset.

This change has 1 small side effect, which is that the `weak` count is not decremented before it is displayed to the user. We can easily do that in the summary function, but imo it feels weird to lie about the value in memory? The `weak` count starts at 1 because the original `Rc` instance "holds" both a strong and a weak reference. It's mostly an artifact of `Rc`'s implementation, but if you're debugging, that seems like something that might matter.
github-actions Bot pushed a commit to rust-lang/rust-analyzer that referenced this pull request Oct 1, 2026
Rollup of 11 pull requests

Successful merges:

 - rust-lang/rust#163085 (Suggest similarly named modules in import paths)
 - rust-lang/rust#163098 ([debugger visualizers] Add workaround to read `Rc` strong/weak counts)
 - rust-lang/rust#163120 (ci: make musl.sh look for patches next to the script)
 - rust-lang/rust#163301 (Fix unused_must_use for scenario which may need to keep value)
 - rust-lang/rust#163307 (Less `SpanData` in diagnostics)
 - rust-lang/rust#163389 (`rustc_builtin_macros` cleanup, part 7)
 - rust-lang/rust#152972 (implement PartialEq<VecDeque<U>> for Vec<T>, &[T], &mut [T], [T; N], &[T; N] and &mut [T; N])
 - rust-lang/rust#162536 (Implement Default for NumBuffer)
 - rust-lang/rust#163141 (Document safety requirements for intrinsic fallbacks)
 - rust-lang/rust#163384 (Various clean-ups around `LayoutCalculator`)
 - rust-lang/rust#163413 (mailmap: add Matilde Morrone)
@Walnut356 Walnut356 mentioned this pull request Oct 3, 2026
18 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants