Subject: Atexit and DLLs
From: [email-masked] (Colin Peters)

24 Feb 1998 14:59:15 -0800
Message-ID: <[email-masked]>
Mime-Version: 1.0
Content-Type: text/plain;
	charset="iso-8859-1"
Content-Transfer-Encoding: 7bit
To: "GNU-Win32" <[email-masked]>

(Thanks to Andrey A. Smirnov for pointing this out)

I have discovered a fascinating problem with loading and freeing dlls in
Mingw32. This is probably not a problem in Cygwin32 because Cygwin32 doesn't
call the __do_global_ctors function to initialize global objects inside the
DLL. Basically the problem is this:

You can load a DLL using LoadLibrary and call functions through pointers
obtained with GetProcAddress, however if you unload the DLL with FreeLibrary
your program will crash when it exits.

What's happening is related to atexit. Inside __do_global_ctors (part of the
libgcc library) all the global objects in the DLL are initialized (my entry
code for DLLs calls this so that you can have global objects inside a DLL).
It also calls atexit to register the __do_global_dtors function to destroy
all global objects should the program exit (prematurely or otherwise). Very
smart, but...

My entry code also calls __do_global_dtors when the DLL is unloaded, so that
is not a problem: all the global objects inside the DLL are nicely
destroyed. If the program exits normally __do_global_dtors gets called
twice, but it's smart enough to deal with that. However, if you unload the
DLL using FreeLibrary then the function pointer added to the atexit list
(the __do_global_dtors in the DLL) is no longer valid. The call to it inside
the DLL entry code goes fine and destroys the objects, but the call that
occurs because it was added to the atexit list results in a GPF.

Even if __do_global_ctors didn't call atexit(__do_global_dtors) there would
still be a problem with any DLL which called atexit and registered a
function in the DLL. Any program which tried to load the DLL and free it
later would crash on exit.

Andrey proposed (and supplied code for) a version of atexit to be statically
linked in the DLL itself (overriding the crtdll version). Although I don't
like adding more code to the startup, it does seem to be the only reasonable
way to make this work.

Does anyone have anything to add? For example, does MS mention using atexit
in DLLs in their documentation? Does registering a function with atexit in a
dynamically loaded DLL do the right thing in MSVC? Is handling it this way
in fact the right thing (i.e. perhaps atexit should be off limits for use in
DLLs)? If MSVC does something automagical then perhaps there is a capability
built into their library which we could exploit if we could figure out how
to use it.

Awaiting opinions,
Colin.

-- Colin Peters - colin at fu.is.saga-u.ac.jp
-- Saga Univ. Dept. of Information Science
-- http://www.geocities.com/Tokyo/Towers/6162/index.html
-- http://www.fu.is.saga-u.ac.jp/~colin/index.html

-
For help on using this list (especially unsubscribing), send a message to
"[email-masked]" with one line of text: "help".