Skip to content
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

Do not panic in ty::consts::Const::try_to_target_usize() in case of size mismatch #126382

Open
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

gurry
Copy link
Contributor

@gurry gurry commented Jun 13, 2024

Fixes #126359

This is the failing code:

struct OppOrder<const N: u8 = 3, T = u32> {
    arr: [T; N],
}

fn main() {
    let _ = OppOrder::<3, u32> { arr: [0, 0, 0] };
}

The ICE occurred while unifying the type of array [0, 0, 0] with OppOrder::<3, u32>.arr field. arr's type is malformed because it has u8 for size instead of usize. So when we try to unify usize with u8 a method in Valtree panics causing the ICE.

This PR makes ty::consts::Const::try_to_target_usize, which calls Valtree methods, check for size mismatch and gracefully return None instead of calling Valtree.

@rustbot
Copy link
Collaborator

rustbot commented Jun 13, 2024

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 Jun 13, 2024
@BoxyUwU
Copy link
Member

BoxyUwU commented Jun 13, 2024

We intentionally started ICEing here because it is genuinely a bug to be doing this. This PR Is effectively a partial revert of #126159. Ideally what should be happening is we should be tainting errors somewhere so that we can check for ErrorGuaranteed somewhere and avoid running this codepath

@BoxyUwU
Copy link
Member

BoxyUwU commented Jun 13, 2024

Looking it into it a little bit the problem is that super_relate_tys for TyKind::Array has diagnostic logic in it that unconditionally evaluates the array length to a usize. This codepath should correctly handle length arguments that are incorrectly typed instead of assuming they can be evaluated to a usize.

edit: wrote a bit more in the actual issue itself, should read that too

@BoxyUwU
Copy link
Member

BoxyUwU commented Jun 13, 2024

r? @BoxyUwU

@rustbot rustbot assigned BoxyUwU and unassigned davidtwco Jun 13, 2024
--> $DIR/ice-const-size-relate-126359.rs:12:39
|
LL | let _ = OppOrder::<3, u32> { arr: [0, 0, 0] };
| ^^^^^^^^^ expected `3`, found `3`
Copy link
Member

Choose a reason for hiding this comment

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

This diagnostic still looks buggy.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yeah, it should be suppressed. Will look into it

@RalfJung
Copy link
Member

Yeah, as you said for most users of try_to_target_usize it is a bug if the type is not usize (the "try" refers to the fact that the constant may fail to evaluate, but it must have the right type).

The special situation here is that this is called in an error path.

@gurry
Copy link
Contributor Author

gurry commented Jun 13, 2024

Looking it into it a little bit the problem is that super_relate_tys for TyKind::Array has diagnostic logic in it that unconditionally evaluates the array length to a usize. This codepath should correctly handle length arguments that are incorrectly typed instead of assuming they can be evaluated to a usize.

Yeah, that's why I felt the solution was simply to prevent the panic. First I thought I should make the change here in structurally_relate_tys():

Err(err) => {
// Check whether the lengths are both concrete/known values,
// but are unequal, for better diagnostics.
let sz_a = sz_a.try_to_target_usize(tcx);
let sz_b = sz_b.try_to_target_usize(tcx);
match (sz_a, sz_b) {
(Some(sz_a_val), Some(sz_b_val)) if sz_a_val != sz_b_val => Err(
TypeError::FixedArraySize(ExpectedFound::new(true, sz_a_val, sz_b_val)),
),
_ => Err(err),
}
}

but then it seemed easier to do it inside Const::try_to_target_size(). I can move it to the above location if you guys prefer.

@RalfJung
Copy link
Member

I don't think try_to_target_size is the right place for this. Though the function could probably use a comment saying that it is resilient to constants that fail to compute, but not resilient to constants having the wrong type.

@gurry
Copy link
Contributor Author

gurry commented Jun 13, 2024

@rustbot author

@rustbot rustbot added S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Jun 13, 2024
Comment on lines +7 to +8
= note: expected array `[u32; 3]`
found array `[u32; 3]`
Copy link
Member

Choose a reason for hiding this comment

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

wooondering if its worth having a debug_assert against this kind of stuff ('note: expected X, found Y' where x.display() == y.display()) because that just seems silly from a diagnostic point of view 😅

@gurry gurry force-pushed the 126359-expected-sz-8-got-1 branch from 10bc842 to f67d045 Compare July 7, 2024 08:25
@gurry
Copy link
Contributor Author

gurry commented Jul 7, 2024

I have undone my changes to rustc_middle::ty::consts::Const::try_to_target_usize and moved them to the impl of rustc_type_ir::inherent::::Const::try_to_target_usize on rustc_middle::ty::consts::Const. This leaves the semantics of rustc_middle::ty::consts::Const::try_to_target_usize intact.

As for the confusing diagnostics:

LL |     let _ = OppOrder::<3, u32> { arr: [0, 0, 0] };
   |                                       ^^^^^^^^^ expected `3`, found `3`

and

= note: expected array `[u32; 3]`
              found array `[u32; 3]`

I'll tackle them later in a separate PR.

@rustbot review

@rustbot rustbot added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. and removed S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. labels Jul 7, 2024
@rust-log-analyzer

