Skip to content

nounwind declaration of _Unwind_Resume generates bad gcc_except_table #56825

@smeenai

Description

@smeenai

See https://godbolt.org/z/19c3ohsKs. The generated gcc_except_table is missing the call site table entry for the end of the function:

GCC_except_table0:
.Lexception0:
        .byte   255                             // @LPStart Encoding = omit
        .byte   255                             // @TType Encoding = omit
        .byte   1                               // Call site Encoding = uleb128
        .uleb128 .Lcst_end0-.Lcst_begin0
.Lcst_begin0:
        .uleb128 .Ltmp0-.Lfunc_begin0           // >> Call Site 1 <<
        .uleb128 .Ltmp1-.Ltmp0                  //   Call between .Ltmp0 and .Ltmp1
        .uleb128 .Ltmp2-.Lfunc_begin0           //     jumps to .Ltmp2
        .byte   0                               //   On action: cleanup
.Lcst_end0:

As a result, any exception thrown through this function will end up terminating, because we'll enter the cleanup, resume unwinding, and then the personality function will be unable to find any call site table entry corresponding to the cleanup PC.

Removing the nounwind attribute from the declaration of either _ZN14has_destructorD1Ev or _Unwind_Resume produces a correct gcc_except_table:

GCC_except_table0:
.Lexception0:
        .byte   255                             // @LPStart Encoding = omit
        .byte   255                             // @TType Encoding = omit
        .byte   1                               // Call site Encoding = uleb128
        .uleb128 .Lcst_end0-.Lcst_begin0
.Lcst_begin0:
        .uleb128 .Ltmp0-.Lfunc_begin0           // >> Call Site 1 <<
        .uleb128 .Ltmp1-.Ltmp0                  //   Call between .Ltmp0 and .Ltmp1
        .uleb128 .Ltmp2-.Lfunc_begin0           //     jumps to .Ltmp2
        .byte   0                               //   On action: cleanup
        .uleb128 .Ltmp1-.Lfunc_begin0           // >> Call Site 2 <<
        .uleb128 .Lfunc_end0-.Ltmp1             //   Call between .Ltmp1 and .Lfunc_end0
        .byte   0                               //     has no landing pad
        .byte   0                               //   On action: cleanup
.Lcst_end0:

This repros with any target using DWARF unwinding, not just Android AArch64.

I discovered this when building a combined libc++, libc++abi, and libunwind library with LTO, with libunwind providing the actual _Unwind_Resume definition; it resulted in various libc++ functions having bad gcc_except_tables, leading to exception handling issues. That's probably an unusual setup, but I'd still expect it to work.

Metadata

Metadata

Assignees

No one assigned

    Labels

    cmakeBuild system in general and CMake in particularlibunwind

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions