dll_list::detach() can stackdump

Jason Tishler jason@tishler.net
Thu Nov 7 09:13:00 GMT 2002


I'm trying to debug a dll_list::detach() stackdump problem that I first
triggered by a Cygwin Perl application.  Specifically, the problem
occurs at the following dll_init.cc line:

    void
    dll_list::detach (dll *d)
    {
        ...
***>    if (d->count <= 0)
        ...
    }

Note that I can only reproduce this problem on one Cygwin installation
so far.  FWIW, this is a partial installation (i.e., not all packages
installed) with all standard Cygwin DLLs (except for the Cygwin DLL
itself) rebased.  However, all extra CPAN Perl extension module DLLs are
not rebased due to an oversight.

The first attachment is the a minimal Perl application that can also
trigger the problem, the second is a C version.  It appears that
dlopen()-ing "many" DLLs (some rebased, some not) and then forking
(two-levels) can trigger the problem.

The third attachment is a patch (in a very loose sense of the word) that
"fixes" the problem and adds some (hopefully) useful annotations:

  ...
  284 5197991 [main] perl 620! dll_list::detach: JLT: myself->process_state = C1
  422 5198413 [main] perl 620! dll_list::detach: JLT: d = 0xB20000
  340 5198753 [main] perl 620! dll_list::detach: JLT: VirtualFree(d = 0xB20000, d->name = c:\Program Files\Hewlett-Packard\SANmaster\usr\lib\perl5\5.8.0\cygwin-multi-64int\auto\Socket\Socket.dll)
  489 5199242 [main] perl 620! dll_list::detach: JLT: loaded_dlls = 5

*>860 5200102 [main] perl 620! dll_list::detach: JLT: skipping bad d = 0xB00000

  440 5200542 [main] perl 620! dll_list::detach: JLT: myself->process_state = C1
  414 5200956 [main] perl 620! dll_list::detach: JLT: d = 0x67F70000
  431 5201387 [main] perl 620! dll_list::detach: JLT: VirtualFree(d = 0x67F70000, d->name = c:\cygwin\bin\cygexpat-0.dll)
  339 5201726 [main] perl 620! dll_list::detach: JLT: loaded_dlls = 4
  ...

The above seems to imply that a bad address is passed into
cygwin_detach_dll() for one of the DLLs.  Unfortunately, I don't
understand why.  FWIW, in this case, the skipped DLL is the CPAN
XML::Parser's Expat.dll which was not rebased.

Any hints on how to debug this further is greatly appreciated.

Thanks,
Jason

-- 
PGP/GPG Key: http://www.tishler.net/jason/pubkey.asc or key servers
Fingerprint: 7A73 1405 7F2B E669 C19D  8784 1AFD E4CC ECF4 8EF6
-------------- next part --------------
A non-text attachment was scrubbed...
Name: stack.pl
Type: application/x-perl
Size: 411 bytes
Desc: not available
URL: <http://cygwin.com/pipermail/cygwin-developers/attachments/20021107/9b774d49/attachment.pl>
-------------- next part --------------
#include <stdio.h>
#include <stdlib.h>
#include <dlfcn.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>

int
main(int argc, const char* argv[])
{
	for (int i = 1; i < argc; i++)
	{
		const char *filename = argv[i];
		void* h = dlopen(filename, RTLD_LAZY);
		if (!h)
		{
			printf ("%s: %s\n", filename, dlerror());
			exit(1);
		}
	}

	pid_t pid = fork();
	if (pid > 0)
		wait(0);
	else if (pid == 0)
		execl("/bin/uname", "/bin/uname", "-a", 0);

	exit(0);
}
-------------- next part --------------
Index: dll_init.cc
===================================================================
RCS file: /cvs/src/src/winsup/cygwin/dll_init.cc,v
retrieving revision 1.32
diff -u -p -r1.32 dll_init.cc
--- dll_init.cc	2 Nov 2002 03:31:15 -0000	1.32
+++ dll_init.cc	7 Nov 2002 16:11:14 -0000
@@ -187,6 +187,15 @@ dll_list::detach (dll *d)
   if (!myself || myself->process_state == PID_EXITED)
     return;
 
+  if (IsBadReadPtr (d, sizeof (dll)))
+    {
+      system_printf ("JLT: skipping bad d = %p", d);
+      return;
+    }
+
+  system_printf ("JLT: myself->process_state = %lx", myself->process_state);
+  system_printf ("JLT: d = %p", d);
+
   if (d->count <= 0)
     system_printf ("WARNING: try to detach an already detached dll ...");
   else if (--d->count == 0)
@@ -199,8 +208,14 @@ dll_list::detach (dll *d)
 	loaded_dlls--;
       if (end == d)
 	end = d->prev;
+
+      system_printf ("JLT: VirtualFree(d = %p, d->name = %s)", d, d->name);
+      system_printf ("JLT: loaded_dlls = %d", loaded_dlls);
+
       VirtualFree (d, 0, MEM_RELEASE);
     }
+  else
+    system_printf ("JLT: --d->count, d = %p, count = %d", d, d->count);
 }
 
 /* Initialization for all linked DLLs, called by dll_crt0_1. */


More information about the Cygwin-developers mailing list