std: unsafe-wrap gcc::rust_eh_personality and impl · model-checking/verify-rust-std@d252b6b
@@ -35,6 +35,7 @@
3535//!
3636//! Once stack has been unwound down to the handler frame level, unwinding stops
3737//! and the last personality routine transfers control to the catch block.
38+#![forbid(unsafe_op_in_unsafe_fn)]
38393940use super::dwarf::eh::{self, EHAction, EHContext};
4041use crate::ffi::c_int;
@@ -92,7 +93,11 @@ const UNWIND_DATA_REG: (i32, i32) = (4, 5); // a0, a1
9293// https://github.com/gcc-mirror/gcc/blob/trunk/libgcc/unwind-c.c
93949495cfg_if::cfg_if! {
95-if #[cfg(all(not(all(target_vendor = "apple", not(target_os = "watchos"))), target_arch = "arm", not(target_os = "netbsd")))] {
96+if #[cfg(all(
97+ target_arch = "arm",
98+ not(all(target_vendor = "apple", not(target_os = "watchos"))),
99+ not(target_os = "netbsd"),
100+))] {
96101// ARM EHABI personality routine.
97102// https://web.archive.org/web/20190728160938/https://infocenter.arm.com/help/topic/com.arm.doc.ihi0038b/IHI0038B_ehabi.pdf
98103//
@@ -104,90 +109,94 @@ cfg_if::cfg_if! {
104109 exception_object: *mut uw::_Unwind_Exception,
105110 context: *mut uw::_Unwind_Context,
106111) -> uw::_Unwind_Reason_Code {
107-let state = state as c_int;
108-let action = state & uw::_US_ACTION_MASK as c_int;
109-let search_phase = if action == uw::_US_VIRTUAL_UNWIND_FRAME as c_int {
110-// Backtraces on ARM will call the personality routine with
111-// state == _US_VIRTUAL_UNWIND_FRAME | _US_FORCE_UNWIND. In those cases
112-// we want to continue unwinding the stack, otherwise all our backtraces
113-// would end at __rust_try
114-if state & uw::_US_FORCE_UNWIND as c_int != 0 {
112+unsafe {
113+let state = state as c_int;
114+let action = state & uw::_US_ACTION_MASK as c_int;
115+let search_phase = if action == uw::_US_VIRTUAL_UNWIND_FRAME as c_int {
116+// Backtraces on ARM will call the personality routine with
117+// state == _US_VIRTUAL_UNWIND_FRAME | _US_FORCE_UNWIND. In those cases
118+// we want to continue unwinding the stack, otherwise all our backtraces
119+// would end at __rust_try
120+if state & uw::_US_FORCE_UNWIND as c_int != 0 {
121+return continue_unwind(exception_object, context);
122+}
123+true
124+} else if action == uw::_US_UNWIND_FRAME_STARTING as c_int {
125+false
126+} else if action == uw::_US_UNWIND_FRAME_RESUME as c_int {
115127return continue_unwind(exception_object, context);
116-}
117-true
118-} else if action == uw::_US_UNWIND_FRAME_STARTING as c_int {
119-false
120-} else if action == uw::_US_UNWIND_FRAME_RESUME as c_int {
121-return continue_unwind(exception_object, context);
122-} else {
123-return uw::_URC_FAILURE;
124-};
128+} else {
129+return uw::_URC_FAILURE;
130+};
125131126-// The DWARF unwinder assumes that _Unwind_Context holds things like the function
127-// and LSDA pointers, however ARM EHABI places them into the exception object.
128-// To preserve signatures of functions like _Unwind_GetLanguageSpecificData(), which
129-// take only the context pointer, GCC personality routines stash a pointer to
130-// exception_object in the context, using location reserved for ARM's
131-// "scratch register" (r12).
132- uw::_Unwind_SetGR(context, uw::UNWIND_POINTER_REG, exception_object as uw::_Unwind_Ptr);
133-// ...A more principled approach would be to provide the full definition of ARM's
134-// _Unwind_Context in our libunwind bindings and fetch the required data from there
135-// directly, bypassing DWARF compatibility functions.
132+ // The DWARF unwinder assumes that _Unwind_Context holds things like the function
133+ // and LSDA pointers, however ARM EHABI places them into the exception object.
134+ // To preserve signatures of functions like _Unwind_GetLanguageSpecificData(), which
135+ // take only the context pointer, GCC personality routines stash a pointer to
136+ // exception_object in the context, using location reserved for ARM's
137+ // "scratch register" (r12).
138+ uw::_Unwind_SetGR(context, uw::UNWIND_POINTER_REG, exception_object as uw::_Unwind_Ptr);
139+ // ...A more principled approach would be to provide the full definition of ARM's
140+ // _Unwind_Context in our libunwind bindings and fetch the required data from there
141+ // directly, bypassing DWARF compatibility functions.
136142137-let eh_action = match find_eh_action(context) {
138-Ok(action) => action,
139-Err(_) => return uw::_URC_FAILURE,
140-};
141-if search_phase {
142-match eh_action {
143-EHAction::None | EHAction::Cleanup(_) => {
144-return continue_unwind(exception_object, context);
143+let eh_action = match find_eh_action(context) {
144+Ok(action) => action,
145+Err(_) => return uw::_URC_FAILURE,
146+};
147+if search_phase {
148+match eh_action {
149+EHAction::None | EHAction::Cleanup(_) => {
150+return continue_unwind(exception_object, context);
151+}
152+EHAction::Catch(_) | EHAction::Filter(_) => {
153+// EHABI requires the personality routine to update the
154+// SP value in the barrier cache of the exception object.
155+(*exception_object).private[5] =
156+ uw::_Unwind_GetGR(context, uw::UNWIND_SP_REG);
157+return uw::_URC_HANDLER_FOUND;
158+}
159+EHAction::Terminate => return uw::_URC_FAILURE,
145160}
146-EHAction::Catch(_) | EHAction::Filter(_) => {
147-// EHABI requires the personality routine to update the
148-// SP value in the barrier cache of the exception object.
149-(*exception_object).private[5] =
150- uw::_Unwind_GetGR(context, uw::UNWIND_SP_REG);
151-return uw::_URC_HANDLER_FOUND;
152-}
153-EHAction::Terminate => return uw::_URC_FAILURE,
154-}
155-} else {
156-match eh_action {
157-EHAction::None => return continue_unwind(exception_object, context),
158-EHAction::Filter(_) if state & uw::_US_FORCE_UNWIND as c_int != 0 => return continue_unwind(exception_object, context),
159-EHAction::Cleanup(lpad) | EHAction::Catch(lpad) | EHAction::Filter(lpad) => {
160- uw::_Unwind_SetGR(
161- context,
162-UNWIND_DATA_REG.0,
163- exception_object as uw::_Unwind_Ptr,
164-);
165- uw::_Unwind_SetGR(context, UNWIND_DATA_REG.1, core::ptr::null());
166- uw::_Unwind_SetIP(context, lpad);
167-return uw::_URC_INSTALL_CONTEXT;
161+} else {
162+match eh_action {
163+EHAction::None => return continue_unwind(exception_object, context),
164+EHAction::Filter(_) if state & uw::_US_FORCE_UNWIND as c_int != 0 => return continue_unwind(exception_object, context),
165+EHAction::Cleanup(lpad) | EHAction::Catch(lpad) | EHAction::Filter(lpad) => {
166+ uw::_Unwind_SetGR(
167+ context,
168+UNWIND_DATA_REG.0,
169+ exception_object as uw::_Unwind_Ptr,
170+);
171+ uw::_Unwind_SetGR(context, UNWIND_DATA_REG.1, core::ptr::null());
172+ uw::_Unwind_SetIP(context, lpad);
173+return uw::_URC_INSTALL_CONTEXT;
174+}
175+EHAction::Terminate => return uw::_URC_FAILURE,
168176}
169-EHAction::Terminate => return uw::_URC_FAILURE,
170177}
171-}
172178173-// On ARM EHABI the personality routine is responsible for actually
174-// unwinding a single stack frame before returning (ARM EHABI Sec. 6.1).
175-unsafe fn continue_unwind(
176- exception_object: *mut uw::_Unwind_Exception,
177- context: *mut uw::_Unwind_Context,
178-) -> uw::_Unwind_Reason_Code {
179-if __gnu_unwind_frame(exception_object, context) == uw::_URC_NO_REASON {
180- uw::_URC_CONTINUE_UNWIND
181-} else {
182- uw::_URC_FAILURE
183-}
184-}
185-// defined in libgcc
186- extern "C" {
187-fn __gnu_unwind_frame(
179+// On ARM EHABI the personality routine is responsible for actually
180+// unwinding a single stack frame before returning (ARM EHABI Sec. 6.1).
181+unsafe fn continue_unwind(
188182 exception_object: *mut uw::_Unwind_Exception,
189183 context: *mut uw::_Unwind_Context,
190-) -> uw::_Unwind_Reason_Code;
184+) -> uw::_Unwind_Reason_Code {
185+unsafe {
186+if __gnu_unwind_frame(exception_object, context) == uw::_URC_NO_REASON {
187+ uw::_URC_CONTINUE_UNWIND
188+} else {
189+ uw::_URC_FAILURE
190+}
191+}
192+}
193+// defined in libgcc
194+ extern "C" {
195+fn __gnu_unwind_frame(
196+ exception_object: *mut uw::_Unwind_Exception,
197+ context: *mut uw::_Unwind_Context,
198+) -> uw::_Unwind_Reason_Code;
199+}
191200}
192201}
193202} else {
@@ -200,35 +209,37 @@ cfg_if::cfg_if! {
200209 exception_object: *mut uw::_Unwind_Exception,
201210 context: *mut uw::_Unwind_Context,
202211) -> uw::_Unwind_Reason_Code {
203-if version != 1 {
204-return uw::_URC_FATAL_PHASE1_ERROR;
205-}
206-let eh_action = match find_eh_action(context) {
207-Ok(action) => action,
208-Err(_) => return uw::_URC_FATAL_PHASE1_ERROR,
209-};
210-if actions as i32 & uw::_UA_SEARCH_PHASE as i32 != 0 {
211-match eh_action {
212-EHAction::None | EHAction::Cleanup(_) => uw::_URC_CONTINUE_UNWIND,
213-EHAction::Catch(_) | EHAction::Filter(_) => uw::_URC_HANDLER_FOUND,
214-EHAction::Terminate => uw::_URC_FATAL_PHASE1_ERROR,
212+unsafe {
213+if version != 1 {
214+return uw::_URC_FATAL_PHASE1_ERROR;
215215}
216-} else {
217-match eh_action {
218-EHAction::None => uw::_URC_CONTINUE_UNWIND,
219-// Forced unwinding hits a terminate action.
220-EHAction::Filter(_) if actions as i32 & uw::_UA_FORCE_UNWIND as i32 != 0 => uw::_URC_CONTINUE_UNWIND,
221-EHAction::Cleanup(lpad) | EHAction::Catch(lpad) | EHAction::Filter(lpad) => {
222- uw::_Unwind_SetGR(
223- context,
224-UNWIND_DATA_REG.0,
225- exception_object.cast(),
226-);
227- uw::_Unwind_SetGR(context, UNWIND_DATA_REG.1, core::ptr::null());
228- uw::_Unwind_SetIP(context, lpad);
229- uw::_URC_INSTALL_CONTEXT
216+let eh_action = match find_eh_action(context) {
217+Ok(action) => action,
218+Err(_) => return uw::_URC_FATAL_PHASE1_ERROR,
219+};
220+if actions as i32 & uw::_UA_SEARCH_PHASE as i32 != 0 {
221+match eh_action {
222+EHAction::None | EHAction::Cleanup(_) => uw::_URC_CONTINUE_UNWIND,
223+EHAction::Catch(_) | EHAction::Filter(_) => uw::_URC_HANDLER_FOUND,
224+EHAction::Terminate => uw::_URC_FATAL_PHASE1_ERROR,
225+}
226+} else {
227+match eh_action {
228+EHAction::None => uw::_URC_CONTINUE_UNWIND,
229+// Forced unwinding hits a terminate action.
230+EHAction::Filter(_) if actions as i32 & uw::_UA_FORCE_UNWIND as i32 != 0 => uw::_URC_CONTINUE_UNWIND,
231+EHAction::Cleanup(lpad) | EHAction::Catch(lpad) | EHAction::Filter(lpad) => {
232+ uw::_Unwind_SetGR(
233+ context,
234+UNWIND_DATA_REG.0,
235+ exception_object.cast(),
236+);
237+ uw::_Unwind_SetGR(context, UNWIND_DATA_REG.1, core::ptr::null());
238+ uw::_Unwind_SetIP(context, lpad);
239+ uw::_URC_INSTALL_CONTEXT
240+}
241+EHAction::Terminate => uw::_URC_FATAL_PHASE2_ERROR,
230242}
231-EHAction::Terminate => uw::_URC_FATAL_PHASE2_ERROR,
232243}
233244}
234245}
@@ -245,13 +256,15 @@ cfg_if::cfg_if! {
245256 contextRecord: *mut uw::CONTEXT,
246257 dispatcherContext: *mut uw::DISPATCHER_CONTEXT,
247258) -> uw::EXCEPTION_DISPOSITION {
248- uw::_GCC_specific_handler(
249- exceptionRecord,
250- establisherFrame,
251- contextRecord,
252- dispatcherContext,
253- rust_eh_personality_impl,
254-)
259+unsafe {
260+ uw::_GCC_specific_handler(
261+ exceptionRecord,
262+ establisherFrame,
263+ contextRecord,
264+ dispatcherContext,
265+ rust_eh_personality_impl,
266+)
267+}
255268}
256269} else {
257270// The personality routine for most of our targets.
@@ -263,32 +276,36 @@ cfg_if::cfg_if! {
263276 exception_object: *mut uw::_Unwind_Exception,
264277 context: *mut uw::_Unwind_Context,
265278) -> uw::_Unwind_Reason_Code {
266- rust_eh_personality_impl(
267- version,
268- actions,
269- exception_class,
270- exception_object,
271- context,
272-)
279+unsafe {
280+ rust_eh_personality_impl(
281+ version,
282+ actions,
283+ exception_class,
284+ exception_object,
285+ context,
286+)
287+}
273288}
274289}
275290}
276291}
277292}
278293279294unsafe fn find_eh_action(context: *mut uw::_Unwind_Context) -> Result<EHAction, ()> {
280-let lsda = uw::_Unwind_GetLanguageSpecificData(context) as *const u8;
281-let mut ip_before_instr: c_int = 0;
282-let ip = uw::_Unwind_GetIPInfo(context, &mut ip_before_instr);
283-let eh_context = EHContext {
284-// The return address points 1 byte past the call instruction,
285-// which could be in the next IP range in LSDA range table.
286-//
287-// `ip = -1` has special meaning, so use wrapping sub to allow for that
288-ip: if ip_before_instr != 0 { ip } else { ip.wrapping_sub(1) },
289-func_start: uw::_Unwind_GetRegionStart(context),
290-get_text_start: &|| uw::_Unwind_GetTextRelBase(context),
291-get_data_start: &|| uw::_Unwind_GetDataRelBase(context),
292-};
293- eh::find_eh_action(lsda, &eh_context)
295+unsafe {
296+let lsda = uw::_Unwind_GetLanguageSpecificData(context) as *const u8;
297+let mut ip_before_instr: c_int = 0;
298+let ip = uw::_Unwind_GetIPInfo(context, &mut ip_before_instr);
299+let eh_context = EHContext {
300+// The return address points 1 byte past the call instruction,
301+// which could be in the next IP range in LSDA range table.
302+//
303+// `ip = -1` has special meaning, so use wrapping sub to allow for that
304+ip: if ip_before_instr != 0 { ip } else { ip.wrapping_sub(1) },
305+func_start: uw::_Unwind_GetRegionStart(context),
306+get_text_start: &|| uw::_Unwind_GetTextRelBase(context),
307+get_data_start: &|| uw::_Unwind_GetDataRelBase(context),
308+};
309+ eh::find_eh_action(lsda, &eh_context)
310+}
294311}