Hi, I'm your neighborhood Debian package maintainer for mod_perl...
I made the mistake of getting off this list a while back, and I've
accumulated a bit of a collection of patches since then.  Most in the
last few days.  So I figured now that I was actively working on
mod_perl again, I would submit them back where they belong.


First of all, in CVS I see this:
> fix $ENV{PATH} corruption, thanks to help from Chip Turner, 
> Oleg Bartunov and Tomasz Przygoda 

I'm still seeing some $ENV{PATH} corruption built as a DSO, though. 
I'll look in to it later tonight.




The first really important one is a fix for the crashes I've been
seeing in boot_DBI.  I can't find the exact message in the archive now,
but anyone who reported that a problem was fixed by setting
PERL_STARTUP_DONE_CHECK=1 in the environment probably wants this patch
instead.  The problem was that a library (in this case libpg.so) called
putenv() after perl was initialized but before perl's my_setenv got
called.  Thus environ[] never got copied to malloc()'d memory, and
trying to overwrite $ENV{TZ} caused a bogus free().  That's
environment-mod_perl.c.

A pair of small perl patches, from Roderick Schertler <[EMAIL PROTECTED]>:
  - Apache.pm: send_cgi_header was modifying the string in $_.
  Fixed in local-underscore-Apache.pm.

  - There was a precedence problem in StatINC.pm.  Fixed in
  precedence-StatINC.pm.


And a trivial fix for mod_perl.c - one of the status messages had
"...ok" instead of "...".  Fixed in message-cleanup-mod_perl.c.

Makefile.PL would not handle PERL_DEBUG=1 if USE_DSO, because the code
was stuck in a loop over available apache source trees.  I just moved
it outside of the loop.  Fixed in PERL_DEBUG-Makefile.PL.


And now the doozy.  This one is not like the others; it is a stopgap,
EVIL hack and should not be included in the source.  It's included only
for observation purposes.  I worked around the ongoing bug involving
the DSO not liking being reloaded.  From what I could tell the former
hack, mp_dso_unload, was somehow never getting called; if it had gotten
called, it would have caused a segfault at dlclose(0), which I found
out the hard way.  The patch 'hideous-hack-mod_perl.c' actually walks
the cleanup tree and removes all module unloads - removing our own did
not suffice to fix the problem, oddly.  I can think of a dozen better
ways to do this cleanly, involving small apache patches; I am also
fully aware that this is a symptom, not a problem, that I am fixing. 
But it -does- suffice to make the DSO work.  For now.

Be warned, the patch might reverses the meaning of PERL_DSO_UNLOAD.
I couldn't quite tell what it was supposed to accomplish before as I
could not even get that code to trigger.


I saw the message about the cyclic .init sections... I don't think that
is truly the problem, although I'm sure it's a problem.  I'm using
libperl.a instead of libperl.so on this platform, and thus there is no
.init section.  Right?  Certainly none showed up in the linker debug
logs, although this is the linux dynamic loader, which does not do
cyclic dependency checking far as I can tell, or at least can't print a
message about it.

LD_PRELOAD'ing the module DOES work to prevent the bug, however.  I
can't see why, and I can't get a good debugging dump.  I'll look at it
more later.



Dan

/--------------------------------\  /--------------------------------\
|       Daniel Jacobowitz        |__|        SCS Class of 2002       |
|   Debian GNU/Linux Developer    __    Carnegie Mellon University   |
|         [EMAIL PROTECTED]         |  |       [EMAIL PROTECTED]      |
\--------------------------------/  \--------------------------------/

precedence-StatINC.pm

PERL_DEBUG-Makefile.PL

--- libapache-mod-perl-1.21.orig/src/modules/perl/mod_perl.c
+++ libapache-mod-perl-1.21/src/modules/perl/mod_perl.c
@@ -659,6 +655,16 @@
     }
     MP_TRACE_g(fprintf(stderr, "ok\n"));
 
