Project

General

Profile

Actions

Bug #13824

closed

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

Added by Hans Rosenfeld over 1 year ago. Updated 13 days ago.

Status:
Resolved
Priority:
High
Assignee:
Category:
OI-Userland
Target version:
Start date:
Due date:
% Done:

0%

Estimated time:
Difficulty:
Medium
Tags:

Description

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>

int
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 about 1 year 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)

Actions #2

Updated by Hans Rosenfeld 14 days ago

I've dug around some more in this issue and checked the libraries being linked and the symbols being bound using "elfdump -y".

I found that libexiv2 is linked explicitly against libc before libgcc_s, and _Unwind_Resume is bound to libc. The removing -lc before -lgcc_s on the link command results in a libexiv2 that correctly binds _Unwind_Resume to libgcc_s. So this is a bug in exiv2, not in illumos.

For reference, the reason exiv2 links against libc is this: exiv2 is uses cmake for building, and it ships its own private copy of FindIconv.cmake to work around an issue with Visual Studio. This old version of FindIconv.cmake correctly finds iconv() in libc and unnecessarily adds it to the list of libraries to be linked. Cmake fixed this a while ago (https://gitlab.kitware.com/cmake/cmake/-/merge_requests/6046), so removing the private FindIconv.cmake from exiv2 before building fixes this issue, provided a recent enough cmake is used for building.

Actions #3

Updated by Andreas Wacknitz 13 days ago

Finally, with the good analysis done be Hans I have been able to create a fix for this problem.
WIth the integration of https://github.com/OpenIndiana/oi-userland/pull/10651 this has been fixed.

Actions #4

Updated by Andreas Wacknitz 13 days ago

  • Status changed from New to Resolved
Actions

Also available in: Atom PDF