2

Any idea why code that looks like this

list<Foo> fooList;
processList(&fooList);

Generates the following machine code

    lea     rax, [rbp-48]
    mov     rdi, rax
    call    processList(std::__cxx11::list<Foo, std::allocator<Foo> >*)
    lea     rax, [rbp-48]
    mov     rdi, rax
    call    std::__cxx11::list<Foo, std::allocator<Foo> >::~list()
    jmp     .L11
    mov     rbx, rax
    lea     rax, [rbp-48]
    mov     rdi, rax
    call    std::__cxx11::list<Foo, std::allocator<Foo> >::~list()
    mov     rax, rbx
    mov     rdi, rax
    call    _Unwind_Resume
.L11:
    add     rsp, 40
    pop     rbx
    pop     rbp
    ret

In particular, I don't see any paths leading to the line after the unconditional jmp .L11

(this is with GCC 6.2 with no optimization, generated on compiler explorer)

For comparison, clang 5.0.0 produces

    call    processList(std::__cxx11::list<Foo, std::allocator<Foo> >*)
    jmp     .LBB5_1
.LBB5_1:
    lea     rdi, [rbp - 24]
    call    std::__cxx11::list<Foo, std::allocator<Foo> >::~list()
    add     rsp, 48
    pop     rbp
    ret
    lea     rdi, [rbp - 24]
    mov     ecx, edx
    mov     qword ptr [rbp - 32], rax
    mov     dword ptr [rbp - 36], ecx
    call    std::__cxx11::list<Foo, std::allocator<Foo> >::~list()
    mov     rdi, qword ptr [rbp - 32]
    call    _Unwind_Resume

Again there is an unconditional jump to a return block, and and unwind block (starting with the second lea rdi) that seems unreachable.

9
  • 1
    Have you tried compiling wih optimization enabled?
    – fuz
    Commented Jan 14, 2018 at 11:33
  • 1
    Exception handlers shouldn't be normally reachable, that's the point
    – user555045
    Commented Jan 14, 2018 at 12:57
  • 2
    Ok let me reword it: exception handlers are unreachable through normal control flow. You're only looking at normal control flow, so they are unreachable.
    – user555045
    Commented Jan 14, 2018 at 13:03
  • 6
    Through the unwinding process, so look at the .eh_frame and such
    – user555045
    Commented Jan 14, 2018 at 13:06
  • 3
    @PaulFloyd If you compile without optimizations, it is not unusal to see dead (unreachable) code in the binary. After all, you forbade the compile to remove such code by turning off the optimizer.
    – fuz
    Commented Jan 14, 2018 at 13:19

1 Answer 1

4

After a bit of research on C++ exception mechanisms, my conclusion is that the process is as follows:

  1. At the point of exception throw, __cxa_throw gets called. This is somewhat like longjmp() in that the function gets called but never returns. The function performs two main tasks
    • It walks up the call stack looking for a catch. If it doesn't find any, std::terminate gets called.
    • If it does find a catch block then it calls all of the unwind handlers between the current function and the catch block, then calls the catch block.

Back to my original machine code (with filtering turned off in compiler explorer). My comments after the hashes.

    # this is the normative path
    call    std::list<Handle, std::allocator<Handle> >::~list()
    # unconditional jump around the unwind handler
    jmp     .L11
.L10:
    # unwind handler code, calls the local variable destructor
    mov     rbx, rax
    .loc 2 30 0
    lea     rax, [rbp-32]
    mov     rdi, rax
    call    std::list<Handle, std::allocator<Foo> >::~list()
    mov     rax, rbx
    mov     rdi, rax
.LEHB1:
    # carry on unwinding
    call    _Unwind_Resume

.L11:

Then there is the exception table

   .section        .gcc_except_table,"a",@progbits
.LLSDA1386:
    .byte   0xff
    .byte   0xff
    .byte   0x1
    .uleb128 .LLSDACSE1386-.LLSDACSB1386
.LLSDACSB1386:
    # entry for unwind handler
    .uleb128 .LEHB0-.LFB1386
    .uleb128 .LEHE0-.LEHB0
    .uleb128 .L10-.LFB1386
    .uleb128 0
    .uleb128 .LEHB1-.LFB1386
    .uleb128 .LEHE1-.LEHB1
    .uleb128 0
    .uleb128 0

I guess that the unwind handler function can work out the positions of the unwind handler blocks from the addresses on the stack and the offsets in this table.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.