Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

std: Avoid panics in rust_eh_personality #42487

Merged
merged 1 commit into from
Jun 8, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 32 additions & 23 deletions src/libpanic_unwind/dwarf/eh.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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
};
Expand All @@ -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.
Expand All @@ -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;
Expand All @@ -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))
}
}
}
Expand All @@ -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 {
Expand All @@ -171,25 +178,27 @@ 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 {
DW_EH_PE_absptr => 0,
// 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)
}
14 changes: 11 additions & 3 deletions src/libpanic_unwind/gcc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,10 @@ unsafe extern "C" fn rust_eh_personality(version: c_int,
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 |
Expand Down Expand Up @@ -219,7 +222,10 @@ unsafe extern "C" fn rust_eh_personality(state: uw::_Unwind_State,
// _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 |
Expand Down Expand Up @@ -260,7 +266,9 @@ unsafe extern "C" fn rust_eh_personality(state: uw::_Unwind_State,
}
}

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);
Expand Down
9 changes: 5 additions & 4 deletions src/libpanic_unwind/seh64_gnu.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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(),
}
}