+    /* Force the environment to be copied out of its original location
+       above argv[].  This fixes a crash caused when a module called putenv()
+       before any Perl modified the environment - environ would change to a
+       new value, and the check in my_setenv() to duplicate the environment
+       would fail, and then setting some environment value which had a previous
+       value would cause perl to try to free() something from the original env.
+       This crashed free(). */
+    my_setenv("MODPERL_BROKEN_ENV", "0");
+    my_setenv("MODPERL_BROKEN_ENV", NULL);
+
     {
 	dTHR;
 	TAINT_NOT; /* At this time all is safe */

local-underscore-Apache.pm

--- libapache-mod-perl-1.21.orig/src/modules/perl/mod_perl.c
+++ libapache-mod-perl-1.21/src/modules/perl/mod_perl.c
@@ -607,7 +603,7 @@
     }
     MP_TRACE_g(fprintf(stderr, "ok\n"));
   
-    MP_TRACE_g(fprintf(stderr, "constructing perl interpreter...ok\n"));
+    MP_TRACE_g(fprintf(stderr, "constructing perl interpreter..."));
     perl_construct(perl);
 
     status = perl_parse(perl, xs_init, argc, argv, NULL);
--- libapache-mod-perl-1.21.orig/src/modules/perl/mod_perl.c
+++ libapache-mod-perl-1.21/src/modules/perl/mod_perl.c
@@ -411,28 +411,6 @@
     if(orig_inc) SvREFCNT_dec(orig_inc); \
     orig_inc = av_copy_array(GvAV(incgv))
 
-#if MODULE_MAGIC_NUMBER >= MMN_130
-static void mp_dso_unload(void *data) 
-{ 
-    module *modp;
-
-    if(!PERL_DSO_UNLOAD)
-	return;
-
-    if(strEQ(top_module->name, "mod_perl.c"))
-	return;
-
-    for(modp = top_module; modp; modp = modp->next) {
-	if(modp->dynamic_load_handle) {
-	    MP_TRACE_g(fprintf(stderr, 
-			       "mod_perl: cancel dlclose for %s\n", 
-			       modp->name));
-	    modp->dynamic_load_handle = NULL;
-	}
-    }
-} 
-#endif
-
 static void mp_server_notstarting(void *data) 
 {
     saveINC;
@@ -506,6 +484,24 @@
     perl_startup(s, p);
 }
 
+/* HIDEOUS HACK - search for cleanup below to see why */
+struct cleanup {
+    void *data;
+    void (*plain_cleanup) (void *);
+    void (*child_cleanup) (void *);
+    struct cleanup *next;
+};
+struct moduleinfo {
+    char *name;
+    module *modp;
+};
+struct pool_hdr {
+    union block_hdr *first;
+    union block_hdr *last;
+    struct cleanup *cleanups;
+    struct process_chain *subprocesses;
+};
+
 void perl_startup (server_rec *s, pool *p)
 {
     char *argv[] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL };
@@ -727,8 +733,37 @@
 
     saveINC;
 #if MODULE_MAGIC_NUMBER >= MMN_130
-    if(perl_module.dynamic_load_handle) 
-	register_cleanup(p, NULL, mp_dso_unload, null_cleanup); 
+    if(perl_module.dynamic_load_handle && !PERL_DSO_UNLOAD) {
+	/* We're a DSO.  But we do NOT want to be unloaded.  Remove the cleanup. */
+	/* Unfortunately, we can not easily use ap_kill_cleanup, as we do not know the value of data. */
+	/* Also unfortunately, mod_perl seems to crash if ANY module is unloaded.  Thus this mess. */
+
+	struct cleanup *cur, **last;
+	void (*unload_func) (void *);
+
+	if(((struct pool_hdr *)p)->cleanups) {
+		for(cur = ((struct pool_hdr *)p)->cleanups; cur; cur = cur->next) {
+			/* This works SOLELY by luck. There are no non-module cleanups on the list before us. */
+			if(cur->child_cleanup == ap_null_cleanup
+			  && cur->data			/* Be paranoid */
+			  && ((struct moduleinfo *)cur->data)->modp == &perl_module)
+			  {
+				unload_func = cur->plain_cleanup;
+				break;
+			  }
+		}
+		last = &((struct pool_hdr *)p)->cleanups;
+		for(cur = ((struct pool_hdr *)p)->cleanups; cur; cur = cur->next) {
+			if(cur->child_cleanup == ap_null_cleanup
+			  && cur->data			/* Be paranoid */
+			  && cur->plain_cleanup == unload_func)
+			  {
+				*last = cur->next;
+			  } else
+			    last = &((*last)->next);
+		}
+	}
+    }
 #endif
 }
 

Reply via email to