Skip to content

Commit

Permalink
read/cfi: always reset context in initialize (#684)
Browse files Browse the repository at this point in the history
  • Loading branch information
philipc authored Nov 24, 2023
1 parent e6adc47 commit 4cc1fe0
Showing 1 changed file with 94 additions and 3 deletions.
97 changes: 94 additions & 3 deletions src/read/cfi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1994,9 +1994,8 @@ impl<R: Reader, A: UnwindContextStorage<R>> UnwindContext<R, A> {
bases: &BaseAddresses,
cie: &CommonInformationEntry<R>,
) -> Result<()> {
if self.is_initialized {
self.reset();
}
// Always reset because previous initialization failure may leave dirty state.
self.reset();

let mut table = UnwindTable::new_for_cie(section, bases, self, cie);
while table.next_row()?.is_some() {}
Expand Down Expand Up @@ -5874,6 +5873,98 @@ mod tests {
assert_eq!(Ok(None), table.next_row());
}

#[test]
fn test_unwind_table_cie_invalid_rule() {
let initial_instructions1 = Section::with_endian(Endian::Little)
// Test that stack length is reset.
.D8(constants::DW_CFA_remember_state.0)
// Test that stack value is reset (different register from that used later).
.D8(constants::DW_CFA_offset.0 | 4)
.uleb(8)
// Invalid due to missing operands.
.D8(constants::DW_CFA_offset.0);
let initial_instructions1 = initial_instructions1.get_contents().unwrap();

let cie1 = CommonInformationEntry {
offset: 0,
length: 0,
format: Format::Dwarf32,
version: 4,
augmentation: None,
address_size: 8,
segment_size: 0,
code_alignment_factor: 1,
data_alignment_factor: 1,
return_address_register: Register(3),
initial_instructions: EndianSlice::new(&initial_instructions1, LittleEndian),
};

let initial_instructions2 = Section::with_endian(Endian::Little)
// Register 3 is 4 from the CFA.
.D8(constants::DW_CFA_offset.0 | 3)
.uleb(4)
.append_repeated(constants::DW_CFA_nop.0, 4);
let initial_instructions2 = initial_instructions2.get_contents().unwrap();

let cie2 = CommonInformationEntry {
offset: 0,
length: 0,
format: Format::Dwarf32,
version: 4,
augmentation: None,
address_size: 8,
segment_size: 0,
code_alignment_factor: 1,
data_alignment_factor: 1,
return_address_register: Register(3),
initial_instructions: EndianSlice::new(&initial_instructions2, LittleEndian),
};

let fde1 = FrameDescriptionEntry {
offset: 0,
length: 0,
format: Format::Dwarf32,
cie: cie1.clone(),
initial_segment: 0,
initial_address: 0,
address_range: 100,
augmentation: None,
instructions: EndianSlice::new(&[], LittleEndian),
};

let fde2 = FrameDescriptionEntry {
offset: 0,
length: 0,
format: Format::Dwarf32,
cie: cie2.clone(),
initial_segment: 0,
initial_address: 0,
address_range: 100,
augmentation: None,
instructions: EndianSlice::new(&[], LittleEndian),
};

let section = &DebugFrame::from(EndianSlice::default());
let bases = &BaseAddresses::default();
let mut ctx = Box::new(UnwindContext::new());

let table = fde1
.rows(section, bases, &mut ctx)
.map_eof(&initial_instructions1);
assert_eq!(table.err(), Some(Error::UnexpectedEof(ReaderOffsetId(4))));
assert!(!ctx.is_initialized);
assert_eq!(ctx.stack.len(), 2);
assert_eq!(ctx.initial_rule, None);

let _table = fde2
.rows(section, bases, &mut ctx)
.expect("Should run initial program OK");
assert!(ctx.is_initialized);
assert_eq!(ctx.stack.len(), 1);
let expected_initial_rule = (Register(3), RegisterRule::Offset(4));
assert_eq!(ctx.initial_rule, Some(expected_initial_rule));
}

#[test]
fn test_unwind_table_next_row() {
let initial_instructions = Section::with_endian(Endian::Little)
Expand Down

0 comments on commit 4cc1fe0

Please sign in to comment.