Bug 57982 - GetModuleHandle in __register_frame_info causes abort on unload
Summary: GetModuleHandle in __register_frame_info causes abort on unload
Alias: None
Product: gcc
Classification: Unclassified
Component: target (show other bugs)
Version: 4.7.3
: P3 normal
Target Milestone: ---
Assignee: Not yet assigned to anyone
Depends on:
Reported: 2013-07-25 09:07 UTC by Daniel Colascione
Modified: 2015-02-27 09:57 UTC (History)
1 user (show)

See Also:
Target: i686-*-mingw32 i686-*-cygwin
Known to work:
Known to fail:
Last reconfirmed:


Note You need to log in before you can comment on or make changes to this bug.
Description Daniel Colascione 2013-07-25 09:07:32 UTC
Say we have modules Foo and Bar. Foo links against shared libgcc, but Bar does not. Now, if we load Foo, load Bar, unload Foo, then unload Bar, then Bar's initialization code finds libgcc and registers itself with it, but Bar's deinitializaton code doesn't find libgcc, tries to instead unregister with Foo's internal data structures, finds them uninitialized, and aborts.

The right fix for libgcc looks something like this:

--- config/i386/cygming-crtbegin.c.orig 2013-07-25 00:07:35.000000000 -0800
+++ config/i386/cygming-crtbegin.c      2013-07-25 00:33:11.000000000 -0800
@@ -82,6 +82,8 @@
 extern void __gcc_register_frame (void);
 extern void __gcc_deregister_frame (void);

+static HANDLE libgcc_dll;
 __gcc_register_frame (void)
@@ -94,8 +96,11 @@
   void (*register_frame_fn) (const void *, struct object *);
   HANDLE h = GetModuleHandle (LIBGCC_SONAME);
   if (h)
-    register_frame_fn = (void (*) (const void *, struct object *))
-                       GetProcAddress (h, "__register_frame_info");
+    {
+      libgcc_dll = LoadLibrary (LIBGCC_SONAME); /* Hold reference */
+      register_frame_fn = (void (*) (const void *, struct object *))
+       GetProcAddress (h, "__register_frame_info");
+    }
     register_frame_fn = __register_frame_info;
   if (register_frame_fn)
@@ -124,13 +129,16 @@
   void *  (*deregister_frame_fn) (const void *);
-  HANDLE h = GetModuleHandle (LIBGCC_SONAME);
-  if (h)
+  if (libgcc_dll)
     deregister_frame_fn = (void* (*) (const void *))
-                         GetProcAddress (libgcc_dl, "__deregister_frame_info");
+      GetProcAddress (libgcc_dll, "__deregister_frame_info");
     deregister_frame_fn = __deregister_frame_info;
   if (deregister_frame_fn)
      deregister_frame_fn (__EH_FRAME_BEGIN__);
+  if (libgcc_dll)
+    FreeLibrary (libgcc_dll);

The problem is that this code is baked into every module compiled with the buggy
libgcc. You have to recompile the world to fix it for good.
Comment 1 Kai Tietz 2013-11-10 12:23:23 UTC
Ups, this bug didn't shown up in my search-list ...
Issue fixed for 4.7, 4.8, and trunk at rev 204635-204637.
Comment 2 Jean-Pierre Flori 2015-02-26 10:19:26 UTC
(In reply to Kai Tietz from comment #1)
> Ups, this bug didn't shown up in my search-list ...
> Issue fixed for 4.7, 4.8, and trunk at rev 204635-204637.

I recently stumbled on a similar problem again with a recent Cygwin/GCC combination.
Looking at the fix included in GCC, it does look slightly different from what was first suggested here.

Could someone more knowledgeable than me have a look and tell whether the included fix is fine or incomplete?
If incomplete, I'll be happy to open a new bug report.

See here for my report on cygwin's mailing-list:
Comment 3 Kai Tietz 2015-02-27 09:57:02 UTC
The problem here is the use of weak on pe-coff.  The change you see on gcc is just addressing the fact that for 64-bit the weak symbol never can get 0 due relocation-limitations.
We try to address this.
On the other hand we have here to work-a-round a binutils quirk that default-implementation of a weak is used in its definition TU always, even if a none-weak symbol is present in a different TU.  This can be worked-a-round by moving default-implementation into different TU.

Hope this answered some of your questions.

(anyway IMHO, in general we should have used here a variant without any weak-symbol)