Rollup merge of #106446 - bzEq:fix-unwind-lsda, r=Amanieu

[LSDA] Take ttype_index into account when taking unwind action

If `cs_action != 0`, we should check the `ttype_index` field in action record. If `ttype_index == 0`, a clean up action is taken; otherwise catch action is taken.

This can fix unwind failure on AIX which uses LLVM's libunwind by default. IIUC, rust's LSDA is borrowed from c++ and I'm assuming itanium-cxx-abi https://itanium-cxx-abi.github.io/cxx-abi/exceptions.pdf should be followed, so the fix follows what libcxxabi does. See ec48682ce9/libcxxabi/src/cxa_personality.cpp (L152) for use of `ttype_index`.
This commit is contained in:
Yuki Okushi 2023-01-13 05:47:21 +09:00 committed by GitHub
commit 3f21b812be
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -84,7 +84,7 @@ pub unsafe fn find_eh_action(lsda: *const u8, context: &EHContext<'_>) -> Result
let cs_start = read_encoded_pointer(&mut reader, context, call_site_encoding)?;
let cs_len = read_encoded_pointer(&mut reader, context, call_site_encoding)?;
let cs_lpad = read_encoded_pointer(&mut reader, context, call_site_encoding)?;
let cs_action = reader.read_uleb128();
let cs_action_entry = reader.read_uleb128();
// Callsite table is sorted by cs_start, so if we've passed the ip, we
// may stop searching.
if ip < func_start + cs_start {
@ -95,7 +95,7 @@ pub unsafe fn find_eh_action(lsda: *const u8, context: &EHContext<'_>) -> Result
return Ok(EHAction::None);
} else {
let lpad = lpad_base + cs_lpad;
return Ok(interpret_cs_action(cs_action, lpad));
return Ok(interpret_cs_action(action_table as *mut u8, cs_action_entry, lpad));
}
}
}
@ -113,26 +113,39 @@ pub unsafe fn find_eh_action(lsda: *const u8, context: &EHContext<'_>) -> Result
let mut idx = ip;
loop {
let cs_lpad = reader.read_uleb128();
let cs_action = reader.read_uleb128();
let cs_action_entry = reader.read_uleb128();
idx -= 1;
if idx == 0 {
// Can never have null landing pad for sjlj -- that would have
// been indicated by a -1 call site index.
let lpad = (cs_lpad + 1) as usize;
return Ok(interpret_cs_action(cs_action, lpad));
return Ok(interpret_cs_action(action_table as *mut u8, cs_action_entry, lpad));
}
}
}
}
fn interpret_cs_action(cs_action: u64, lpad: usize) -> EHAction {
if cs_action == 0 {
// If cs_action is 0 then this is a cleanup (Drop::drop). We run these
unsafe fn interpret_cs_action(
action_table: *mut u8,
cs_action_entry: u64,
lpad: usize,
) -> EHAction {
if cs_action_entry == 0 {
// If cs_action_entry is 0 then this is a cleanup (Drop::drop). We run these
// for both Rust panics and foreign exceptions.
EHAction::Cleanup(lpad)
} else {
// Stop unwinding Rust panics at catch_unwind.
EHAction::Catch(lpad)
// If lpad != 0 and cs_action_entry != 0, we have to check ttype_index.
// If ttype_index == 0 under the condition, we take cleanup action.
let action_record = (action_table as *mut u8).offset(cs_action_entry as isize - 1);
let mut action_reader = DwarfReader::new(action_record);
let ttype_index = action_reader.read_sleb128();
if ttype_index == 0 {
EHAction::Cleanup(lpad)
} else {
// Stop unwinding Rust panics at catch_unwind.
EHAction::Catch(lpad)
}
}
}