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 [EMAIL PROTECTED] --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 [EMAIL PROTECTED] --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/