This is the mail archive of the cygwin@cygwin.com mailing list for the Cygwin 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 report - DLL failure on win ME with gcc-3


Hi
I have come across a problem with dlopened dlls and fork() on Windows
ME, that is not related to the rebase issue. The problem does not occur
on win 2k. Dlls linked using gcc-3 and loaded with dlopen() will cause
the program to fail if it fork()s. In my testing, this is true of every
dll I have tried.

A simple test dll C source, dllmain.c:

#include <windows.h>
#include <stdio.h>

BOOL WINAPI DllMain(
  HINSTANCE hinstDLL,
  DWORD fdwReason,
  LPVOID lpvReserved
) 
{
	char *reason;
	switch (fdwReason) {
		case DLL_PROCESS_ATTACH:
			reason = "DLL_PROCESS_ATTACH";
			break;
		case DLL_THREAD_ATTACH:
			reason = "DLL_THREAD_ATTACH";
			break;
		case DLL_THREAD_DETACH:
			reason = "DLL_THREAD_DETACH";
			break;
		case DLL_PROCESS_DETACH:
			reason = "DLL_PROCESS_DETACH";
			break;
		default:
			reason = "UNKNOWN";
			break;
	}
	fprintf(stderr, "DLLMain pid %d, handle %p, %s\n", getpid(), hinstDLL,
reason);
	return TRUE;
}


compile with:
gcc -g -c dllmain.c

link dll with:
gcc -o mytest.dll -shared -Wl,--export-all dllmain.o


A simple test C program, mytest.c:


#include <dlfcn.h>
#include <stdio.h>

void usage()
{
	fprintf(stderr, "Usage: dlltest dll\n");
}

int main(int argc, char *argv[])
{
	void *module;
	char *errstr;
	
	if (argc < 2)
	{
		usage();
		return 1;	
	}
	
	module = dlopen(argv[1], RTLD_NOW);
	if (module == NULL)
	{
		errstr = dlerror();
		if (errstr != NULL)
		{
			fprintf(stderr, "dlopen %s gave error %s\n", argv[1],
dlerror());
		}
		else
		{
			fprintf(stderr, "dlopen %s failed - no error\n", argv[1]);
		}
		return 2;
	}
	
	fprintf(stderr, "successfully opened %s\n", argv[1]);
	
	switch (fork()) {
		case -1:
			fprintf(stderr, "fork failed\n");
			break;
		case 0:
			fprintf(stderr, "hello from child\n");
			break;
		default:
			fprintf(stderr, "hello from parent\n");
			break;	
	}
	
	dlclose(module);
	return 0;
}

compile with:
gcc -g -o mytest mytest.c

Now run the test as:
./mytest mytest.dll

On win 2k you see the expected output:

DLLMain pid 1008, handle 0x640000, DLL_PROCESS_ATTACH
successfully opened mytest.dll
DLLMain pid 1008, handle 0x640000, DLL_THREAD_ATTACH
hello from parent
DLLMain pid 1008, handle 0x640000, DLL_PROCESS_DETACH
DLLMain pid 940, handle 0x640000, DLL_THREAD_ATTACH
hello from child
DLLMain pid 940, handle 0x640000, DLL_PROCESS_DETACH

But on win Me you see:

DLLMain pid 635949, handle 0x18b90000, DLL_PROCESS_ATTACH
successfully opened mytest.dll
DLLMain pid 635949, handle 0x18b90000, DLL_THREAD_ATTACH
DLLMain pid 549313, handle 0x18b90000, DLL_PROCESS_DETACH

And then I get a windows pop-up saying:
Mytest has caused an error in MYTEST.DLL.
Mytest will now close.
If you continue to experience problems,
try restarting your computer.

ON clicking "close" in that pop-up, the program output then continues:

hello from parent
DLLMain pid 635949, handle 0x18b90000, DLL_PROCESS_DETACH
DLLMain pid 549313, handle 0x18b90000, DLL_THREAD_ATTACH
hello from child
DLLMain pid 549313, handle 0x18b90000, DLL_PROCESS_DETACH

Note here that on win me, there is a DLL_PROCESS_DETACH (the first one)
which is associated with the child pid, whereas on win 2k this message
does not appear; and that it is immediately after this message that the
program breaks. This possibly suggests that there is an extra dll-unload
taking place on win me that results in calling some destructor on a
non-existant object?

If we now link a new dll from the same dllmain.o object file, but using
gcc-2, as:
gcc-2 -o mytest2.dll -shared -Wl,--export-all dllmain.o

and then run on win me:
./mytest mytest2.dll

