This is the mail archive of the gcc-bugs@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[Bug target/42159] unwinding issues on darwin


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

Niklas Hauser <niklas.hauser at arm dot com> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
                 CC|                            |niklas.hauser at arm dot com

--- Comment #35 from Niklas Hauser <niklas.hauser at arm dot com> ---
We can reproduce this issue on OS X 10.12, please see below for a detailed
analysis of the underlying problem.
This issue is fixed by the patch proposed by Pierre Ossman. Did this patch (or
maybe a similar solution) make it upstream already?


Summary of cause:

The libgcc unwinder implementation is broken for all 64-bit builds of OS X
(since 10.6) due to a non-backwards compatible change in the _keymgr API, which
does not provide a process-wide image list anymore.


Details of cause:

This is the minimal example to reproduce the issue on OS X (>10.6):

  #include <iostream>
  int main() {
      try {
          throw 20;
      }
      catch (int e) {
          std::cout << "Exception No. " << e << "\n";
      }
      return 0;
  }

Running this application will cause a SIGABRT:

  g++ -static-libgcc -o failboat main.cpp  && ./failboat
  [1]    4047 abort      ./failboat

Stack trace of this failure is:

  ...
  #12 0x00007fff5fbff370 in ?? ()
  #13 0x00000001000987c1 in uw_init_context_1 ()
  #14 0x0000000100098e1e in _Unwind_RaiseException ()
  #15 0x000000010000d81b in __cxa_throw ()
  #16 0x0000000100000b30 in main () at main.cpp:4

We're failing an assert in uw_init_context_1 (gcc/libgcc/unwind-dw2.c:1578):

  code = uw_frame_state_for (context, &fs);
  gcc_assert (code == _URC_NO_REASON);

Specifically uw_frame_state_for returns code _URC_END_OF_STACK and this then
fails the gcc_assert, which then  unwraps in a SIGABRT. uw_frame_state_for()
calls _Unwind_Find_FDE() in gcc/libgcc/unwind-dw2.c:1249, which returns NULL
however and the entire function therefore returns _URC_END_OF_STACK:

  fde = _Unwind_Find_FDE (context->ra + _Unwind_IsSignalFrame (context) - 1,
&context->bases);
  if (fde == NULL)
    {
      return _URC_END_OF_STACK;
    }

_Unwind_Find_FDE() is defined in gcc/libgcc/unwind-dw2-fde.c:1027, EXCEPT on OS
X (aka. Darwin), where it is reimplemented in
gcc/libgcc/config/unwind-dw2-fde-darwin.c:244!

This implementation uses the _keymgr API to access Dwarf2 object lists and ELF
images (with the KEYMGR_GCC3_DW2_OBJ_LIST and KEYMGR_GCC3_LIVE_IMAGE_LIST keys,
respectively).
The function first checks the Dwarf2 object lists, then falls back to using the
original implementation (which has been renamed to
_Unwind_Find_registered_FDE()) before searching the ELF images in
examine_objects:

  the_obj_info =
    _keymgr_get_and_lock_processwide_ptr (KEYMGR_GCC3_DW2_OBJ_LIST);
  if (! the_obj_info)
    the_obj_info = calloc (1, sizeof (*the_obj_info));

  if (the_obj_info != NULL)
    {
      /* code removed for brevity */
      ret = _Unwind_Find_registered_FDE (pc, bases);
    }

  /* OK, didn't find it in the list of FDEs we've seen before,
     so go through and look at the new ones.  */
  if (ret == NULL)
    ret = examine_objects (pc, bases, the_obj_info == NULL);

Here the first call to KEYMGR_GCC3_DW2_OBJ_LIST returns NULL, thus an empty
object list is allocated. _Unwind_Find_registered_FDE() returns NULL too, since
it operates only on previously seen objects, of which there are none yet.
Finally, examine_objects is finally called, which contains:

  image = _keymgr_get_and_lock_processwide_ptr (KEYMGR_GCC3_LIVE_IMAGE_LIST);

Note how the KEYMGR_GCC3_DW2_OBJ_LIST list is used as a "cache" of previously
seen Dwarf2 objects and is first populated by examine_objects() using the
KEYMGR_GCC3_LIVE_IMAGE_LIST.

However, on 64-bit builds of OS X, KEYMGR_GCC3_LIVE_IMAGE_LIST always returns
NULL and so the image information can never be retrieved. The reason for this
is found in the implementation of keymgr.c, which is published here:
https://opensource.apple.com/source/keymgr/keymgr-28/keymgr.c.auto.html.

At the very bottom, in __keymgr_initializer() it says:

  #if __x86_64__
    /* On Mac OS X 10.6, libunwind in libSystem.dylib implements all unwinding
functionality. */
    /* libunwind does not use keymgr, so there is no need to maintain
KEYMGR_GCC3_LIVE_IMAGE_LIST */
    /* in sync with dyld's list of images.  But there might be some i386 or ppc
applications that */
    /* carry around there own copy of the unwinder (from libgcc.a) and need
KEYMGR_GCC3_LIVE_IMAGE_LIST. */
  #else
    /* register with dyld so that we are notified about all loaded mach-o
images */
    _dyld_register_func_for_add_image (dwarf2_unwind_dyld_add_image_hook);
    _dyld_register_func_for_remove_image
(dwarf2_unwind_dyld_remove_image_hook);
  #endif /* __x86_64__ */

On 64-bit builds of OS X these images are simply never added. The libgcc
unwinder code can therefore never work, since it relies on this information.

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]