Subject: | NEXT messes up $1 and $2 passed as arguments |
Date: | Fri, 20 Jun 2008 16:05:08 +0200 |
To: | bug-NEXT [...] rt.cpan.org |
From: | BUCHMULLER Norbert <norbi [...] nix.hu> |
If $1 or $2 is passed as arguments to a sub called via NEXT, the sub will
receive "NEXT" and the sub name in the corresponding arguments, instead
of the original value of $1 and $2 before the $obj->NEXT::somesub(...)
call. (Similarly some of the other regex punctuation vars are affected.)
See the 'NEXT-regex_match_variable_bug.pl'.
The problem originates from the peculiar scoping of the regex
match variables, and that members of @_ are aliases to the corresponding
members of the actual argument list:
"The numbered match variables ($1, $2, $3, etc.) and the related
punctuation set ($+, $&, $`, $', and $^N) are all dynamically scoped
until he end of the enclosing block or until the next successful match,
whichever comes first." from perlre
"The array @_ is a local array, but its elements are aliases for the
actual scalar parameters." from perlsub
See 'Perl-regex_match_variable_bug.pl' and #23140 and #22369 in
rt.perl.org.
Now there are three ways to avoid this unintended behaviour:
A) Enclosing all the code that modifies the regex vars into an inner
scope inside NEXT::AUTOLOAD, and never use directly @_ from this inner
scope. (We must not use @_ from inside that scope, since in the inner
scope those members of @_ that are aliased to $1, $2, etc. point to the
$1, $2, etc. of the last successfully matched regex in the *inner* scope.)
B) Creating a copy of @_ at the beginning of NEXT::AUTOLOAD, and using
that instead of @_. (This way we create a copy of each member of @_,
there will be no aliases.)
C) Not passing regex match- or punctuation vars as arguments. (ie.
considering this behaviour as a feature)
Note that local()-izing the regex match- and punctuation variables in
the NEXT::AUTOLOAD will not work, first, because that would hide their
previous value (and we want to pass that on, encapsulated in @_), second,
because it does not work for regex vars. :-)
Now, we must drop B) as copying @_ in NEXT::AUTOLOAD will break outbound
parameter passing. (The user can modify the actual variables in the
argument list via $_[1], $_[2], ..., and NEXT does not break it
currently.)
We must drop C) as well, because if someone is aware of the above problem
and writes his/her subs carefully to not modify regex vars inadvertently,
putting NEXT in the call chain should not ruin that.
As far as I can see, there only remains A). So I created a quick and dirty
fix: since in NEXT.pm we use none of the regex vars, simply wrapping all
the match and substitute expressions in 'do { }' blocks does the trick
of putting them in an inner scope. See
'NEXT-regex_match_variable_fix.diff'.
The test cases all pass, and I also did a rough performance measurement,
and it seems that the patch has no negative effect. (I also added a new
testcase for this regex variable problem.)
A nicer solution would require refactoring the code in the sub to
separate those parts that use regex matches or substitutions in an innner
scope (or inner scopes) and collect those parts that use @_ but no regexes
in the outer scope. But that would be hairy, as I can see.
Note: I only considered NEXT::AUTOLOAD above, but the same applies to all
the other subs in NEXT.pm (and the patch fixes them, too).
norbi
Perl version: see 'Perl-version.txt'
NEXT.pm version: 0.60
Message body is not shown because sender requested not to inline it.
Message body is not shown because sender requested not to inline it.
Message body is not shown because sender requested not to inline it.
Message body is not shown because sender requested not to inline it.