abort during exit() with a dynamically loaded C++ library

Jon TURNEY jon.turney@dronecode.org.uk
Mon Jul 7 13:58:00 GMT 2014


On 17/06/2014 19:11, Jon TURNEY wrote:
> I think I have found a problem when building programs using the latest
> mesa library, where abort is being called during exit()
>
> This seems to be x86 specific, and looks like it is somehow related to
> having a C++ library dynamically loaded by a C program.
>
> I think I have reduced it to the following test case:

So, this seems to be related to this patch [1], to fix a different abort 
during __gcc_deregister_frame()

[1] https://sourceware.org/ml/cygwin/2013-07/msg00528.html

Since this code is baked into libgcc itself, that patch has the 
side-effect of making libgcc pin itself in memory.

I can't really tell from what's written there if that was deliberate or 
not, but it seems that it introduces a different problem when the 
executable doesn't have a dependency on libgcc.

> test.c:
>
> #include <assert.h>
> #include <dlfcn.h>
>
> int main()
> {
>     void *h = dlopen("dllib.dll", 0);
>     assert(h);
>     dlclose(h);

The problem can be worked around by adding code to force libgcc to get 
unloaded here, which seems to support this theory, e.g.

+#define LIBGCC_SONAME "cyggcc_s-1.dll"
+   HANDLE hmod_libgcc = GetModuleHandle(LIBGCC_SONAME);
+   FreeLibrary(hmod_libgcc);

> }

Attached is a patch which modifies __gcc_register_frame() to avoid it 
pinning itself in memory.

Alternatively, as one of the emails in the linked thread says [2], the 
assert in __deregister_frame_info_bases() itself could be removed.

[2] http://www.mail-archive.com/gcc@gcc.gnu.org/msg68286.html

-------------- next part --------------
--- cygming-crtbegin.c.bak	2014-07-03 16:41:43.116600000 +0100
+++ cygming-crtbegin.c	2014-07-03 18:39:07.436800000 +0100
@@ -99,8 +99,21 @@
 
   if (h)
     {
-      /* Increasing the load-count of LIBGCC_SONAME DLL.  */
-      hmod_libgcc = LoadLibrary (LIBGCC_SONAME);
+      /*
+         Increase the load-count of the LIBGCC_SONAME DLL by one, so that it remains
+         loaded as long as this module is, so that __gcc_deregister_frame() will call
+         __deregister_frame_info() in that DLL, to match the register_frame_info()
+         we do now.
+
+         Unless this *is* LIBGCC_SONAME DLL, where increasing our own load-count would
+         make us self-pinning.
+      */
+      HMODULE hmod_this = 0;
+      GetModuleHandleEx (GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT,
+	 (LPCTSTR)__gcc_register_frame, &hmod_this);
+      if (hmod_this != h)
+          hmod_libgcc = LoadLibrary (LIBGCC_SONAME);
+
       register_frame_fn = (void (*) (const void *, struct object *))
 			  GetProcAddress (h, "__register_frame_info");
     }
-------------- next part --------------
--
Problem reports:       http://cygwin.com/problems.html
FAQ:                   http://cygwin.com/faq/
Documentation:         http://cygwin.com/docs.html
Unsubscribe info:      http://cygwin.com/ml/#unsubscribe-simple


More information about the Cygwin mailing list