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

Undefined Behavior in safe code that unwinds out of extern "C" function #63943

Closed
gnzlbg opened this issue Aug 27, 2019 · 8 comments
Closed

Undefined Behavior in safe code that unwinds out of extern "C" function #63943

gnzlbg opened this issue Aug 27, 2019 · 8 comments
Labels
A-FFI Area: Foreign function interface (FFI) C-bug Category: This is a bug. I-unsound Issue: A soundness hole (worst kind of bug), see: https://en.wikipedia.org/wiki/Soundness T-lang Relevant to the language team, which will review and decide on the PR/issue.

Comments

@gnzlbg
Copy link
Contributor

gnzlbg commented Aug 27, 2019

UPDATE: this optimization is perfectly correct. It only breaks code that already has undefined behavior. This is however an issue since until #52652 is fixed we want to keep such code working.

ORIGINAL TITLE: mis-compilation of noreturn extern "C" definitions that unwind on stable and nightly


Originally reported here: #63909 (comment) , which might contain a fix, but that has not been verified yet.

The default behavior of the Rust language on nightly Rust was to abort when a panic tries to escape from functions using certain ABIs intended for FFI, like "C". #62603 changed this behavior on nightly Rust to match the stable Rust behavior, which let the function unwind, while still applying the nounwind attribute to these functions. When these functions return Never, they are also noreturn, and this results in mis-compilations on stable and nightly Rust. MWE:

extern "C" fn bar() -> ! { panic!("nounwind noreturn fn unwinds") }
extern "C" fn baz() -> i32 {
    if let Ok(_) = std::panic::catch_unwind(|| bar() ) {
        unsafe { std::hint::unreachable_unchecked() }  // makes IR nicer
    }
    42
}
fn main() { std::process::exit((baz() != 42) as i32); }

cargo run --release returns success, but RUSTFLAGS="-C lto=fat" cargo run --release returns failure.

I think that since #63909 removes the nounwind attribute, it should end up fixing this bug, but we should probably add a test for this somewhere.


The problem #62603 intended to solve is to allow Rust->C->Rust FFI where a Rust callback called from C can unwind through C back into Rust. This example can be adapted to this application, where the miscompilation persists:

// foo.cpp
using fn_type = void(*)();
[[ noreturn ]] extern "C" void foo(fn_type x);
[[ noreturn ]] extern "C" void foo(fn_type x)  { x(); /* unreachable: */ throw 0; }
// main.rs
extern "C" { fn foo(x: extern "C" fn() -> !) -> !; }
extern "C" fn bar() -> ! { panic!("nounwind noreturn fn unwinds") }
extern "C" fn baz() -> i32 {
    if let Ok(_) = std::panic::catch_unwind(|| unsafe { foo(bar) }) {
        unsafe { std::hint::unreachable_unchecked() }
    }
    42
}
fn main() {
   std::process::exit((baz() != 42) as i32);
}

AFAICT this miscompilation has always existed for Rust->C-Rust FFI.

@jonas-schievink jonas-schievink added A-FFI Area: Foreign function interface (FFI) C-bug Category: This is a bug. I-nominated I-unsound Issue: A soundness hole (worst kind of bug), see: https://en.wikipedia.org/wiki/Soundness T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. labels Aug 27, 2019
@nikomatsakis nikomatsakis added T-lang Relevant to the language team, which will review and decide on the PR/issue. and removed T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. labels Aug 29, 2019
@nikomatsakis
Copy link
Contributor

Check-in from the @rust-lang/compiler meeting: I'm changing the nomination to nominate this issue for @rust-lang/lang. In particular, @joshtriplett, it'd be great if you can catch up on the comments here and in #63909 and give some kind of summary, since you've been spearheading this work.

@joshtriplett
Copy link
Member

I'm not sure why this was filed in addition to #63909; I think #63909 completely addresses this, assuming we either merge it or stabilize #[unwind] before the next beta. I'm going to close this issue as a duplicate of #63909. If you feel there's a distinct issue here that #63909 wouldn't address, please clarify that and we can always reopen it.

@gnzlbg
Copy link
Contributor Author

gnzlbg commented Sep 6, 2019

This issue was filled because #62603 re-introduced this soundness bug into nightly. Is this a duplicate of some other issue? #63909 is a PR.

@RalfJung
Copy link
Member

RalfJung commented Sep 9, 2019

I agree with @gnzlbg, the existence of an unmerged PR does not usually suffice to close issues.

@RalfJung RalfJung reopened this Sep 9, 2019
@joshtriplett
Copy link
Member

joshtriplett commented Sep 9, 2019

@RalfJung I tend to treat PRs and issues as synonymous (a PR is just an issue with commits attached) and thus potentially redundant, but your call.

It would be nice, however, if we could avoid further splitting discussion and comments across what seems like an ever-growing number of issues and PRs.

@gnzlbg gnzlbg changed the title mis-compilation of noreturn extern "C" definitions that unwind on stable and nightly Perfectly-correct optimization that breaks code that has undefined behavior Sep 14, 2019
@RalfJung RalfJung changed the title Perfectly-correct optimization that breaks code that has undefined behavior Undefined Behavior in safe code that unwinds out of extern "C" function Mar 26, 2020
@Elinvynia Elinvynia added the I-prioritize Issue: Indicates that prioritization has been requested for this issue. label Jun 9, 2020
@LeSeulArtichaut LeSeulArtichaut removed the I-prioritize Issue: Indicates that prioritization has been requested for this issue. label Jun 9, 2020
@RalfJung
Copy link
Member

Can this be closed due to #76570? Cc @cratelyn

@cratelyn
Copy link

Yes, that sounds correct to me @RalfJung!

@RalfJung
Copy link
Member

Awesome, I love closing soundness issues. :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-FFI Area: Foreign function interface (FFI) C-bug Category: This is a bug. I-unsound Issue: A soundness hole (worst kind of bug), see: https://en.wikipedia.org/wiki/Soundness T-lang Relevant to the language team, which will review and decide on the PR/issue.
Projects
None yet
Development

No branches or pull requests

9 participants