-
Notifications
You must be signed in to change notification settings - Fork 555
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
$1 dynamic scoping breaks with recursion #6543
Comments
From frederik@ugcs.caltech.eduThe perlre man page says: The numbered variables ($1, $2, $3, etc.) and the related punctuation The phrase "until the next successful match" is not quite clear to me. sub r
{
shift =~ /(.*)/;
if(shift) {
r("bar", 0);
print "$1\n";
}
}
r("foo", 1);
# prints: bar
# (expected: foo) In addition to strange action-at-a-distance, this behavior means that # t is a copy of r
sub t
{
shift =~ /(.*)/;
if(shift) {
t("bar", 0);
print "$1\n";
}
}
sub r
{
shift =~ /(.*)/;
if(shift) {
t("bar", 0);
print "$1\n";
}
}
r("foo", 1);
# prints: foo I know of no other programming language that breaks this common Perl Info
|
From @rgs"frederik@ugcs.caltech.edu (via RT)" <perlbug-followup@perl.org> wrote:
As I *know* how the digit variables are implemented, I actually expect Basically regexp vars ($1 and alii) are associated to regexps. There's This could be better documented. |
From guest@guest.guest.xxxxxxxxSomeone, please do document this. This bit me too recently. Unfortunately, I cannot At least this much I understand: $u = ",echle etn sJ";
$t = "\nrka rPrhoatu";
$_ = $u.$t;
sub foo { s/(.)//s or return; bar(); print chop $$1 }
sub bar { s/(.)//s or return; foo(); print chop $$1 }
foo |
From perlbug@spamwagon.comWhen PerlIO::via runs the WRITE stack (or possibly any stack), Consider the following example. Both PerlIO::via::RegexBug and PerlIO::via::RegexBugWorkaround can be layered as expected, and PerlIO::via::RegexBug works fine when pushed once. When pushed package PerlIO::via::RegexBug;
use strict;
sub PUSHED {
my ($class, $mode, $fh) = @_;
return bless {}, $class;
}
sub WRITE {
my ($this, $buffer, $fh) = @_;
my $len = length $buffer;
while ($buffer =~ m/\G(.)/gs) {
my $c = $1;
print $fh ' ';
if ($c ne $1) {
die "Invalid output char expected:'$c' got:'$1'\n";
}
print $fh $1;
}
$len;
}
1;
package PerlIO::via::RegexBugWorkaround;
use strict;
sub PUSHED {
my ($class, $mode, $fh) = @_;
return bless {}, $class;
}
sub WRITE {
my ($this, $buffer, $fh) = @_;
my $len = length $buffer;
while ($buffer =~ m/\G(.)/gs) {
my $c = $1;
print $fh ' ';
print $fh $c;
}
$len;
}
1;
package main;
my @lines = <DATA>;
my $out = \*STDOUT;
Header('NORMAL');
TestOutput($out);
Header('WITH 1xRegexBugWorkaround');
binmode $out, ":via(RegexBugWorkaround)";
TestOutput($out);
Header('WITH 2xRegexBugWorkaround');
binmode $out, ":via(RegexBugWorkaround)";
TestOutput($out);
binmode $out, ":pop";
binmode $out, ":pop";
Header('NORMAL');
TestOutput($out);
Header('WITH 1xRegexBug');
binmode $out, ":via(RegexBug)";
TestOutput($out);
Header('WITH 2xRegexBug');
binmode $out, ":via(RegexBug)";
TestOutput($out);
sub Header {
print STDERR "="x40,"\n";
print STDERR "="x4," ",@_,"\n";
print STDERR "="x40,"\n";
}
sub TestOutput {
my $out = shift;
foreach (@lines) {
print $out $_;
}
}
__DATA__
This is some text
which may match
isnt that fun Perl Info
|
From @cpansproutOn Mon Jun 27 16:13:21 2011, perlbug@spamwagon.com wrote:
You are right in saying ‘possibly any stack’. This is the same as bug |
The RT System itself - Status changed from 'new' to 'open' |
I don't follow how you could fix it at this @cpansprout and possible @demerphq "spamwagon", I don't see how you could possibly change its behavior at this point without causing a even more confusion. |
I think if we were to come up with a technical fix (which I'd certainly like to see), the next step would be various levels of smoking to see if this would cause widespread breakage or not. My first instinct is that a) the kind of recursion that tickles it would be relatively rare; b) that in most cases where people know that they have encountered it, their workarounds would continue to work if it were fixed; c) that in most cases where people don't realise they've encountered it, fixing it would silently fix a bug for them; d) that most exceptions will be deliberately too-clever-by-half code in JAPHs or the like. I can't think of an easy way to test that instinct other than to try it, unless readers report that they've knowingly used this in production code. Hugo |
On 2/15/20 6:55 AM, Hugo van der Sanden wrote:
I think if we were to come up with a technical fix (which I'd certainly
like to see), the next step would be various levels of smoking to see if
this would cause widespread breakage or not.
My first instinct is that a) the kind of recursion that tickles it would
be relatively rare; b) that in most cases where people know that they
have encountered it, their workarounds would continue to work if it were
fixed; c) that in most cases where people don't realise they've
encountered it, fixing it would silently fix a bug for them; d) that
most exceptions will be deliberately too-clever-by-half code in JAPHs or
the like.
I can't think of an easy way to test that instinct other than to try it,
unless readers report that they've knowingly used this in production code.
Hugo
—
This sounds reasonable to me
|
This ticket contains two different bugs. I am not sure if the first bug is really a bug, but the second part does look like a bug. @khwilliamson any thoughts? |
FWIW, I looked into this. The code that executes via hooks does not do a SAVETMPS and FREETMPS. Just ENTER/LEAVE. But when I added SAVETMPS and FREETMPS it did not seem to help. Reading more it seemed like the context code changed in 5.24 or so, and I am still wrapping my head around its implications. I think that it should be creating a context block to use for rolling back PL_curpm, but I admit I could be totally wrong. @iabyn do you have any thoughts on that? |
On Fri, Dec 30, 2022 at 01:10:00AM -0800, Yves Orton wrote:
This ticket contains two different bugs. I am not sure if the first bug
is really a bug, but the second part does look like a bug.
I assume you are referring to bug 1 as being where calling a function
recursively doesn't get a separate dynamic scope for each pattern match,
while calling a separate (but identical) inner function does.
This is because PL_curpm records the *OP* associated with the most recent
match in the current scope, rather than recording the regex. Arguably
we should be recording the latter, and arguably there should be a separate
regex for each level of recursion (in the same way that we have a separate
set of PADTMPs etc per level, IIRC).
But this also ties in with the fact that at the moment we don't properly
split regexes (i.e. SVt_REGEXP SVs) into separate fixed and dynamic parts.
Really the info such as capture indexes should be separate in each SV,
while multiple SVs would all link to the same ref-counted 'fixed' data
structure. This would make copying regexes much faster, including
the copying done in my $r = qr/.../, and also in $x =~ $r which is
paradoxically often slower since $r has to be copied for each match call.
As for the second bug, where PerlIO::via calls a perl-level callback sub
to implement actions on PerlIO layers, then unless I'm misreading it, the
bug reported is that when the *same* layer (RegexBug) is pushed *twice*,
then WRITE() doesn't preserve the value of $1. But since WRITE is now
being called recursively (once for each layer), surely this is *exactly*
the same bug as #1?
PS - as regards scope and context, PerlIO::via invokes the callbacks using
call_sv(), which itself calls pp_entersub(), which pushes a CXt_SUB
context as normal, which saves a copy of PL_curpm as normal, which is
restored as normal on sub return. The actual issue is that the current and
saved (and then being restored) values of PL_curpm are identical, since
they point to the same PMOP in the same WRITE() sub.
…--
I don't want to achieve immortality through my work...
I want to achieve it through not dying.
-- Woody Allen
|
I dont know. That was what i was unsure of. If something is triggered "magically", should it behave differently than if it is executed normally. I was thinking maybe it should, and I found some hints in the docs about context that seemed to suggest as much.
That was what I didn't understand when I wrote my comment.
Yes. I did something like this, with the "mother_re" stuff, which helped somewhat, but I think I wasn't brave enough to completely split out the capture buffer state from the rest. I am now however. I will take care of this. |
Migrated from rt.perl.org#22369 (status was 'open')
Searchable as RT22369$
The text was updated successfully, but these errors were encountered: