-
Notifications
You must be signed in to change notification settings - Fork 12.8k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Auto merge of #92911 - nbdd0121:unwind, r=Amanieu
Guard against unwinding in cleanup code Currently the only safe guard we have against double unwind is the panic count (which is local to Rust). When double unwinds indeed happen (e.g. C++ exception + Rust panic, or two C++ exceptions), then the second unwind actually goes through and the first unwind is leaked. This can cause UB. cc rust-lang/project-ffi-unwind#6 E.g. given the following C++ code: ```c++ extern "C" void foo() { throw "A"; } extern "C" void execute(void (*fn)()) { try { fn(); } catch(...) { } } ``` This program is well-defined to terminate: ```c++ struct dtor { ~dtor() noexcept(false) { foo(); } }; void a() { dtor a; dtor b; } int main() { execute(a); return 0; } ``` But this Rust code doesn't catch the double unwind: ```rust extern "C-unwind" { fn foo(); fn execute(f: unsafe extern "C-unwind" fn()); } struct Dtor; impl Drop for Dtor { fn drop(&mut self) { unsafe { foo(); } } } extern "C-unwind" fn a() { let _a = Dtor; let _b = Dtor; } fn main() { unsafe { execute(a) }; } ``` To address this issue, this PR adds an unwind edge to an abort block, so that the Rust example aborts. This is similar to how clang guards against double unwind (except clang calls terminate per C++ spec and we abort). The cost should be very small; it's an additional trap instruction (well, two for now, since we use TrapUnreachable, but that's a different issue) for each function with landing pads; if LLVM gains support to encode "abort/terminate" info directly in LSDA like GCC does, then it'll be free. It's an additional basic block though so compile time may be worse, so I'd like a perf run. r? `@ghost` `@rustbot` label: F-c_unwind
- Loading branch information
Showing
8 changed files
with
132 additions
and
27 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
-include ../tools.mk | ||
|
||
all: foo | ||
$(call RUN,foo) | $(CGREP) -v unreachable | ||
|
||
foo: foo.rs $(call NATIVE_STATICLIB,foo) | ||
$(RUSTC) $< -lfoo $(EXTRARSCXXFLAGS) | ||
|
||
$(TMPDIR)/libfoo.o: foo.cpp | ||
$(call COMPILE_OBJ_CXX,$@,$<) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
#include <cstdio> | ||
#include <exception> | ||
|
||
void println(const char* s) { | ||
puts(s); | ||
fflush(stdout); | ||
} | ||
|
||
struct outer_exception {}; | ||
struct inner_exception {}; | ||
|
||
extern "C" { | ||
void throw_cxx_exception() { | ||
if (std::uncaught_exception()) { | ||
println("throwing inner C++ exception"); | ||
throw inner_exception(); | ||
} else { | ||
println("throwing outer C++ exception"); | ||
throw outer_exception(); | ||
} | ||
} | ||
|
||
void cxx_catch_callback(void (*cb)()) { | ||
try { | ||
cb(); | ||
println("unreachable: callback returns"); | ||
} catch (outer_exception) { | ||
println("unreachable: caught outer exception in catch (...)"); | ||
} catch (inner_exception) { | ||
println("unreachable: caught inner exception in catch (...)"); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
// Tests that C++ double unwinding through Rust code will be properly guarded | ||
// against instead of exhibiting undefined behaviour. | ||
|
||
#![feature(c_unwind)] | ||
|
||
extern "C-unwind" { | ||
fn throw_cxx_exception(); | ||
fn cxx_catch_callback(cb: extern "C-unwind" fn()); | ||
} | ||
|
||
struct ThrowOnDrop; | ||
|
||
impl Drop for ThrowOnDrop { | ||
fn drop(&mut self) { | ||
unsafe { throw_cxx_exception() }; | ||
} | ||
} | ||
|
||
extern "C-unwind" fn test_double_unwind() { | ||
let _a = ThrowOnDrop; | ||
let _b = ThrowOnDrop; | ||
} | ||
|
||
fn main() { | ||
unsafe { cxx_catch_callback(test_double_unwind) }; | ||
} |