Clang with libc++ exceptions
Asked Answered
M

2

8

I've been experimenting with different c++ libs, and found out the following: The simple application:

#include <iostream>

int main(int argc, char* argv[])
{
    try
    {
        throw 1;
    }
    catch(...)
    {
        std::cout << "Exception is caught\n";
    }
}

When I compile it on ARM like this:

clang++ -stdlib=stdlibc++

The exception is caught as expected.

But when I change it to:

clang++ -stdlib=libc++

I am constantly getting:

terminating with uncaught exception of type int
Aborted

I've tried to turn on exception explicitly with various flags like:

-fexceptions
-fcxx-exceptions
-frtti

But none of these flags work. What is the reason of the uncaught exception? Could it be because incorrectly installed libc++?

P.S. On the PC, the same program compiled with libc++ works as expected. libc++ version is the same on both platforms - 3.7.0-1ubuntu0.1

Methodism answered 3/8, 2018 at 13:5 Comment(3)
You should've gotten a linker or loader error of some flavor if it was due to a bad libc++ install. I'm betting libc++ only supports standard exceptions in a catch-all.Robbierobbin
so why does it work on PC ? Besides usual std::exception is not caught either.Methodism
Maybe clang generates exception managment code assuming it will be linked with the wrong unwind library!?!?? Try ldd on both generated executable. Usually it is linked with libgcc_s which provides the GCC version of the _Unwind_x symbols. Maybe also check nm a.out | grep _Unwind. There may appear information about the expected symbol version, for example "@@@GCC_3.0" on may x86. But I wonder how linking phase could have been successfull anyway.Jeffryjeffy
D
8

Yes I got exactly the same issue for PowerPC, ARM and even on the X86 Linux itself. The problem is (I traced it with PowerPC): The the throw is doing a __cxa_throw, which is calling _Unwind_RaiseException in the libunwind part of the libc++. This _Unwind_RaiseException itself is calling unw_getcontext to get all registers at this point. Now it tries to find the calling functions backwards via the ".eh_frame" in the ELF file. But as the UnwindLevel1.c is a C file, there are no .cfi_start ... information in the assembly part which are creating the .eh_frame information. Means, that the stack-traceback is directly ending on the first function (_Unwind_RaiseException) and not going further back to identfy the calling "catch" part. This can by corrected by compiling the .c parts in the libc++ with the C++ compiler (clang++ instead of clang). For this case the .cfi_start information are also generated for for the functions. Now the Stack-Trace-Back can find the first functions and also previous functions up to main (in my test case). For ARM, I'm hunting for the next problem right now, as the Stack-Trace-Back is not working. It scans the same function again and again, but not going backward (endless loop).

When compiling the .c files with clang++, you will run into an issue with not defined parts in stdlib.h, because it uses the wrong stdlib.h from libcxx/include and not from the MUSL includes. I don't have a good solution right now, except for modifying some header files by hand.

Kei

Domingadomingo answered 7/8, 2018 at 11:37 Comment(3)
All of this sounds like a bug that should be reported to the libc++ maintainers.Humming
My fault for ARM with the endless loop was, that no "unwind information" were added to the code. This happened, because my target was not detected as EABI and therefore the compiler didn't create the .save .setfp .pad instructions into the assembly code.Domingadomingo
@Domingadomingo Could you please provide the installation instructions how you built your lib ?Methodism
G
1

This is because of a bug in the compilation of libunwind. It has been fixed now: https://reviews.llvm.org/D71117

Exceptions were broken for ARM when using libc++ and libunwind. From what I can tell, it was fixed in LLVM-10.0.0.

Goody answered 27/8, 2020 at 12:48 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.