we get the output:
DLLMain pid 3183405, handle 0x18b90000, DLL_PROCESS_ATTACH
successfully opened mytest2.dll
DLLMain pid 3183405, handle 0x18b90000, DLL_THREAD_ATTACH
DLLMain pid 550537, handle 0x18b90000, DLL_PROCESS_DETACH
hello from parent
DLLMain pid 3183405, handle 0x18b90000, DLL_PROCESS_DETACH
DLLMain pid 550537, handle 0x18b90000, DLL_THREAD_ATTACH
hello from child
DLLMain pid 550537, handle 0x18b90000, DLL_PROCESS_DETACH

Note that here the extra DLL_PROCESS_DETACH message still appears, but
this time the program does not fail. Maybe gcc-2 does not clean up dlls
as aggressively as gcc-3.

As further evidence that it is the dll clean-up code that is causing the
failure, if I re-do the dll link with gcc-3, this time with the -v flag,
I see:

gcc -v -o mytest2.dll -shared --export-all dllmain.o
Reading specs from /usr/lib/gcc-lib/i686-pc-cygwin/3.2/specs
Configured with: /netrel/src/gcc-3.2-3/configure
--enable-languages=c,c++,f77,java --enable-libgcj --enable-threads=posix
--with-system-zlib --enable-nls --without-included-gettext
--enable-interpreter --disable-sjlj-exceptions
--disable-version-specific-runtime-libs --enable-shared
--build=i686-pc-linux --host=i686-pc-cygwin --target=i686-pc-cygwin
--enable-haifa --prefix=/usr --exec-prefix=/usr --sysconfdir=/etc
--libdir=/usr/lib --includedir=/nonexistent/include
--libexecdir=/usr/sbin
Thread model: posix
gcc version 3.2 20020927 (prerelease)
 /usr/lib/gcc-lib/i686-pc-cygwin/3.2/collect2.exe --shared -Bdynamic -e
__cygwin_dll_entry at 12 --dll-search-prefix=cyg -o mytest2.dll
/usr/lib/gcc-lib/i686-pc-cygwin/3.2/crtbegin.o
-L/usr/lib/gcc-lib/i686-pc-cygwin/3.2
-L/usr/lib/gcc-lib/i686-pc-cygwin/3.2/../../.. dllmain.o -lgcc -lcygwin
-luser32 -lkernel32 -ladvapi32 -lshell32 -lgcc
/usr/lib/gcc-lib/i686-pc-cygwin/3.2/crtend.o

If I then run the collect2 command manually, but *without the crtend.o
object*, as:

/usr/lib/gcc-lib/i686-pc-cygwin/3.2/collect2.exe --shared -Bdynamic -e
__cygwin_dll_entry at 12 --dll-search-prefix=cyg -o mytest.dll
/usr/lib/gcc-lib/i686-pc-cygwin/3.2/crtbegin.o
-L/usr/lib/gcc-lib/i686-pc-cygwin/3.2
-L/usr/lib/gcc-lib/i686-pc-cygwin/3.2/../../.. dllmain.o -lgcc -lcygwin
-luser32 -lkernel32 -ladvapi32 -lshell32 -lgcc

then the test gives me:
./mytest mytest.dll
DLLMain pid 3184093, handle 0x18b90000, DLL_PROCESS_ATTACH              
       successfully opened mytest.dll                                   
              DLLMain pid 3184093, handle 0x18b90000, DLL_THREAD_ATTACH 
                     DLLMain pid 643965, handle 0x18b90000,
DLL_PROCESS_DETACH
hello from parent
DLLMain pid 3184093, handle 0x18b90000, DLL_PROCESS_DETACH
DLLMain pid 643965, handle 0x18b90000, DLL_THREAD_ATTACH
hello from child
DLLMain pid 643965, handle 0x18b90000, DLL_PROCESS_DETACH

That is, the same result as using gcc-2. There is still an extra call of
DllMain with DLL_PROCESS_DETACH in the child process, but the program
does not fail.

I do not know whether this extra call is a bug in win Me, or the cygwin
dll, but it certainly wrecks any program that uses dynamic modules and
needs to fork.

If anyone has win 95 or 98, could they please see if these platforms
give the same behaviour as win Me? If it turns out to be a Windows
error, would it be possible to patch cygwin to work around it? I will
have a look at the cygwin code to see if I can find any problems there,
but I wanted to raise this issue now just in case someone can find a fix
or work-aound in time for the next release :)

Regards,
Steven

--
Unsubscribe info:      http://cygwin.com/ml/#unsubscribe-simple
Bug reporting:         http://cygwin.com/bugs.html
Documentation:         http://cygwin.com/docs.html
FAQ:                   http://cygwin.com/faq/


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