Incorrect unwind when throwing exceptions - possible cause?

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



I have a hair-tearing problem with x86_64 gcc 9.3.0 (Ubuntu 20.04),
-O2 and the following "minimal" example
(the real minimal example also links in a bunch of 3rd party libraries
and is a part of a big project, so I can't really provide a minimal example,
but I slimmed it down to basically this):

class Application() {
public:
  Application(int argc, char **argv) {}

  int process() {
     if (argc > 1)  { throw std::runtime_error("Exception"); }

    // do some processing here
    return 0;
  }

int main(int argc, char **argv) {
  Application app(argc, argv);
  int result = 0;

  try {
    result = app.process();
  } catch (const std::exception &e) {
    result = 1;
    puts(e.what());
  }

  return result;
}

I get crashes if I throw and there's some more core after the if() in process().

This is an excerpt of how .eh_frame looks like when it works (90% code
in process() commented out):

00014c84 000000000000002c 00000000 CIE
  Version:               1
  Augmentation:          "zPLR"
  Code alignment factor: 1
  Data alignment factor: -8
  Return address column: 16
  Augmentation data:     9b 49 4f 3c 00 1b 1b
  DW_CFA_def_cfa: r7 (rsp) ofs 8
  DW_CFA_offset: r16 (rip) at cfa-8
  DW_CFA_def_cfa: r6 (rbp) ofs 16
  DW_CFA_offset: r3 (rbx) at cfa-56
  DW_CFA_offset: r6 (rbp) at cfa-16
  DW_CFA_offset: r12 (r12) at cfa-48
  DW_CFA_offset: r13 (r13) at cfa-40
  DW_CFA_offset: r14 (r14) at cfa-32
  DW_CFA_offset: r15 (r15) at cfa-24
  DW_CFA_nop
  DW_CFA_nop
  DW_CFA_nop

00014cb4 0000000000000014 00000034 FDE cie=00014c84
pc=000000000025081e..00000000002508d6
  Augmentation data:     d4 7e 20 00
  DW_CFA_nop
  DW_CFA_nop
  DW_CFA_nop

However, if I put just a bit more stuff inside process() after that
throwing if(), gcc changes the process function prologue a bit
and the unwind table looks like this:

0001ce38 0000000000000034 00013428 FDE cie=00009a14
pc=0000000000252534..0000000000256376
  Augmentation data:     ab 34 20 00
  DW_CFA_def_cfa_expression (DW_OP_breg6 (rbp): -40; DW_OP_deref)
  DW_CFA_expression: r3 (rbx) (DW_OP_breg6 (rbp): -48)
  DW_CFA_expression: r6 (rbp) (DW_OP_breg6 (rbp): 0)
  DW_CFA_expression: r12 (r12) (DW_OP_breg6 (rbp): -32)
  DW_CFA_expression: r13 (r13) (DW_OP_breg6 (rbp): -24)
  DW_CFA_expression: r14 (r14) (DW_OP_breg6 (rbp): -16)
  DW_CFA_expression: r15 (r15) (DW_OP_breg6 (rbp): -8)

So it basically references everything against rbp instead of against
the cfa, great. Here are the libunwind debug prints.
Notice how after processing the expression OP_breg(r6,0x0), thus
calculating the new value for r6 (rbp) by dereferencing itself with
offset zero, the change is reflected in the calculations for subsequent
registers r12-r15 which are wrong.
`apply_reg_state` in libunwind writes the new address for the value of
r6. However, the offsets for r12-r15 are supposed to be calculated
against the inner stack frame's value of rbp (0x7fffffffca70), not against
the new one (0x7fffffffcab0)!


