Alex Krohn <[EMAIL PROTECTED]> wrote:
> #!/usr/local/bin/perl
> # ----------------------------------------------------------------
> use CGI;
> use strict;
> my $in = new CGI;
> print $in->header();
> print "Init Value: ", $in->param('val'), "\n";
> &foobar();
> 
> sub foobar {
>    print "Sub Value: ", $in->param('val'), "\n";
> }
> # ----------------------------------------------------------------
> 
> I then run a couple times from the web test.cgi?val=a, test.cgi?val=b,
> etc. When I hit 6, 7 times things start getting strange (i.e. all the
> children have loaded the script). I then get:
> 
> Init Value: a Sub Value: b 

> However, if I do:
[...]
> &foobar($in);
> 
> sub foobar {
>    my $in = shift;
>    print "Sub Value: ", $in->param('val'), "\n";
> }
> 
> The script works normally. I'm not quite sure what's going on. =)

I don't think this is CGI.pm's fault, I think you may be running into
the odd interaction of Apache::Registry and the bizarre way perl
(mis)handles lexically scoped variables.  This oddity only comes into
play if you use a lexical variable in a block *and* a sub-block of
that block, and you run that same code multiple times, and the values
are not constant.  What happens is that the variable in the sub-block
becomes independentne in the outer block.

The reason this comes into play under Apache::Registry, is that it
compiles your module-level code and caches it as a sub, then reused it
from run to run.  So, your module level code, where you declare the
lexical variable $in, is actually not "module level", it is a sub.
And sub foobar is a sub-within-a-sub, accessing the same lexical
variable $in.  And once you hit the page enough times that you start
reusing the same httpd subprocesses that have already served you a
page each, then you are actually re-running the same cached perl code
without recompiling it, so the variables "remember" what values they
had the last time you hit that httpd process.

The reason your second version of the script works, of course, is that
you're explictly creating a separate $in variable for the sub, and
then explicitly synchronizing it with the value of the "outer" $in,
each time the code is run.

If my guess is right, your problem will go away if you drop the "my"
and make $in a global.  Try that and see if it makes the first version
of your script work.

This is all explained in the "Apache::Registry traps" section of
Chapter 4 of the O'Reilly "Writing Apache Modules in Perl and C"
book.  Those few pages alone are worth more than the price of the
book.  I happened to stumble across this bug before I'd read that
chapter, and it took literally something like 20 hours of coding and
debugging time to figure out what was going on.  Then I saw it in the
book and the light clicked.  Why perl behaves this way, I have no
idea.

  --  Cos (Ofer Inbar)  --  [EMAIL PROTECTED]  [EMAIL PROTECTED]
  --  Exodus Professional Services  --  [EMAIL PROTECTED]
 "This may seem a bit weird, but that's okay, because it is weird."
    -- Larry Wall in perlref(1) man page, Perl 5.001

Reply via email to