Skip to content

Commit 998e277

Browse files
committed
Allow foreign exceptions to unwind through Rust code
1 parent 2cf88db commit 998e277

File tree

9 files changed

+217
-156
lines changed

9 files changed

+217
-156
lines changed

src/doc/unstable-book/src/language-features/lang-items.md

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -249,9 +249,8 @@ the source code.
249249
- Runtime
250250
- `start`: `libstd/rt.rs`
251251
- `eh_personality`: `libpanic_unwind/emcc.rs` (EMCC)
252-
- `eh_personality`: `libpanic_unwind/seh64_gnu.rs` (SEH64 GNU)
252+
- `eh_personality`: `libpanic_unwind/gcc.rs` (GNU)
253253
- `eh_personality`: `libpanic_unwind/seh.rs` (SEH)
254-
- `eh_unwind_resume`: `libpanic_unwind/seh64_gnu.rs` (SEH64 GNU)
255254
- `eh_unwind_resume`: `libpanic_unwind/gcc.rs` (GCC)
256255
- `msvc_try_filter`: `libpanic_unwind/seh.rs` (SEH)
257256
- `panic`: `libcore/panicking.rs`

src/libpanic_unwind/dwarf/eh.rs

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ pub enum EHAction {
5151

5252
pub const USING_SJLJ_EXCEPTIONS: bool = cfg!(all(target_os = "ios", target_arch = "arm"));
5353

54-
pub unsafe fn find_eh_action(lsda: *const u8, context: &EHContext<'_>)
54+
pub unsafe fn find_eh_action(lsda: *const u8, context: &EHContext<'_>, foreign_exception: bool)
5555
-> Result<EHAction, ()>
5656
{
5757
if lsda.is_null() {
@@ -96,7 +96,7 @@ pub unsafe fn find_eh_action(lsda: *const u8, context: &EHContext<'_>)
9696
return Ok(EHAction::None)
9797
} else {
9898
let lpad = lpad_base + cs_lpad;
99-
return Ok(interpret_cs_action(cs_action, lpad))
99+
return Ok(interpret_cs_action(cs_action, lpad, foreign_exception))
100100
}
101101
}
102102
}
@@ -121,15 +121,17 @@ pub unsafe fn find_eh_action(lsda: *const u8, context: &EHContext<'_>)
121121
// Can never have null landing pad for sjlj -- that would have
122122
// been indicated by a -1 call site index.
123123
let lpad = (cs_lpad + 1) as usize;
124-
return Ok(interpret_cs_action(cs_action, lpad))
124+
return Ok(interpret_cs_action(cs_action, lpad, foreign_exception))
125125
}
126126
}
127127
}
128128
}
129129

