]> git.lizzy.rs Git - rust.git/commitdiff
std: Avoid panics in rust_eh_personality
authorAlex Crichton <alex@alexcrichton.com>
Tue, 6 Jun 2017 18:34:10 +0000 (11:34 -0700)
committerAlex Crichton <alex@alexcrichton.com>
Thu, 8 Jun 2017 14:06:43 +0000 (07:06 -0700)
This commit removes a few calls to panic and/or assert in `rust_eh_personality`.
This function definitely can't itself panic (that'd probably segfault or do
something else weird) and I was also noticing that a `pub extern fn foo() {}`
cdylib was abnormally large. Turns out all that size was the panicking machinery
brought in by the personality function!

The change here is to return a `Result` internally so we can bubble up the fatal
error, eventually translating to the appropriate error code for the libunwind
ABI.

src/libpanic_unwind/dwarf/eh.rs
src/libpanic_unwind/gcc.rs
src/libpanic_unwind/seh64_gnu.rs

index e7994f4e0ef0a3837ee33ad2719db00e18d45c80..0c326ce3718435f6f4517275f1b7838e12b931b8 100644 (file)
@@ -61,9 +61,11 @@ pub enum EHAction {
 
 pub const USING_SJLJ_EXCEPTIONS: bool = cfg!(all(target_os = "ios", target_arch = "arm"));
 
-pub unsafe fn find_eh_action(lsda: *const u8, context: &EHContext) -> EHAction {
+pub unsafe fn find_eh_action(lsda: *const u8, context: &EHContext)
+    -> Result<EHAction, ()>
+{
     if lsda.is_null() {
-        return EHAction::None;
+        return Ok(EHAction::None)
     }
 
     let func_start = context.func_start;
@@ -72,7 +74,7 @@ pub unsafe fn find_eh_action(lsda: *const u8, context: &EHContext) -> EHAction {
     let start_encoding = reader.read::<u8>();
     // base address for landing pad offsets
     let lpad_base = if start_encoding != DW_EH_PE_omit {
-        read_encoded_pointer(&mut reader, context, start_encoding)
+        read_encoded_pointer(&mut reader, context, start_encoding)?
     } else {
         func_start
     };
@@ -90,9 +92,9 @@ pub unsafe fn find_eh_action(lsda: *const u8, context: &EHContext) -> EHAction {
 
     if !USING_SJLJ_EXCEPTIONS {
         while reader.ptr < action_table {
-            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_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();
             // Callsite table is sorted by cs_start, so if we've passed the ip, we
             // may stop searching.
@@ -101,23 +103,23 @@ pub unsafe fn find_eh_action(lsda: *const u8, context: &EHContext) -> EHAction {
             }
             if ip < func_start + cs_start + cs_len {
                 if cs_lpad == 0 {
-                    return EHAction::None;
+                    return Ok(EHAction::None)
                 } else {
                     let lpad = lpad_base + cs_lpad;
-                    return interpret_cs_action(cs_action, lpad);
+                    return Ok(interpret_cs_action(cs_action, lpad))
                 }
             }
         }
         // Ip is not present in the table.  This should not happen... but it does: issue #35011.
         // So rather than returning EHAction::Terminate, we do this.
-        EHAction::None
+        Ok(EHAction::None)
     } else {
         // SjLj version:
         // The "IP" is an index into the call-site table, with two exceptions:
         // -1 means 'no-action', and 0 means 'terminate'.
         match ip as isize {
-            -1 => return EHAction::None,
-            0 => return EHAction::Terminate,
+            -1 => return Ok(EHAction::None),
+            0 => return Ok(EHAction::Terminate),
             _ => (),
         }
         let mut idx = ip;
@@ -129,7 +131,7 @@ pub unsafe fn find_eh_action(lsda: *const u8, context: &EHContext) -> EHAction {
                 // 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 interpret_cs_action(cs_action, lpad);
+                return Ok(interpret_cs_action(cs_action, lpad))
             }
         }
     }
@@ -144,21 +146,26 @@ fn interpret_cs_action(cs_action: u64, lpad: usize) -> EHAction {
 }
 
 #[inline]
-fn round_up(unrounded: usize, align: usize) -> usize {
-    assert!(align.is_power_of_two());
-    (unrounded + align - 1) & !(align - 1)
+fn round_up(unrounded: usize, align: usize) -> Result<usize, ()> {
+    if align.is_power_of_two() {
+        Ok((unrounded + align - 1) & !(align - 1))
+    } else {
+        Err(())
+    }
 }
 
 unsafe fn read_encoded_pointer(reader: &mut DwarfReader,
                                context: &EHContext,
                                encoding: u8)
-                               -> usize {
-    assert!(encoding != DW_EH_PE_omit);
+                               -> Result<usize, ()> {
+    if encoding == DW_EH_PE_omit {
+        return Err(())
+    }
 
     // DW_EH_PE_aligned implies it's an absolute pointer value
     if encoding == DW_EH_PE_aligned {
-        reader.ptr = round_up(reader.ptr as usize, mem::size_of::<usize>()) as *const u8;
-        return reader.read::<usize>();
+        reader.ptr = round_up(reader.ptr as usize, mem::size_of::<usize>())? as *const u8;
+        return Ok(reader.read::<usize>())
     }
 
     let mut result = match encoding & 0x0F {
@@ -171,7 +178,7 @@ unsafe fn read_encoded_pointer(reader: &mut DwarfReader,
         DW_EH_PE_sdata2 => reader.read::<i16>() as usize,
         DW_EH_PE_sdata4 => reader.read::<i32>() as usize,
         DW_EH_PE_sdata8 => reader.read::<i64>() as usize,
-        _ => panic!(),
+        _ => return Err(()),
     };
 
     result += match encoding & 0x70 {
@@ -179,17 +186,19 @@ unsafe fn read_encoded_pointer(reader: &mut DwarfReader,
         // relative to address of the encoded value, despite the name
         DW_EH_PE_pcrel => reader.ptr as usize,
         DW_EH_PE_funcrel => {
-            assert!(context.func_start != 0);
+            if context.func_start == 0 {
+                return Err(())
+            }
             context.func_start
         }
         DW_EH_PE_textrel => (*context.get_text_start)(),
         DW_EH_PE_datarel => (*context.get_data_start)(),
-        _ => panic!(),
+        _ => return Err(()),
     };
 
     if encoding & DW_EH_PE_indirect != 0 {
         result = *(result as *const usize);
     }
 
-    result
+    Ok(result)
 }
index 84abc6bc4a5132e248470e31ad231cf1e12b8aa5..aadbeb96b2d235a255c8981c445de957fb39223c 100644 (file)
@@ -156,7 +156,10 @@ fn rust_exception_class() -> uw::_Unwind_Exception_Class {
     if version != 1 {
         return uw::_URC_FATAL_PHASE1_ERROR;
     }
-    let eh_action = find_eh_action(context);
+    let eh_action = match find_eh_action(context) {
+        Ok(action) => action,
+        Err(_) => return uw::_URC_FATAL_PHASE1_ERROR,
+    };
     if actions as i32 & uw::_UA_SEARCH_PHASE as i32 != 0 {
         match eh_action {
             EHAction::None |
@@ -219,7 +222,10 @@ fn rust_exception_class() -> uw::_Unwind_Exception_Class {
     // _Unwind_Context in our libunwind bindings and fetch the required data from there directly,
     // bypassing DWARF compatibility functions.
 
-    let eh_action = find_eh_action(context);
+    let eh_action = match find_eh_action(context) {
+        Ok(action) => action,
+        Err(_) => return uw::_URC_FAILURE,
+    };
     if search_phase {
         match eh_action {
             EHAction::None |
@@ -260,7 +266,9 @@ fn __gnu_unwind_frame(exception_object: *mut uw::_Unwind_Exception,
     }
 }
 
-unsafe fn find_eh_action(context: *mut uw::_Unwind_Context) -> EHAction {
+unsafe fn find_eh_action(context: *mut uw::_Unwind_Context)
+    -> Result<EHAction, ()>
+{
     let lsda = uw::_Unwind_GetLanguageSpecificData(context) as *const u8;
     let mut ip_before_instr: c_int = 0;
     let ip = uw::_Unwind_GetIPInfo(context, &mut ip_before_instr);
index d4906b556b31a5be0fd2e9922dd7c9ade6629f0e..0a9fa7d9a80b44e637cb453dcc6df449a0c82847 100644 (file)
@@ -128,9 +128,10 @@ unsafe fn find_landing_pad(dc: &c::DISPATCHER_CONTEXT) -> Option<usize> {
         get_data_start: &|| unimplemented!(),
     };
     match find_eh_action(dc.HandlerData, &eh_ctx) {
-        EHAction::None => None,
-        EHAction::Cleanup(lpad) |
-        EHAction::Catch(lpad) => Some(lpad),
-        EHAction::Terminate => intrinsics::abort(),
+        Err(_) |
+        Ok(EHAction::None) => None,
+        Ok(EHAction::Cleanup(lpad)) |
+        Ok(EHAction::Catch(lpad)) => Some(lpad),
+        Ok(EHAction::Terminate) => intrinsics::abort(),
     }
 }