diff options
author | Dave Watson <davejwatson@fb.com> | 2017-08-17 12:01:16 -0700 |
---|---|---|
committer | Dave Watson <davejwatson@fb.com> | 2017-08-24 08:51:18 -0700 |
commit | 3d9a694de85f2ba10368b4fbc2aff1c6b8b76f58 (patch) | |
tree | cfff1756b93a16b3453ab3c3516d4dea419b097e | |
parent | 836c91c43d7a996028aa7e8d1f53630a6b8e7cbe (diff) | |
download | libunwind-3d9a694de85f2ba10368b4fbc2aff1c6b8b76f58.tar.gz |
dwarf: Fix incorrect application of restore_state
Repro for a multilib binary on host x86_64:
CFLAGS="-m32" LDFLAGS="-m32" ./configure --enable-debug -- host=i686-pc-linux-gnu --target=i686-pc-linux-gnu --libdur=/usr/lib32 --prefix=/usr --disable-documentation
make check
Gtest-init function fails trying to step through libc_start_main. The CFA function is:
DW_CFA_def_cfa_offset: 112
DW_CFA_advance_loc: 5 to ...643
DW_CFA_restore state
Where the return address is 643.
Generally, it appears we apply all ip <= end_ip, which is incorrect in some circumstances.
libgcc only applies ip < end_ip + is_signal_frame, but that seems to break async signal handling
tests in libunwind for unknown reasons.
This is somewhat simlar to the fix in e9e8ed73e for GNU_args_size,
where the same ip check was added.
-rw-r--r-- | src/dwarf/Gparser.c | 6 |
1 files changed, 4 insertions, 2 deletions
diff --git a/src/dwarf/Gparser.c b/src/dwarf/Gparser.c index e8eaeac8..9d405e76 100644 --- a/src/dwarf/Gparser.c +++ b/src/dwarf/Gparser.c @@ -289,8 +289,10 @@ run_cfi_program (struct dwarf_cursor *c, dwarf_state_record_t *sr, ret = -UNW_EINVAL; break; } - memcpy (&sr->rs_current, &(*rs_stack)->state, sizeof (sr->rs_current)); - pop_rstate_stack(rs_stack); + if (*ip < end_ip) { + memcpy (&sr->rs_current, &(*rs_stack)->state, sizeof (sr->rs_current)); + pop_rstate_stack(rs_stack); + } Debug (15, "CFA_restore_state\n"); break; |