130-
fn interpret_cs_action(cs_action: u64, lpad: usize) -> EHAction {
130+
fn interpret_cs_action(cs_action: u64, lpad: usize, foreign_exception: bool) -> EHAction {
131131
if cs_action == 0 {
132132
EHAction::Cleanup(lpad)
133+
} else if foreign_exception {
134+
EHAction::None
133135
} else {
134136
EHAction::Catch(lpad)
135137
}

src/libpanic_unwind/gcc.rs

Lines changed: 51 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -133,23 +133,20 @@ const UNWIND_DATA_REG: (i32, i32) = (0, 1); // R0, R1
133133
// https://github.com/gcc-mirror/gcc/blob/master/libstdc++-v3/libsupc++/eh_personality.cc
134134
// https://github.com/gcc-mirror/gcc/blob/trunk/libgcc/unwind-c.c
135135

136-
// The personality routine for most of our targets, except ARM, which has a slightly different ABI
137-
// (however, iOS goes here as it uses SjLj unwinding). Also, the 64-bit Windows implementation
138-
// lives in seh64_gnu.rs
139-
#[cfg(all(any(target_os = "ios", target_os = "netbsd", not(target_arch = "arm"))))]
140-
#[lang = "eh_personality"]
141-
#[no_mangle]
136+
// Shared version of the default personality routine, which is used directly on
137+
// most targets and indirectly on Windows x86_64 via SEH.
142138
#[allow(unused)]
143-
unsafe extern "C" fn rust_eh_personality(version: c_int,
144-
actions: uw::_Unwind_Action,
145-
exception_class: uw::_Unwind_Exception_Class,
146-
exception_object: *mut uw::_Unwind_Exception,
147-
context: *mut uw::_Unwind_Context)
148-
-> uw::_Unwind_Reason_Code {
139+
unsafe extern "C" fn rust_eh_personality_impl(version: c_int,
140+
actions: uw::_Unwind_Action,
141+
exception_class: uw::_Unwind_Exception_Class,
142+
exception_object: *mut uw::_Unwind_Exception,
143+
context: *mut uw::_Unwind_Context)
144+
-> uw::_Unwind_Reason_Code {
149145
if version != 1 {
150146
return uw::_URC_FATAL_PHASE1_ERROR;
151147
}
152-
let eh_action = match find_eh_action(context) {
148+
let foreign_exception = exception_class != rust_exception_class();
149+
let eh_action = match find_eh_action(context, foreign_exception) {
153150
Ok(action) => action,
154151
Err(_) => return uw::_URC_FATAL_PHASE1_ERROR,
155152
};
@@ -175,6 +172,23 @@ unsafe extern "C" fn rust_eh_personality(version: c_int,
175172
}
176173
}
177174

175+
// The personality routine for most of our targets, except ARM, which has a slightly different ABI
176+
// (however, iOS goes here as it uses SjLj unwinding). Also, the 64-bit Windows implementation
177+
// uses a different personality (below) but eventually also calls rust_eh_personality_impl.
178+
#[cfg(all(any(target_os = "ios", target_os = "netbsd", not(target_arch = "arm")),
179+
not(all(windows, target_arch = "x86_64", target_env = "gnu"))))]
180+
#[lang = "eh_personality"]
181+
#[no_mangle]
182+
#[allow(unused)]
183+
unsafe extern "C" fn rust_eh_personality(version: c_int,
184+
actions: uw::_Unwind_Action,
185+
exception_class: uw::_Unwind_Exception_Class,
186+
exception_object: *mut uw::_Unwind_Exception,
187+
context: *mut uw::_Unwind_Context)
188+
-> uw::_Unwind_Reason_Code {
189+
rust_eh_personality_impl(version, actions, exception_class, exception_object, context)
190+
}
191+
178192
// ARM EHABI personality routine.
179193
// http://infocenter.arm.com/help/topic/com.arm.doc.ihi0038b/IHI0038B_ehabi.pdf
180194
#[cfg(all(target_arch = "arm", not(target_os = "ios"), not(target_os = "netbsd")))]
@@ -215,7 +229,9 @@ unsafe extern "C" fn rust_eh_personality(state: uw::_Unwind_State,
215229
// _Unwind_Context in our libunwind bindings and fetch the required data from there directly,
216230
// bypassing DWARF compatibility functions.
217231

218-
let eh_action = match find_eh_action(context) {
232+
let exception_class = unsafe { (*exception_object).exception_class };
233+
let foreign_exception = exception_class != rust_exception_class();
234+
let eh_action = match find_eh_action(context, foreign_exception) {
219235
Ok(action) => action,
220236
Err(_) => return uw::_URC_FAILURE,
221237
};
@@ -259,7 +275,25 @@ unsafe extern "C" fn rust_eh_personality(state: uw::_Unwind_State,
259275
}
260276
}
261277

262-
unsafe fn find_eh_action(context: *mut uw::_Unwind_Context)
278+
// On x86_64 MinGW targets, the unwinding mechanism is SEH however the unwind
279+
// handler data (aka LSDA) uses GCC-compatible encoding.
280+
#[cfg(all(windows, target_arch = "x86_64", target_env = "gnu"))]
281+
#[lang = "eh_personality"]
282+
#[no_mangle]
283+
#[allow(nonstandard_style)]
284+
unsafe extern "C" fn rust_eh_personality(exceptionRecord: *mut uw::EXCEPTION_RECORD,
285+
establisherFrame: uw::LPVOID,
286+
contextRecord: *mut uw::CONTEXT,
287+
dispatcherContext: *mut uw::DISPATCHER_CONTEXT)
288+
-> uw::EXCEPTION_DISPOSITION {
289+
uw::_GCC_specific_handler(exceptionRecord,
290+
establisherFrame,
291+
contextRecord,
292+
dispatcherContext,
293+
rust_eh_personality_impl)
294+
}
295+
296+
unsafe fn find_eh_action(context: *mut uw::_Unwind_Context, foreign_exception: bool)
263297
-> Result<EHAction, ()>
264298
{
265299
let lsda = uw::_Unwind_GetLanguageSpecificData(context) as *const u8;
@@ -273,11 +307,11 @@ unsafe fn find_eh_action(context: *mut uw::_Unwind_Context)
273307
get_text_start: &|| uw::_Unwind_GetTextRelBase(context),
274308
get_data_start: &|| uw::_Unwind_GetDataRelBase(context),
275309
};
276-
eh::find_eh_action(lsda, &eh_context)
310+
eh::find_eh_action(lsda, &eh_context, foreign_exception)
277311
}
278312

279313
// See docs in the `unwind` module.
280-
#[cfg(all(target_os="windows", target_arch = "x86", target_env="gnu"))]
314+
#[cfg(all(target_os="windows", any(target_arch = "x86", target_arch = "x86_64"), target_env="gnu"))]
281315
#[lang = "eh_unwind_resume"]
282316
#[unwind(allowed)]
283317
unsafe extern "C" fn rust_eh_unwind_resume(panic_ctx: *mut u8) -> ! {

src/libpanic_unwind/lib.rs

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,8 @@
55
//! essentially gets categorized into three buckets currently:
66
//!
77
//! 1. MSVC targets use SEH in the `seh.rs` file.
8-
//! 2. The 64-bit MinGW target half-uses SEH and half-use gcc-like information
9-
//! in the `seh64_gnu.rs` module.
10-
//! 3. All other targets use libunwind/libgcc in the `gcc/mod.rs` module.
8+
//! 2. Emscripten uses C++ exceptions in the `emcc.rs` file.
9+
//! 3. All other targets use libunwind/libgcc in the `gcc.rs` file.
1110
//!
1211
//! More documentation about each implementation can be found in the respective
1312
//! module.
@@ -52,9 +51,6 @@ cfg_if::cfg_if! {
5251
} else if #[cfg(target_env = "msvc")] {
5352
#[path = "seh.rs"]
5453
mod imp;
55-
} else if #[cfg(all(windows, target_arch = "x86_64", target_env = "gnu"))] {
56-
#[path = "seh64_gnu.rs"]
57-
mod imp;
5854
} else {
5955
// Rust runtime's startup objects depend on these symbols, so make them public.
6056
#[cfg(all(target_os="windows", target_arch = "x86", target_env="gnu"))]

src/libpanic_unwind/seh64_gnu.rs

Lines changed: 0 additions & 127 deletions
This file was deleted.

src/libunwind/libunwind.rs

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -244,3 +244,30 @@ if #[cfg(not(all(target_os = "ios", target_arch = "arm")))] {
244244
}
245245
}
246246
} // cfg_if!
247+
248+
cfg_if::cfg_if! {
249+
if #[cfg(all(windows, target_arch = "x86_64", target_env = "gnu"))] {
250+
// We declare these as opaque types. This is fine since you just need to
251+
// pass them to _GCC_specific_handler and forget about them.
252+
pub enum EXCEPTION_RECORD {}
253+
pub type LPVOID = *mut c_void;
254+
pub enum CONTEXT {}
255+
pub enum DISPATCHER_CONTEXT {}
256+
pub type EXCEPTION_DISPOSITION = c_int;
257+
type PersonalityFn = unsafe extern "C" fn(version: c_int,
258+
actions: _Unwind_Action,
259+
exception_class: _Unwind_Exception_Class,
260+
exception_object: *mut _Unwind_Exception,
261+
context: *mut _Unwind_Context)
262+
-> _Unwind_Reason_Code;
263+
264+
extern "C" {
265+
pub fn _GCC_specific_handler(exceptionRecord: *mut EXCEPTION_RECORD,
266+
establisherFrame: LPVOID,
267+
contextRecord: *mut CONTEXT,
268+
dispatcherContext: *mut DISPATCHER_CONTEXT,
269+
personality: PersonalityFn)
270+
-> EXCEPTION_DISPOSITION;
271+
}
272+
}
273+
} // cfg_if!
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
-include ../tools.mk
2+
3+
all: foo
4+
$(call RUN,foo)
5+
6+
foo: foo.rs $(call NATIVE_STATICLIB,foo)
7+
$(RUSTC) $< -lfoo $(EXTRACXXFLAGS)
8+
9+
$(TMPDIR)/libfoo.o: foo.cpp
10+
$(call COMPILE_OBJ_CXX,$@,$<)

0 commit comments

Comments
 (0)