Skip to content

Conversation

zachs18
Copy link
Contributor

@zachs18 zachs18 commented Aug 24, 2025

When determining if a non-first supertrait vptr can be omitted from a subtrait vtable, check if the supertrait or any of its (transitive) supertraits have methods, instead of only checking if the supertrait itself has methods.

This fixes the soundness issue where a vptr would be omitted for a supertrait with no methods but that itself had a supertrait with methods, while still optimizing the case where the supertrait is "truly" empty (it has no own vtable entries, and none of its (transitive) supertraits have any own vtable entries).

Fixes #145752


Old description:

Treat all non-auto traits as non-empty (possibly having methods) for purposes of determining if we need to emit a vptr for a non-direct supertrait (and for new "sibling" entries after a direct or non-direct supertrait).

This fixes (I believe) the soundness issue, but regresses vtable sizes and possibly upcasting perf in some cases when using trait hierarchies with empty non-auto traits (see tests/ui/traits/vtable/multiple-markers.stderr) since we use vptrs in some cases where we could re-use the vtable.

Fixes #145752

Re-opens (not anymore) #114942

Should not affect #131813 (i.e. the soundness issue is still fixed, though the relevant vtables in the trait Evil example will be larger now)

cc implementation history #131864 #113856


It should be possible to check if a trait has any methods from itself or supertraits (instead of just from itself), but to fix the immediate soundness issue, just assume any non-auto trait could have methods. A more optimistic check can be implemented later (or if someone does it soon it could just supercede this PR 😄). Done in latest push

@rustbot label A-dyn-trait F-trait_upcasting

@rustbot
Copy link
Collaborator

rustbot commented Aug 24, 2025

r? @SparrowLii

rustbot has assigned @SparrowLii.
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

@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. A-dyn-trait Area: trait objects, vtable layout F-trait_upcasting `#![feature(trait_upcasting)]` labels Aug 24, 2025
@jieyouxu
Copy link
Member

@bors try @rust-timer queue

@rust-timer

This comment has been minimized.

@rust-bors

This comment has been minimized.

rust-bors bot added a commit that referenced this pull request Aug 24, 2025
Only consider auto traits empty for the purposes of omitting vptrs from subtrait vtables.
@rustbot rustbot added the S-waiting-on-perf Status: Waiting on a perf run to be completed. label Aug 24, 2025
@rust-bors
Copy link

rust-bors bot commented Aug 24, 2025

☀️ Try build successful (CI)
Build commit: b128140 (b1281401f3d41c9a4c5290caa55cd74176ccc2be, parent: f6d23413c399fb530be362ebcf25a4e788e16137)

@rust-timer

This comment has been minimized.

@rust-timer
Copy link
Collaborator

Finished benchmarking commit (b128140): comparison URL.

Overall result: no relevant changes - no action needed

Benchmarking this pull request means it may be perf-sensitive – we'll automatically label it not fit for rolling up. You can override this, but we strongly advise not to, due to possible changes in compiler perf.

@bors rollup=never
@rustbot label: -S-waiting-on-perf -perf-regression

Instruction count

This benchmark run did not return any relevant results for this metric.

Max RSS (memory usage)

Results (primary 6.0%, secondary 0.4%)

A less reliable metric. May be of interest, but not used to determine the overall result above.

mean range count
Regressions ❌
(primary)
6.0% [6.0%, 6.0%] 1
Regressions ❌
(secondary)
1.6% [1.3%, 2.0%] 2
Improvements ✅
(primary)
- - 0
Improvements ✅
(secondary)
-2.2% [-2.2%, -2.2%] 1
All ❌✅ (primary) 6.0% [6.0%, 6.0%] 1

Cycles

This benchmark run did not return any relevant results for this metric.

Binary size

This benchmark run did not return any relevant results for this metric.

Bootstrap: 468.54s -> 466.319s (-0.47%)
Artifact size: 378.30 MiB -> 378.29 MiB (-0.00%)

@rustbot rustbot removed the S-waiting-on-perf Status: Waiting on a perf run to be completed. label Aug 24, 2025
@@ -153,16 +153,26 @@ fn prepare_vtable_segments_inner<'tcx, T>(

