rust-lang / rust

Empowering everyone to build reliable and efficient software.
https://www.rust-lang.org
Other
98.61k stars 12.74k forks source link

miri reports ub when panicing inside #[start] function #97049

Open matthiaskrgr opened 2 years ago

matthiaskrgr commented 2 years ago

I tried this code:

// run-pass
// compile-flags: --test

#![feature(start)]

#[start]
fn start(_: isize, _: *const *const u8) -> isize { panic!(); }

miri reports:

thread '<unnamed>' panicked at 'explicit panic', src/main.rs:7:52
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
error: Undefined Behavior: unwinding past the topmost frame of the stack
 --> src/main.rs:7:1
  |
7 | fn start(_: isize, _: *const *const u8) -> isize { panic!(); }
  | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unwinding past the topmost frame of the stack
  |
  = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
  = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information

  = note: inside `start` at src/main.rs:7:1

error: aborting due to previous error

which does not happen when I just panic!() without a #[start] fn miri 0.1.0 (3b8b6aa 2022-05-06)

saethlin commented 2 years ago

I think Miri is correct here. I'm pretty sure #[start] runs before the Rust runtime is initialized, which means there is nothing to catch a panic. I can't tell if the feature is documented anywhere, the unstable book just links to tracking issue, which dates back to 2015: https://github.com/rust-lang/rust/issues/29633

But the opening comment does say

In general this forgoes a bit of runtime setup that's normally run before and after main.

Though it's hard to tell if that is normative or correct, being that is an unstable feature and that was 7 years ago.

asquared31415 commented 2 years ago

This feature is incredibly poorly documented, and because of that, I think most people end up using platform-specific linker things to get the same result, which leads to less interest in the feature, which means there's less effort to document it, and it's a horrible cycle.

bjorn3 commented 2 years ago

Libstd's lang_start impl wraps all calls it does in catch_unwind to avoid UB.

RalfJung commented 2 years ago

It is my understanding that a panic "leaving" the top of the Rust-controlled stack is UB, and that is the check that Miri is implementing here.

Maybe we should add this as a testcase. :D