Skip to content

Do not assert layout in KnownPanicsLint. #144226

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 5 commits into
base: master
Choose a base branch
from

Conversation

cjgillot
Copy link
Contributor

@cjgillot cjgillot commented Jul 20, 2025

Fixes #121176
Fixes #129109
Fixes #130970
Fixes #131347
Fixes #139872
Fixes #140332

@rustbot
Copy link
Collaborator

rustbot commented Jul 20, 2025

r? @davidtwco

rustbot has assigned @davidtwco.
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. labels Jul 20, 2025
@rustbot
Copy link
Collaborator

rustbot commented Jul 20, 2025

Some changes occurred to the CTFE / Miri interpreter

cc @rust-lang/miri

This PR changes a file inside tests/crashes. If a crash was fixed, please move into the corresponding ui subdir and add 'Fixes #' to the PR description to autoclose the issue upon merge.

Some changes occurred to MIR optimizations

cc @rust-lang/wg-mir-opt

Some changes occurred to the CTFE machinery

cc @RalfJung, @oli-obk, @lcnr

@@ -243,6 +243,17 @@ impl<'tcx, Prov: Provenance> std::ops::Deref for ImmTy<'tcx, Prov> {
}

impl<'tcx, Prov: Provenance> ImmTy<'tcx, Prov> {
#[inline(always)]
pub fn try_from_immediate(imm: Immediate<Prov>, layout: TyAndLayout<'tcx>) -> Option<Self> {
Copy link
Member

@RalfJung RalfJung Jul 20, 2025

Choose a reason for hiding this comment

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

I'm not a fan of these functions. The point of the assertions is that they are a last line of defense to detect defective callers. They are not exhaustive checks. If the caller can't ensure that the value has the right type, that can only be fixed in the caller.

IOW, matches_abi here really is more of a maybe_matches_abi. It is necessary, but not sufficient. And trying to make it sufficient is the wrong approach; the right approach is figuring out why someone is feeding bogus data into these functions.


use std::fmt::Debug;

static STATIC_1: dyn Debug + Sync = *();
Copy link
Member

@RalfJung RalfJung Jul 20, 2025

Choose a reason for hiding this comment

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

For instance, this is a clearly ill-formed static. Nothing should ever look at its MIR. Trying to make the MIR interpreter APIs resistant against bogus MIR is a pointless game of whack-a-mole.

Copy link
Contributor

Choose a reason for hiding this comment

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

yea those cases are straight forward to prevent within type_of, we don't even need to compute the layout, just doing a sizedness check.

Copy link
Member

Choose a reason for hiding this comment

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

That doesn't quite work since we allow extern statics that have extern types, which are unsized.

Copy link
Contributor

Choose a reason for hiding this comment

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

Well, we can check the tail manually for slices and dyn trait

Copy link
Member

Choose a reason for hiding this comment

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

But that requires unfolding the type which will trigger the same cycle error, won't it?

Copy link
Member

@RalfJung RalfJung left a comment

Choose a reason for hiding this comment

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

These all seem to be standard cases of "ill-formed MIR gets too far into the pipeline". We should never run any MIR passes on ill-formed MIR; it is a waste of effort to try and fix this inside every individual pass.

@cjgillot
Copy link
Contributor Author

cjgillot commented Jul 20, 2025

These all seem to be standard cases of "ill-formed MIR gets too far into the pipeline". We should never run any MIR passes on ill-formed MIR; it is a waste of effort to try and fix this inside every individual pass.

I agree, but fixing this is general is hard too. We have an ImpossiblePredicates pass to skip this kind of nonsense, but it is quite limited to avoid query cycles. And it cannot handle nonsense that spans multiple items.

A "cleaner" way would be to ensure we never produce a constant with mismatching ABI, be it as a ConstValue or as an OpTy. But that also clashes with the notion that miri should run on sensible code.

@RalfJung
Copy link
Member

RalfJung commented Jul 20, 2025

These are statics failing the "it must be sized" check. It's not some impossible where bound. I don't see what is so hard about marking them as tainted so nothing else ever touches them again. It's the exact same thing as a static whose initializer body is plainly ill-typed.

@cjgillot cjgillot force-pushed the known-panics-panics branch 2 times, most recently from 7e54047 to a825a96 Compare July 20, 2025 21:44
@cjgillot
Copy link
Contributor Author

@RalfJung this latest version prevents creating the erroneous constants altogether. Do you agree with this version?

@rust-log-analyzer

This comment has been minimized.

@cjgillot cjgillot force-pushed the known-panics-panics branch from a825a96 to a250112 Compare July 20, 2025 22:33
@rust-log-analyzer

This comment has been minimized.

@RalfJung
Copy link
Member

Yeah, that looks much better, thanks.

I'm not familiar with MIR building so I can't approve this on my own, however.

@cjgillot
Copy link
Contributor Author

It's not ready yet. Just checking sizedness is not enough, as some non-sized types are OK too, like extern types. And using layout causes cycles.

@RalfJung
Copy link
Member

Extern types can only work with extern statics, right?

And even then, that seems kind of cursed. Did we intentionally allow that or just forget to disallow it?

@cjgillot
Copy link
Contributor Author

Extern types can only work with extern statics, right?

Or inside pointers. And pointers to extern types are scalars.

And even then, that seems kind of cursed. Did we intentionally allow that or just forget to disallow it?

It's intentional. We have a run-make test to verify this works.

@RalfJung
Copy link
Member

RalfJung commented Jul 22, 2025 via email

@cjgillot
Copy link
Contributor Author

The failing test is this one:

extern "C" {
type Foo;
static FOO: Foo;
fn bar(foo: *const Foo) -> u8;
}

As a foreign type Foo is not sized, but &Foo and *mut Foo are still scalar. This is a special case in layout computation.

Checking whether &T is scalar in full generality requires either to call layout_of, or to open-code it. Internally, it normalizes <T as Pointee>::Metadata and compute that type's layout. The normalization process may try to normalize opaque types. This breaks https://github.com/rust-lang/rust/blob/master/tests/ui/coroutine/layout-error.rs

@RalfJung
Copy link
Member

The failing test is this one:

Yeah, that is a very odd test, I didn't think we'd allow extern statics with unknown size. Interestingly, we reject static FOO2: [i32]; (as we have to).

What is not entirely clear to me is why we'd care about whether &Foo has metadata or not. Is that for constructing the pointer that represents the extern static access in MIR? As far as I can see, those pointers are always scalar, since statics with unsized types that require metadata are forbidden (and that makes sense; where would the metadata come from anyway).

@RalfJung
Copy link
Member

RalfJung commented Jul 23, 2025

All the issues referenced here seem to be about statics that are unsized-with-metadata. You can check for this without knowing the layout; just call ptr_metadata_ty on the type of the static. Statics can't be generic so this should always give you a definite answer.

This still has to normalize some things though, so that coroutine case could become interesting. But it's okay for that code to error, it just can't ICE.

// Still, producing a single scalar constant would be inconsistent, as pointers to
// non-`Sized` types are scalar pairs. Avoid an ICE by producing an error constant.
let guar =
tcx.dcx().span_delayed_bug(span, format!("static's type `{ty}` is not Sized"));
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
tcx.dcx().span_delayed_bug(span, format!("static's type `{ty}` is not Sized"));
tcx.dcx().span_delayed_bug(span, format!("static's type `{pointee}` is not Sized"));

@RalfJung
Copy link
Member

Wouldn't an alternative be to change the type of the static itself to TyKind::Error after we determined that it's not a valid type for a static? Then we don't need patches like this all over the rest of the compiler.

Cc @oli-obk

@cjgillot cjgillot force-pushed the known-panics-panics branch from a250112 to 1a23d74 Compare July 25, 2025 03:00
// Still, producing a single scalar constant would be inconsistent, as pointers to
// non-`Sized` types are scalar pairs. Avoid an ICE by producing an error constant.
let guar =
tcx.dcx().span_delayed_bug(span, format!("static's type `{ty}` is not scalar"));
Copy link
Member

Choose a reason for hiding this comment

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

ty is not the type of the static, it's the type of a pointer to the static.

Comment on lines 87 to 88
let const_ = if let Ok(layout) = layout
&& let BackendRepr::Scalar(..) = layout.backend_repr
Copy link
Member

Choose a reason for hiding this comment

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

As noted before, I think the better approach would be to give the static an Error type -- otherwise, there might well be other consumers all over rustc that assume things about a statics type, that all need to get a fix like this.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I tried that, and for some reason that was not enough to fix the ices. I did try to find why error tainting failed.

Copy link
Member

Choose a reason for hiding this comment

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

@oli-obk is it okay for this to cycle-error? Having the type of a static depend on its value does seem quite cursed.^^

Copy link
Contributor

Choose a reason for hiding this comment

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

Is a static's type meaningfully different from a function's return type? Because it's not about its evaluated value, but just how opaque types work.

I don't think this use case is particularly unusual and expect people will want to be using TAITs like this.

Copy link
Member

Choose a reason for hiding this comment

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

Is a static's type meaningfully different from a function's return type?

Hm... not really, the problem is just that the constraint on the type cannot be so easily expressed as a trait query. For return types it's T: Sized, but for static types it's... T: Pointee<Metadata = ()> or so?

@oli-obk
Copy link
Contributor

oli-obk commented Jul 25, 2025

Wouldn't an alternative be to change the type of the static itself to TyKind::Error after we determined that it's not a valid type for a static? Then we don't need patches like this all over the rest of the compiler.

that would mean moving these checks to type_of, which should be fine for static items, but are very cycle prone for other things

@cjgillot cjgillot force-pushed the known-panics-panics branch from 1a23d74 to 8095c2d Compare July 25, 2025 23:07
@rustbot
Copy link
Collaborator

rustbot commented Jul 25, 2025

This PR modifies tests/ui/issues/. If this PR is adding new tests to tests/ui/issues/,
please refrain from doing so, and instead add it to more descriptive subdirectories.

@cjgillot
Copy link
Contributor Author

Wouldn't an alternative be to change the type of the static itself to TyKind::Error after we determined that it's not a valid type for a static? Then we don't need patches like this all over the rest of the compiler.

that would mean moving these checks to type_of, which should be fine for static items, but are very cycle prone for other things

The latest commit tries that. I think it's worse because it breaks passing tests.

@rust-log-analyzer

This comment was marked as outdated.

@cjgillot cjgillot force-pushed the known-panics-panics branch from 8095c2d to 7c64961 Compare July 25, 2025 23:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
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.
Projects
None yet
6 participants