This comment has been minimized.

… size mismatch

Fixes an ICE when we try to relate an array size of type u8 to usize
@gurry gurry force-pushed the 126359-expected-sz-8-got-1 branch from f67d045 to a1a0865 Compare July 7, 2024 09:05
@gurry
Copy link
Contributor Author

gurry commented Jul 7, 2024

The job x86_64-gnu-llvm-17 failed! Check out the build log: (web) (plain)

Click to see the possible cause of the failure (guessed by this bot)

 - LegacyKeyValueFormat: "ENV key=value" should be used instead of legacy "ENV key value" format (line 46)
 - LegacyKeyValueFormat: "ENV key=value" should be used instead of legacy "ENV key value" format (line 49)
 - LegacyKeyValueFormat: "ENV key=value" should be used instead of legacy "ENV key value" format (line 61)
##[endgroup]
Setting extra environment values for docker:  --env ENABLE_GCC_CODEGEN=1 --env GCC_EXEC_PREFIX=/usr/lib/gcc/
[CI_JOB_NAME=x86_64-gnu-llvm-17]
---
sccache: Starting the server...
##[group]Configure the build
configure: processing command line
configure: 
configure: build.configure-args := ['--build=x86_64-unknown-linux-gnu', '--llvm-root=/usr/lib/llvm-17', '--enable-llvm-link-shared', '--set', 'rust.thin-lto-import-instr-limit=10', '--set', 'change-id=99999999', '--enable-verbose-configure', '--enable-sccache', '--disable-manage-submodules', '--enable-locked-deps', '--enable-cargo-native-static', '--set', 'rust.codegen-units-std=1', '--set', 'dist.compression-profile=balanced', '--dist-compression-formats=xz', '--set', 'rust.lld=false', '--disable-dist-src', '--release-channel=nightly', '--enable-debug-assertions', '--enable-overflow-checks', '--enable-llvm-assertions', '--set', 'rust.verify-llvm-ir', '--set', 'rust.codegen-backends=llvm,cranelift,gcc', '--set', 'llvm.static-libstdcpp', '--enable-new-symbol-mangling']
configure: target.x86_64-unknown-linux-gnu.llvm-config := /usr/lib/llvm-17/bin/llvm-config
configure: llvm.link-shared     := True
configure: rust.thin-lto-import-instr-limit := 10
configure: change-id            := 99999999
---

running 237 tests
........................................................................................  88/237
........................................................................................ 176/237
........2024-07-07T08:49:16.171323Z ERROR compiletest::runtest: fatal error, panic: "crashtest no longer crashes/triggers ICE, horray! Please give it a meaningful name, add a doc-comment to the start of the test explaining why it exists and move it to tests/ui or wherever you see fit. Adding 'Fixes #<issueNr>' to your PR description ensures that the corresponding ticket is auto-closed upon merge."
[crashes] tests/crashes/126359.rs ... F
....................................................

failures:
failures:

---- [crashes] tests/crashes/126359.rs stdout ----

error: crashtest no longer crashes/triggers ICE, horray! Please give it a meaningful name, add a doc-comment to the start of the test explaining why it exists and move it to tests/ui or wherever you see fit. Adding 'Fixes #<issueNr>' to your PR description ensures that the corresponding ticket is auto-closed upon merge.
thread '[crashes] tests/crashes/126359.rs' panicked at src/tools/compiletest/src/runtest.rs:377:18:
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace


failures:

Occurred due to an overdue rebase. Rebased now.

@RalfJung
Copy link
Member

RalfJung commented Jul 7, 2024

That seems potentially quite confusing if there are two try_to_target_usize methods on the same type that don't behave the same.

#126159 was written under the assumption that the compiler can reliably avoid feeding ill-typed programs to later phases. If that is not the case, maybe we should go back to having the Const::try* methods check for size mismatches...

@gurry
Copy link
Contributor Author

gurry commented Jul 7, 2024

That seems potentially quite confusing if there are two try_to_target_usize methods on the same type that don't behave the same.

#126159 was written under the assumption that the compiler can reliably avoid feeding ill-typed programs to later phases. If that is not the case, maybe we should go back to having the Const::try* methods check for size mismatches...

What if we rename the try_to_target_usize on the rustc_type_ir::inherent::::Const trait to something else? Perhaps to a name that suggests that it takes size mismatch into account.

@RalfJung
Copy link
Member

RalfJung commented Jul 7, 2024

Is it clear where one would want to call which function? Sounds a bit like the one on the inherent impl is just an ICE waiting to happen, it the compiler feeds ill-typed terms so deep into the type system.

Is it clear why that happens / why it cannot be prevented? Boxy wrote above

"Looking it into it a little bit the problem is that super_relate_tys for TyKind::Array has diagnostic logic in it that unconditionally evaluates the array length to a usize. This codepath should correctly handle length arguments that are incorrectly typed instead of assuming they can be evaluated to a usize."

Have you dug to the bottom of why that does not work?
How much such diagnostic logic do we have? Can we realistically expect it to be written in a way that avoids the pitfalls of ill-typed code?

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
Development

Successfully merging this pull request may close these issues.

ICE: expected int of size 8, but got size 1
7 participants