about summary refs log tree commit diff
diff options
context:
space:
mode:
authorYuki Okushi <huyuumi.dev+love@gmail.com>2023-01-13 05:47:21 +0900
committerGitHub <noreply@github.com>2023-01-13 05:47:21 +0900
commit3f21b812bec836dc3bc0f56d4e34b7c46ec68af1 (patch)
tree07315c53a463f7a78a79a40201491ce661af456d
parentfa8f77a1deb0952fa81fd4f2f0809ceec8d7f7e8 (diff)
parent93ef4b3991d19cddf011da8f0b5a7bf9a8672541 (diff)
downloadrust-3f21b812bec836dc3bc0f56d4e34b7c46ec68af1.tar.gz
rust-3f21b812bec836dc3bc0f56d4e34b7c46ec68af1.zip
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 https://github.com/llvm/llvm-project/blob/ec48682ce9f61d056361c5095f21e930b8365661/libcxxabi/src/cxa_personality.cpp#L152 for use of `ttype_index`.
-rw-r--r--library/std/src/personality/dwarf/eh.rs31
1 files changed, 22 insertions, 9 deletions
diff --git a/library/std/src/personality/dwarf/eh.rs b/library/std/src/personality/dwarf/eh.rs
index a783e187004..87585a8fcd0 100644
--- a/library/std/src/personality/dwarf/eh.rs
+++ b/library/std/src/personality/dwarf/eh.rs
@@ -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)
+        }
     }
 }