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

Program that uses the const VOID: ! =panic!() associated constant compiles and runs into illegal intruction. #66975

Closed
rodrimati1992 opened this issue Dec 2, 2019 · 11 comments · Fixed by #67164
Assignees
Labels
A-const-eval Area: Constant evaluation, covers all const contexts (static, const fn, ...) C-bug Category: This is a bug. I-unsound Issue: A soundness hole (worst kind of bug), see: https://en.wikipedia.org/wiki/Soundness requires-nightly This issue requires a nightly compiler in some way. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.

Comments

@rodrimati1992
Copy link
Contributor

This unsound code compiles in the playground (on Rust nightly 2019-12-01):

#![feature(const_panic)]

struct PrintName;

impl PrintName {
    const VOID: ! = panic!();
}

fn main() {
    let _ = PrintName::VOID;
}

And runs into an illegal instruction:

   Compiling playground v0.0.1 (/playground)
    Finished dev [unoptimized + debuginfo] target(s) in 0.65s
     Running `target/debug/playground`
timeout: the monitored command dumped core
/root/entrypoint.sh: line 8:     7 Illegal instruction     timeout --signal=KILL ${timeout} "$@"

I expected this to fail to compile because panicking in constants should cause compilation errors.

@jonas-schievink jonas-schievink added A-const-eval Area: Constant evaluation, covers all const contexts (static, const fn, ...) C-bug Category: This is a bug. I-unsound Issue: A soundness hole (worst kind of bug), see: https://en.wikipedia.org/wiki/Soundness requires-nightly This issue requires a nightly compiler in some way. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. labels Dec 2, 2019
@Centril
Copy link
Contributor

Centril commented Dec 3, 2019

cc @rust-lang/wg-const-eval

@oli-obk
Copy link
Contributor

oli-obk commented Dec 3, 2019

Ok, there's three questionable things going on.

  1. Why do we get an error if it's not an associated constant but just a normal constant
  2. It also happens for normal constants with allow(const_err)
#![feature(const_panic)]
#![allow(const_err)]

const VOID: ! = panic!();

fn main() {
    let _ = VOID;
}
  1. It does not happen for arithmetic panics
#![allow(const_err)]

const VOID: u32 = 0 - 1;

fn main() {
    let x = VOID; // still an error
}

@matthewjasper matthewjasper self-assigned this Dec 7, 2019
@oli-obk
Copy link
Contributor

oli-obk commented Dec 8, 2019

Ok... so I did a full MIR dump of the example code and even the very first MIR directly after mir building does not contain the assignment (although it contains the variable of ! type). I'm not sure what we're doing here, but it seems mir building must already bail out of building this assignment, because it knows it's dead.

@matthewjasper
Copy link
Contributor

We throw the constant on the floor:

unpack!(block = this.as_local_rvalue(block, source));

This needs to be as_temp to ensure that anything ends up in the MIR.

@oli-obk
Copy link
Contributor

oli-obk commented Dec 8, 2019

Wouldn't as_temp change the behaviour of let _ = ...; to let _tmp = ...;, thus affecting the drop behaviour if the assign rhs is a temporary value?

@matthewjasper
Copy link
Contributor

as_temp takes the scope of the temporary that it creates. We generate an Unreachable terminator right after this, so I don't think that it matters much either way.

@RalfJung
Copy link
Member

RalfJung commented Dec 8, 2019

FWIW I don't think this is unsound; this just runs into the safety net that we have when embedding consts/promoteds with errors into the code -- we emit a trap. So this is certainly wrong codegen but I don't think there is any UB.

@oli-obk
Copy link
Contributor

oli-obk commented Dec 8, 2019

It is unsound, because we don't run into the promoted safety net. The constant never even shows up in MIR, instead all it is is a basic block with an unreachable terminator.

@matthewjasper my worry was not about this specific code miscompiling, but other code miscompiling. But you're right, the call you found only is run for never types. Can you open a PR with the change and a mir opt test showing that it doesn't get optimized away? This may additionally require #67134

