Browse Source

Special case Rust unwind terminate for forced unwind

This changes the personality to match the current libstd impl.
Gary Guo 11 tháng trước cách đây
mục cha
commit
2f19304851
2 tập tin đã thay đổi với 30 bổ sung13 xóa
  1. 1 1
      Cargo.lock
  2. 29 12
      src/personality.rs

+ 1 - 1
Cargo.lock

@@ -69,7 +69,7 @@ dependencies = [
 
 [[package]]
 name = "unwinding"
-version = "0.2.1"
+version = "0.2.2"
 dependencies = [
  "compiler_builtins",
  "gimli",

+ 29 - 12
src/personality.rs

@@ -16,6 +16,8 @@ enum EHAction {
     None,
     Cleanup(usize),
     Catch(usize),
+    Filter(usize),
+    Terminate,
 }
 
 fn parse_pointer_encoding(input: &mut StaticSlice) -> gimli::Result<constants::DwEhPe> {
@@ -92,31 +94,31 @@ fn find_eh_action(
 
     let call_site_encoding = parse_pointer_encoding(reader)?;
     let call_site_table_length = reader.read_uleb128()?;
-    reader.truncate(call_site_table_length as _)?;
+    let (mut call_site_table, mut action_table) = reader.split_at(call_site_table_length as _);
 
-    while !reader.is_empty() {
+    while !call_site_table.is_empty() {
         let cs_start = unsafe {
             deref_pointer(parse_encoded_pointer(
                 call_site_encoding,
                 unwind_ctx,
-                reader,
+                &mut call_site_table,
             )?)
         };
         let cs_len = unsafe {
             deref_pointer(parse_encoded_pointer(
                 call_site_encoding,
                 unwind_ctx,
-                reader,
+                &mut call_site_table,
             )?)
         };
         let cs_lpad = unsafe {
             deref_pointer(parse_encoded_pointer(
                 call_site_encoding,
                 unwind_ctx,
-                reader,
+                &mut call_site_table,
             )?)
         };
-        let cs_action = reader.read_uleb128()?;
+        let cs_action = call_site_table.read_uleb128()?;
         if ip < func_start + cs_start {
             break;
         }
@@ -125,14 +127,23 @@ fn find_eh_action(
                 return Ok(EHAction::None);
             } else {
                 let lpad = lpad_base + cs_lpad;
-                return Ok(match cs_action {
-                    0 => EHAction::Cleanup(lpad),
-                    _ => EHAction::Catch(lpad),
+                if cs_action == 0 {
+                    return Ok(EHAction::Cleanup(lpad));
+                }
+
+                action_table.skip((cs_action - 1) as _)?;
+                let ttype_index = action_table.read_sleb128()?;
+                return Ok(if ttype_index == 0 {
+                    EHAction::Cleanup(lpad)
+                } else if ttype_index > 0 {
+                    EHAction::Catch(lpad)
+                } else {
+                    EHAction::Filter(lpad)
                 });
             }
         }
     }
-    Ok(EHAction::None)
+    Ok(EHAction::Terminate)
 }
 
 #[lang = "eh_personality"]
@@ -161,12 +172,17 @@ unsafe fn rust_eh_personality(
     if actions.contains(UnwindAction::SEARCH_PHASE) {
         match eh_action {
             EHAction::None | EHAction::Cleanup(_) => UnwindReasonCode::CONTINUE_UNWIND,
-            EHAction::Catch(_) => UnwindReasonCode::HANDLER_FOUND,
+            EHAction::Catch(_) | EHAction::Filter(_) => UnwindReasonCode::HANDLER_FOUND,
+            EHAction::Terminate => UnwindReasonCode::FATAL_PHASE1_ERROR,
         }
     } else {
         match eh_action {
             EHAction::None => UnwindReasonCode::CONTINUE_UNWIND,
-            EHAction::Cleanup(lpad) | EHAction::Catch(lpad) => {
+            // Forced unwinding hits a terminate action.
+            EHAction::Filter(_) if actions.contains(UnwindAction::FORCE_UNWIND) => {
+                UnwindReasonCode::CONTINUE_UNWIND
+            }
+            EHAction::Cleanup(lpad) | EHAction::Catch(lpad) | EHAction::Filter(lpad) => {
                 _Unwind_SetGR(
                     unwind_ctx,
                     Arch::UNWIND_DATA_REG.0 .0 as _,
@@ -176,6 +192,7 @@ unsafe fn rust_eh_personality(
                 _Unwind_SetIP(unwind_ctx, lpad);
                 UnwindReasonCode::INSTALL_CONTEXT
             }
+            EHAction::Terminate => UnwindReasonCode::FATAL_PHASE2_ERROR,
         }
     }
 }