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)]

38393940

use super::dwarf::eh::{self, EHAction, EHContext};

4041

use 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

93949495

cfg_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 {

115127

return 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

}

278293279294

unsafe 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

}