@RalfJung
Copy link
Member

RalfJung commented Dec 8, 2019

It is unsound, because we don't run into the promoted safety net. The constant never even shows up in MIR, instead all it is is a basic block with an unreachable terminator.

Oh. Yeah okay that's pretty bad indeed.

@jyn514
Copy link
Member

jyn514 commented Dec 10, 2019

Running this with miri gives error: entering unreachable code:

error: Miri evaluation error: entering unreachable code
  --> src/main.rs:10:13
   |
10 |     let _ = PrintName::VOID;
   |             ^^^^^^^^^^^^^^^ Miri evaluation error: entering unreachable code
   |
   = note: inside call to `main` at /root/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/src/libstd/rt.rs:67:34
   = note: inside call to closure at /root/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/src/libstd/rt.rs:52:73
   = note: inside call to closure at /root/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/src/libstd/sys_common/backtrace.rs:136:5
   = note: inside call to `std::sys_common::backtrace::__rust_begin_short_backtrace::<[closure@DefId(1:6014 ~ std[74ff]::rt[0]::lang_start_internal[0]::{{closure}}[0]::{{closure}}[0]) 0:&dyn std::ops::Fn() -> i32 + std::marker::Sync + std::panic::RefUnwindSafe], i32>` at /root/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/src/libstd/rt.rs:52:13
   = note: inside call to closure at /root/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/src/libstd/panicking.rs:292:40
   = note: inside call to `std::panicking::r#try::do_call::<[closure@DefId(1:6013 ~ std[74ff]::rt[0]::lang_start_internal[0]::{{closure}}[0]) 0:&&dyn std::ops::Fn() -> i32 + std::marker::Sync + std::panic::RefUnwindSafe], i32>` at /root/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/src/libstd/panicking.rs:270:13
   = note: inside call to `std::panicking::r#try::<i32, [closure@DefId(1:6013 ~ std[74ff]::rt[0]::lang_start_internal[0]::{{closure}}[0]) 0:&&dyn std::ops::Fn() -> i32 + std::marker::Sync + std::panic::RefUnwindSafe]>` at /root/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/src/libstd/panic.rs:394:14
   = note: inside call to `std::panic::catch_unwind::<[closure@DefId(1:6013 ~ std[74ff]::rt[0]::lang_start_internal[0]::{{closure}}[0]) 0:&&dyn std::ops::Fn() -> i32 + std::marker::Sync + std::panic::RefUnwindSafe], i32>` at /root/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/src/libstd/rt.rs:51:25
   = note: inside call to `std::rt::lang_start_internal` at /root/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/src/libstd/rt.rs:67:5
   = note: inside call to `std::rt::lang_start::<()>`

error: aborting due to previous error

error: could not compile `playground`.

@jyn514
Copy link
Member

jyn514 commented Dec 10, 2019

Also if you remove the let binding it correctly gives an error:

#![feature(const_panic)]

struct PrintName;

impl PrintName {
    const VOID: ! = panic!();
}

fn main() {
    PrintName::VOID;
}
error: any use of this value will cause an error
 --> src/main.rs:6:21
  |
6 |     const VOID: ! = panic!();
  |     ----------------^^^^^^^^-
  |                     |
  |                     the evaluated program panicked at 'explicit panic', src/main.rs:6:21
  |
  = note: `#[deny(const_err)]` on by default
  = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)

error[E0080]: erroneous constant used
  --> src/main.rs:10:5
   |
10 |     PrintName::VOID;
   |     ^^^^^^^^^^^^^^^ referenced constant has errors

@bors bors closed this as completed in 96b288f Dec 11, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-const-eval Area: Constant evaluation, covers all const contexts (static, const fn, ...) C-bug Category: This is a bug. I-unsound Issue: A soundness hole (worst kind of bug), see: https://en.wikipedia.org/wiki/Soundness requires-nightly This issue requires a nightly compiler in some way. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.
Projects
None yet
Development

Successfully merging a pull request may close this issue.

7 participants