https://gcc.gnu.org/bugzilla/show_bug.cgi?id=91737

            Bug ID: 91737
           Summary: On Alpine Linux (libmusl) a statically linked C++
                    program which throws the first exception in two
                    threads at the same time can busy spin on shutdown
                    after main().
           Product: gcc
           Version: 8.3.0
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: libgcc
          Assignee: unassigned at gcc dot gnu.org
          Reporter: max at arangodb dot com
  Target Milestone: ---

Created attachment 46870
  --> https://gcc.gnu.org/bugzilla/attachment.cgi?id=46870&action=edit
Program exposing the problem when compiled under Alpine Linux and linked
statically.

My statically linked program runs a busy loop after main() has terminated,
provided that the very first exception that is thrown in the run is thrown in
two threads at the very same time. The attached program shows the problem.

This only happens on Linux, and only if one does not use glibc as C-library,
and only if the executable is statically linked and does not explicitly use the
`pthread_cancel` function.

I tested with g++ 8.3.0, but I think the problem is present in other versions
as well.

Here is what is happening: In the file `libgcc/unwind-dw2-fde.c` in the
function `_Unwind_Find_FDE` there is a mutex which is only acquired if the
underlying program is detected to be "multi-threaded". This test for
multi-threadedness is done differently on various platforms (see file
`libgcc/gthr-posix.h` lines 156 to 306). On Linux without glibc and if it is
not the Android bionic C library, a weak reference to the symbol
`pthread_cancel` is used. If the underlying program does not explicitly use
`pthread_cancel` (and few C++ programs will, because cancelling threads is not
in the C++ standard), and the linking is done statically, the program will link
`libpthread` but not have a symbol `pthread_cancel`. In this case the mutex is
not used at all.

If now the first exception in the program happens in two exceptions
concurrently, the function `_Unwind_Find_FDE` will move an object from the
static list `unseen_objects` to the static list `seen_objects` and a data race
occurs. Sometimes, the same object is moved twice from one list to the other.
This leads to the fact that the `seen_objects` list ends in an object which
points to itself (with the `next` pointer).

In this case, on shutdown, well after main() and all static destructors, the
function `__deregister_frame_info_bases` will busy loop running around the
circular data structure `seen_objects`.

I think this is overoptimized and the multi-threadedness detection does not
work for many statically linked programs when libmusl is used as underlying
C-library.

Reply via email to