Bug #13824


exiv2 / C++ exception handling broken on 64bit systems

Added by Hans Rosenfeld 8 months ago. Updated 5 days ago.

Target version:
Start date:
Due date:
% Done:


Estimated time:


I'm seeing a problem with programs using libexiv2 like geeqie and darktable:

Any C++ exception thrown in libexiv2 either causes some sort of segfault or a tight loop that allocates more and more memory until a ulimit is hit or the system locks up. Exceptions are thrown by libexiv2 all the time, for all kinds of fatal and non-fatal errors, making any program using libexiv2 unusable.

The system runs OI Hipster from just before 2021.04, I'm using g++ 7.5.0-il-0 and exiv2 0.27.3. The problem seems to be limited to exiv2 as I don't see this with other C++ libraries, and also exiv2 0.26 seems to work fine. I wouldn't rule out a problem or incompatibility with our exception handling, though, as the code in exiv2 looks fine (at least as far as I can tell with my limited knowledge of C++).

The following simple program illustrates the problem, inspired by whats causing this issue in darktable. The exif key "Exif.Image.DefaultBlackRender" is unknown to exiv2, so it throws an exception:

#include <exiv2/exiv2.hpp>
#include <iostream>

main(int argc, char* const argv[]) try {
        Exiv2::ExifKey key = Exiv2::ExifKey("Exif.Image.DefaultBlackRender");

        return 0;

catch (Exiv2::Error& e) {
        std::cout << "Caught Exiv2 exception '" << e.what() << "'\n";
        return -1;

When compiled for 32bit, it works as intended:

$ g++ -o exiv exiv.cpp -Wl,-rpath /usr/lib -lexiv2
$ ./exiv
Caught Exiv2 exception 'Invalid tag name or ifdId `DefaultBlackRender', ifdId 1'

When compiled for 64bit, it just runs into an endless loop consuming memory until hits the ulimit:

$ g++ -m64 -o exiv exiv.cpp -Wl,-rpath /usr/lib/amd64 -lexiv2
$ ulimit -d 1048576
$ ./exiv
terminate called without an active exception
Abort (core dumped)

I also tried compiling exiv2 from pkgsrc and using that, and it fails in a different way:

$ g++ -m64 -o exiv exiv.cpp -Wl,-rpath /usr/pkg/lib -lexiv2
$ ./exiv
Memory fault(coredump)
$ pstack core
core 'core' of 3328:    ./exiv
 00005fffaf900723 parse_lsda_header(_Unwind_Context*, unsigned char const*, lsda_header_info*) () + 23
 00005fffaf900925 __gxx_personality_v0 () + 135
 00005fffaf75bf09 _Unwind_RaiseException_Body (42a2f0, 7fffbfffeb80, 2) + 1b6
 00005fffaf75c2ec _SUNW_Unwind_Resume (42a2f0) + 9a
 00005fffafcbbf92 Exiv2::ExifKey::Impl::decomposeKey(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&) () + 2f2
 00005fffafcbc1fb Exiv2::ExifKey::ExifKey(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&) () + 5b
 0000000000401c01 main () + 46
 0000000000401ac7 _start_crt () + 87
 0000000000401a28 _start () + 18

Actions #1

Updated by Rich Lowe 5 days ago

This latter case looks like it's definitely calling into the unwinder in libc, rather than libstdc++. This is usually a recipe for disaster (though it doesn't necessarily have to be).

g++ should linking using a mapfile that forces it to bind to libstdc++ for the unwinder symbols, is it not?
I would say from this the problem is almost definitely getting the mix of libc and libstdc++ unwinders, and their private data not agreeing as we've seen before. The reason it's not happening on 32bit applications is that there is no unwinder in 32bit libc.

I can't really figure out what you can do next, except compare the link-edit of libexiv2 with something else which you have which works. (pass -'###' to the compiler front end, and it'll tell you how it calls collect2, which for our purposes is ld)


Also available in: Atom PDF