     >_ULx86_64_reuse_frame: reuse frame ip=0x5555557a9d46
cfa=0x7fffffff6cc0 format=0 addr=0x0 offset=+0
              >_ULx86_64_dwarf_eval_expr: len=3, pushing cfa=0x7fffffff6cc0
               >_ULx86_64_dwarf_eval_expr: OP_breg(r6,0xffffffffffffffd8)
                >access_mem: mem[00007fffffff6c90] -> 7fffffffca70
               >_ULx86_64_dwarf_eval_expr: OP_deref
              >_ULx86_64_dwarf_eval_expr: final value = 0x7fffffffca90
              >_ULx86_64_dwarf_eval_expr: len=2, pushing cfa=0x7fffffff6cc0
               >_ULx86_64_dwarf_eval_expr: OP_breg(r6,0xffffffffffffffd0)
                >access_mem: mem[00007fffffff6c90] -> 7fffffffca70
              >_ULx86_64_dwarf_eval_expr: final value = 0x7fffffffca40
              >_ULx86_64_dwarf_eval_expr: len=2, pushing cfa=0x7fffffff6cc0
               >_ULx86_64_dwarf_eval_expr: OP_breg(r6,0x0)
                >access_mem: mem[00007fffffff6c90] -> 7fffffffca70
              >_ULx86_64_dwarf_eval_expr: final value = 0x7fffffffca70
              >_ULx86_64_dwarf_eval_expr: len=2, pushing cfa=0x7fffffff6cc0
               >_ULx86_64_dwarf_eval_expr: OP_breg(r6,0xffffffffffffffe0)
                >access_mem: mem[00007fffffffca70] -> 7fffffffcab0
              >_ULx86_64_dwarf_eval_expr: final value = 0x7fffffffca90
              >_ULx86_64_dwarf_eval_expr: len=2, pushing cfa=0x7fffffff6cc0
               >_ULx86_64_dwarf_eval_expr: OP_breg(r6,0xffffffffffffffe8)
                >access_mem: mem[00007fffffffca70] -> 7fffffffcab0
              >_ULx86_64_dwarf_eval_expr: final value = 0x7fffffffca98
              >_ULx86_64_dwarf_eval_expr: len=2, pushing cfa=0x7fffffff6cc0
               >_ULx86_64_dwarf_eval_expr: OP_breg(r6,0xfffffffffffffff0)
                >access_mem: mem[00007fffffffca70] -> 7fffffffcab0
              >_ULx86_64_dwarf_eval_expr: final value = 0x7fffffffcaa0
              >_ULx86_64_dwarf_eval_expr: len=2, pushing cfa=0x7fffffff6cc0
               >_ULx86_64_dwarf_eval_expr: OP_breg(r6,0xfffffffffffffff8)
                >access_mem: mem[00007fffffffca70] -> 7fffffffcab0
              >_ULx86_64_dwarf_eval_expr: final value = 0x7fffffffcaa8
                >access_mem: mem[00007fffffffca88] -> 5555558b67a9
               >_ULx86_64_dwarf_step: returning 1
  >_ULx86_64_step: returning 1
              >_ULx86_64_dwarf_find_proc_info: looking for IP=0x5555558b67a8
               >_ULx86_64_dwarf_callback: checking , base=0x555555554000)
               >_ULx86_64_dwarf_callback: found table `':
segbase=0x555557215230, len=57926, gp=0x5555576567e8,
table_data=0x55555721523c
               >lookup: e->start_ip_offset = fffffffffebc5730
...........
               >lookup: e->start_ip_offset = fffffffffe6a1410
               >_ULx86_64_dwarf_search_unwind_table:
ip=0x5555558b67a8, start_ip=0xfffffffffe6a1410
 >_ULx86_64_dwarf_search_unwind_table: e->fde_offset = 8e0b0, segbase
= 555557215230, debug_frame_base = 0, fde_addr = 5555572a32e0
            >_ULx86_64_dwarf_extract_proc_info_from_fde: FDE @ 0x5555572a32e0
               >_ULx86_64_dwarf_extract_proc_info_from_fde: looking
for CIE at address 55555728fe84
               >parse_cie: CIE parsed OK, augmentation = "zPLR",
handler=0x7fffeeaf3a80
               >_ULx86_64_dwarf_extract_proc_info_from_fde: FDE covers
IP 0x5555558b6640-0x5555558b6867, LSDA=0x5555574a67ec
     >_ULx86_64_fetch_frame: fetch frame ip=0x5555558b67a9
cfa=0x7fffffffca90 format=0
                >access_mem: mem[00007fffffffca88] <- 5555558b67e9
 >_ULx86_64_resume: (cursor=0x7fffffff6870)
        >establish_machine_state: copying out cursor state
                >establish_machine_state: copying RBP 6
                >access_mem: mem[00007fffffffca70] -> 7fffffffcab0
            >access_reg: RBP <- 0x00007fffffffcab0
                >establish_machine_state: copying RSP 7
            >access_reg: RSP <- 0x00007fffffffca90
                >establish_machine_state: copying R8 8
                >access_mem: mem[00007fffffff64c8] -> 555557ced700
...  All of these are wrong and cause a crash after landing in the
exception handler in main():
            >access_reg: R12 <- 0x73746e6f662f6269
                >establish_machine_state: copying R13 13
                >access_mem: mem[00007fffffffca98] -> 257c32600
            >access_reg: R13 <- 0x0000000257c32600
                >establish_machine_state: copying R14 14
                >access_mem: mem[00007fffffffcaa0] -> 555557c325d0
            >access_reg: R14 <- 0x0000555557c325d0
                >establish_machine_state: copying R15 15
                >access_mem: mem[00007fffffffcaa8] -> 17ebc2371241f
            >access_reg: R15 <- 0x00017ebc2371241f
                >establish_machine_state: copying RIP 16
                >access_mem: mem[00007fffffffca88] -> 5555558b67e9
            >access_reg: RIP <- 0x00005555558b67e9

Does anyone have any ideas? What could be causing this?
I'm tearing my hair out. Thanks a lot!



[Index of Archives]     [Linux C Programming]     [Linux Kernel]     [eCos]     [Fedora Development]     [Fedora Announce]     [Autoconf]     [The DWARVES Debugging Tools]     [Yosemite Campsites]     [Yosemite News]     [Linux GCC]

  Powered by Linux