// emit innermost item, move to next sibling and stop there if possible, otherwise jump to outer level.
while let Some((inner_most_trait_ref, emit_vptr, mut siblings)) = stack.pop() {
let has_entries = has_own_existential_vtable_entries(tcx, inner_most_trait_ref.def_id);
Copy link
Member

@compiler-errors compiler-errors Aug 25, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you would like to look at if any of the supertraits (including the trait itself) has entries, you can do something like:

let has_entries = elaborate::supertrait_def_ids(tcx, inner_most_trait_ref.def_id).any(|def_id| has_own_existential_vtable_entries(tcx, def_id));

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice! This is a much better solution

@zachs18 zachs18 force-pushed the only-consider-auto-traits-empty branch from bae9ed3 to 904e83c Compare August 25, 2025 21:16
@zachs18 zachs18 changed the title Only consider auto traits empty for the purposes of omitting vptrs from subtrait vtables. When determining if a trait has no entries for the purposes of omitting vptrs from subtrait vtables, consider a its transitive supertraits' entries, instead of just its own entries. Aug 25, 2025
@zachs18 zachs18 changed the title When determining if a trait has no entries for the purposes of omitting vptrs from subtrait vtables, consider a its transitive supertraits' entries, instead of just its own entries. When determining if a trait has no entries for the purposes of omitting vptrs from subtrait vtables, consider its transitive supertraits' entries, instead of just its own entries. Aug 25, 2025
@compiler-errors
Copy link
Member

@bors r+

@bors
Copy link
Collaborator

bors commented Aug 28, 2025

📌 Commit 904e83c has been approved by compiler-errors

It is now in the queue for this repository.

@bors bors 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 Aug 28, 2025
@bors
Copy link
Collaborator

bors commented Aug 28, 2025

⌛ Testing commit 904e83c with merge 35d55b3...

@bors
Copy link
Collaborator

bors commented Aug 28, 2025

☀️ Test successful - checks-actions
Approved by: compiler-errors
Pushing 35d55b3 to master...

@bors bors added the merged-by-bors This PR was explicitly merged by bors. label Aug 28, 2025
@bors bors merged commit 35d55b3 into rust-lang:master Aug 28, 2025
11 checks passed
@rustbot rustbot added this to the 1.91.0 milestone Aug 28, 2025
Copy link
Contributor

What is this? This is an experimental post-merge analysis report that shows differences in test outcomes between the merged PR and its parent PR.

Comparing 1f7dcc8 (parent) -> 35d55b3 (this PR)

Test differences

Show 8 test diffs

Stage 1

  • [ui] tests/ui/traits/vtable/empty-supertrait-with-nonempty-supersupertrait.rs#dump: [missing] -> pass (J1)
  • [ui] tests/ui/traits/vtable/empty-supertrait-with-nonempty-supersupertrait.rs#run: [missing] -> pass (J1)
  • [ui] tests/ui/traits/vtable/multiple-auto.rs: [missing] -> pass (J1)

Stage 2

  • [ui] tests/ui/traits/vtable/empty-supertrait-with-nonempty-supersupertrait.rs#dump: [missing] -> pass (J0)
  • [ui] tests/ui/traits/vtable/empty-supertrait-with-nonempty-supersupertrait.rs#run: [missing] -> pass (J0)
  • [ui] tests/ui/traits/vtable/multiple-auto.rs: [missing] -> pass (J0)

Additionally, 2 doctest diffs were found. These are ignored, as they are noisy.

Job group index

Test dashboard

Run

cargo run --manifest-path src/ci/citool/Cargo.toml -- \
    test-dashboard 35d55b34bffd51384ac430cc20852b7d16dd5a90 --output-dir test-dashboard

And then open test-dashboard/index.html in your browser to see an overview of all executed tests.

Job duration changes

  1. dist-aarch64-linux: 6239.5s -> 8607.2s (37.9%)
  2. pr-check-1: 1665.3s -> 1392.5s (-16.4%)
  3. x86_64-gnu-nopt: 7304.1s -> 8357.4s (14.4%)
  4. x86_64-gnu-llvm-19: 2842.9s -> 2460.4s (-13.5%)
  5. dist-apple-various: 5788.8s -> 5049.3s (-12.8%)
  6. aarch64-gnu-llvm-19-1: 4155.6s -> 3727.6s (-10.3%)
  7. tidy: 201.6s -> 181.8s (-9.8%)
  8. aarch64-msvc-2: 5385.9s -> 4897.9s (-9.1%)
  9. i686-gnu-2: 6201.9s -> 5693.6s (-8.2%)
  10. dist-x86_64-apple: 8360.4s -> 7688.7s (-8.0%)
How to interpret the job duration changes?

Job durations can vary a lot, based on the actual runner instance
that executed the job, system noise, invalidated caches, etc. The table above is provided
mostly for t-infra members, for simpler debugging of potential CI slow-downs.

@rust-timer
Copy link
Collaborator

Finished benchmarking commit (35d55b3): comparison URL.

Overall result: no relevant changes - no action needed

@rustbot label: -perf-regression

Instruction count

This benchmark run did not return any relevant results for this metric.

Max RSS (memory usage)

Results (secondary 1.7%)

A less reliable metric. May be of interest, but not used to determine the overall result above.

mean range count
Regressions ❌
(primary)
- - 0
Regressions ❌
(secondary)
1.7% [1.7%, 1.7%] 1
Improvements ✅
(primary)
- - 0
Improvements ✅
(secondary)
- - 0
All ❌✅ (primary) - - 0

Cycles

This benchmark run did not return any relevant results for this metric.

Binary size

This benchmark run did not return any relevant results for this metric.

Bootstrap: 465.563s -> 466.374s (0.17%)
Artifact size: 388.46 MiB -> 388.50 MiB (0.01%)

@theemathas
Copy link
Contributor

Beta-nominating, since it's a fix to a critical soundness bug. (Affects rust since version 1.86.0, when trait upcasting stabilized.)

@rustbot labels +beta-nominated

@rustbot rustbot added the beta-nominated Nominated for backporting to the compiler in the beta channel. label Aug 29, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-dyn-trait Area: trait objects, vtable layout beta-nominated Nominated for backporting to the compiler in the beta channel. F-trait_upcasting `#![feature(trait_upcasting)]` merged-by-bors This PR was explicitly merged by bors. 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.

SIGSEGV without unsafe when passing &dyn Trait to &dyn ParentTrait
8 participants