Perl / perl5

🐪 The Perl programming language
https://dev.perl.org/perl5/
Other
1.92k stars 551 forks source link

scope error with brackets #6274

Closed p5pRT closed 21 years ago

p5pRT commented 21 years ago

Migrated from rt.perl.org#20716 (status was 'resolved')

Searchable as RT20716$

p5pRT commented 21 years ago

From dwjones@spawar.navy.mil

Created by dwjones@spawar.navy.mil

I have encountered a bug that involves the changing of scope. Here is some sample code that demonstrates the problem.

\

1 #!/usr/bin/perl -w 2 3 $x = "outer-scope"; 4 5 { 6 my $x = "inner-scope"; 7 print "$x[R0]" . "\n"; 8 print "${x}[R0]" . "\n"; 9 print "${x} [R0]" . "\n"; 10 }

\

Results​: Argument "R0" isn't numeric in aelem at ./test.pl line 7. Use of uninitialized value at ./test.pl line 7.

outer-scope[R0] inner-scope [R0]

Line 8 should either print an error because it is expecting an array\, as line 7 did\, or else it should give ${x} as the local value. Instead it prints the outer scoped variable.

There are many variations of this that can be reproduced\, but this is a basic example. The easy work-around is to escape the brackets around 'R0'.

Perl Info ``` Site configuration information for perl 5.00503: Configured by oper1 at Tue Nov 9 17:08:34 PST 1999. Summary of my perl5 (5.0 patchlevel 5 subversion 3) configuration: Platform: osname=solaris, osvers=2.7, archname=sun4-solaris uname='sunos yoohoo 5.7 generic_106541-07 sun4u sparc sunw,ultra-enterprise ' hint=recommended, useposix=true, d_sigaction=define usethreads=undef useperlio=undef d_sfio=undef Compiler: cc='gcc', optimize='-O', gccversion=2.8.1 cppflags='-I/usr/local/include' ccflags ='-I/usr/local/include' stdchar='char', d_stdstdio=define, usevfork=false intsize=4, longsize=4, ptrsize=4, doublesize=8 d_longlong=define, longlongsize=8, d_longdbl=define, longdblsize=16 alignbytes=8, usemymalloc=y, prototype=define Linker and Libraries: ld='gcc', ldflags =' -L/usr/local/lib' libpth=/usr/local/lib /lib /usr/lib /usr/ccs/lib libs=-lsocket -lnsl -ldl -lm -lc -lcrypt libc=/lib/libc.so, so=so, useshrplib=false, libperl=libperl.a Dynamic Linking: dlsrc=dl_dlopen.xs, dlext=so, d_dlsymun=undef, ccdlflags=' ' cccdlflags='-fPIC', lddlflags='-G -L/usr/local/lib' Locally applied patches: @INC for perl 5.00503: tools/config ../tools/config ../../tools/config /export/ui/bridge_spec/tools/config /usr/local/lib/perl5/5.00503/sun4-solaris /usr/local/lib/perl5/5.00503 /usr/local/lib/perl5/site_perl/5.005/sun4-solaris /usr/local/lib/perl5/site_perl/5.005 . Environment for perl 5.00503: HOME=/homea/dwjones LANG (unset) LANGUAGE (unset) LD_LIBRARY_PATH=/r0/common/rti/RTI-1.3NGv5update4/SunOS-5.7-Sparc-SPRO-5.3-dbg-mt/lib:/quikr0/common/CCSEV1.0.01/CCSEV1.0.01/SimEngineCore/SPEEDES/lib:/quikr0/common/CCSEV1.0.01/CCSEV1.0.01/MDDI/lib:/quikr0/common/JCL_CCSE/JCL/lib:/quikr0/common/Warlib/lib:/quikr0/common/Sne/lib LOGDIR (unset) PATH=/quikr0/common/CCSEV1.0.01/CCSEV1.0.01/SimEngineCore/SPEEDES/bin:/quikr0/common/CCSEV1.0.01/CCSEV1.0.01/MDDI/bin:/export/ui/bridge_spec/tools/bin:/bin:/usr/bin:/usr/sbin:/usr/local/bin:/opt/SUNWspro/bin:/usr/ucb:/usr/openwin/bin:/app/BridgePoint/bin:/usr/atria/bin/:.:/usr/local/samba/bin:/homea/langford/bin:/usr/mccabe:/usr/ccs/bin:/app/McCabe:/opt/KCC_BASE/kdb/bin:/usr/atria/bin/ PERLLIB=tools/config:../tools/config:../../tools/config:/export/ui/bridge_spec/tools/config PERL_BADLANG (unset) SHELL=/bin/csh ```
p5pRT commented 21 years ago

From @rgs

Dustin Jones (via RT) \perlbug\-followup@​perl\.org wrote​:

I have encountered a bug that involves the changing of scope. Here is some sample code that demonstrates the problem.

Here's a cut-down version :

  my $x = 'x';   print "${x}{";   print "${x}[";   print "\n";

This simply prints '{['.

Somehow the qq lexer doesn't see lexicals in this case.

Summary of my perl5 (5.0 patchlevel 5 subversion 3) configuration​:

This bug is present in 5.6.x\, 5.8.0 and in blead.

p5pRT commented 21 years ago

From enache@rdslink.ro

On Wed\, Feb 05\, 2003 at 10​:06​:53AM +0100\, Rafael Garcia-Suarez wrote​:

Here's a cut-down version :

my $x = 'x';
print "$\{x\}\{";
print "$\{x\}\[";
print "\\n";

This simply prints '{['.

this little hack fixes it​:


Inline Patch ```diff --- /arc/perl-current/toke.c Sat Feb 8 21:36:52 2003 +++ perl-current/toke.c Mon Feb 10 17:57:48 2003 @@ -6287,6 +6287,8 @@ S_scan_ident(pTHX_ register char *s, reg funny, dest, funny, dest); } } + if (PL_lex_inwhat == OP_STRINGIFY) + PL_expect = XREF; } else { s = bracket; /* let the parser handle it */ ---------------------------------------------------------------------- ```

Setting PL_expect to XREF will prevent Perl from searching for '%x' or '@​x' instead of '$x' in pad_findmy() and\, not finding it\, generate a 'gvsv' OP instead of a 'padsv' OP\, as it should. (see toke.c :3461 :3557 :5288)

It's otherwise harmless - PL_expect will be set to XOPERATOR anyway.

Here is a test script​:

#! /usr/bin/perl use Test​::More tests => 3; {   undef $a;   undef @​b;   my $a="a"; ok("${a}{" eq "a{");   my $a="a"; ok("${a}[" eq "a[");   my @​b=("b"); ok("@​{b}{" eq "b{"); } __END__

Regards Adi

p5pRT commented 21 years ago

arthur@contiller.se - Status changed from 'new' to 'open'

p5pRT commented 21 years ago

From arthur@contiller.se

Hi\,

This bug has now been closed as the patch from Enache Adrian was applied as change 18687 to bleadperl.

Arthur

p5pRT commented 21 years ago

arthur@contiller.se - Status changed from 'open' to 'resolved'

p5pRT commented 21 years ago

From @hvds

Rafael Garcia-Suarez \rgarciasuarez@​free\.fr wrote​: :Dustin Jones (via RT) \perlbug\-followup@​perl\.org wrote​: :> I have encountered a bug that involves the changing of scope. :> Here is some sample code that demonstrates the problem. : :Here's a cut-down version : : : my $x = 'x'; : print "${x}{"; : print "${x}["; : print "\n"; : :This simply prints '{['. : :Somehow the qq lexer doesn't see lexicals in this case.

I think I looked at this a couple of years ago\, and got stuck. If I remember rightly\, cleverness in toke.c sees the '[' and modifies the token buffer to '@​{x}'; later it knows @​x is not a lexical\, so doesn't upgrade it to a pad lookup; and then later still it releases that the '[' didn't introduce a dereference\, and fixes up the resulting op to find the scalar :​:$x rather than :​:@​x.

Some of the details may be wrong\, but this bit is right​: it's a whole hairy mess\, and should get its darned hair cut.

Hugo

p5pRT commented 21 years ago

From sky@nanisky.com

On onsdag\, feb 12\, 2003\, at 05​:43 Europe/Stockholm\, hv@​crypt.org wrote​:

ubject​: Re​: [perl #20716] scope error with brackets

Rafael Garcia-Suarez \rgarciasuarez@​free\.fr wrote​: :Dustin Jones (via RT) \perlbug\-followup@​perl\.org wrote​: :> I have encountered a bug that involves the changing of scope. :> Here is some sample code that demonstrates the problem. : :Here's a cut-down version : : : my $x = 'x'; : print "${x}{"; : print "${x}["; : print "\n"; : :This simply prints '{['. : :Somehow the qq lexer doesn't see lexicals in this case.

I think I looked at this a couple of years ago\, and got stuck. If I remember rightly\, cleverness in toke.c sees the '[' and modifies the token buffer to '@​{x}'; later it knows @​x is not a lexical\, so doesn't upgrade it to a pad lookup; and then later still it releases that the '[' didn't introduce a dereference\, and fixes up the resulting op to find the scalar :​:$x rather than :​:@​x.

Some of the details may be wrong\, but this bit is right​: it's a whole hairy mess\, and should get its darned hair cut.

Hugo

I applied patch 18687 from Enache Adrian that fixed this problem\, was the patch incorrect?

Arthur

p5pRT commented 21 years ago

From @rgs

A.Bergman \sky@​nanisky\.com wrote​:

I applied patch 18687 from Enache Adrian that fixed this problem\, was the patch incorrect?

I was also going to apply this one\, this patch looks (partially) correct to me. Except that it doesn't solve the similar bug with qr{} -- probably the only thing that's needed is to test for PL_lex_inwhat == OP_QR as well.

p5pRT commented 21 years ago

From enache@rdslink.ro

On Wed\, Feb 12\, 2003 at 09​:50​:32AM +0100\, Rafael Garcia-Suarez wrote​:

A.Bergman \sky@​nanisky\.com wrote​:

I applied patch 18687 from Enache Adrian that fixed this problem\, was the patch incorrect?

I was also going to apply this one\, this patch looks (partially) correct to me. Except that it doesn't solve the similar bug with qr{} -- probably the only thing that's needed is to test for PL_lex_inwhat == OP_QR as well.


Inline Patch ```diff --- /arc/perl-current/toke.c 2003-02-10 21:23:38.000000000 +0200 +++ perl-current/toke.c 2003-02-12 21:18:42.000000000 +0200 @@ -6287,7 +6287,7 @@ S_scan_ident(pTHX_ register char *s, reg funny, dest, funny, dest); } } - if (PL_lex_inwhat == OP_STRINGIFY) + if (PL_lex_inwhat == OP_STRINGIFY || PL_lex_inwhat == OP_MATCH) PL_expect = XREF; } else { --------------------------------------------------------------------------- ```

I could swear intuit_more() was already handling this :-)

Regards Adi

p5pRT commented 21 years ago

From @rgs

Enache Adrian wrote​:

--- /arc/perl-current/toke.c 2003-02-10 21​:23​:38.000000000 +0200 +++ perl-current/toke.c 2003-02-12 21​:18​:42.000000000 +0200 @​@​ -6287\,7 +6287\,7 @​@​ S_scan_ident(pTHX_ register char *s\, reg funny\, dest\, funny\, dest); } } - if (PL_lex_inwhat == OP_STRINGIFY) + if (PL_lex_inwhat == OP_STRINGIFY || PL_lex_inwhat == OP_MATCH)

Nope\, I think you'll need OP_QR at least also for the case qr/${x}{/.

Note that Arthur added regression tests when he applied your patch (to t/comp/parser.t\, see change #18687). Could you do the same for m// and qr// ? and s/// ? and possibly with qx// ? (and I think we're done with interpolation contexts) (although it's arguably difficult to add portable tests that use qx//\, esp. in a t/comp/ test\, which is aimed at testing the basic parsing techniques)

p5pRT commented 21 years ago

From enache@rdslink.ro

On Wed\, Feb 12\, 2003 at 10​:01​:46PM +0100\, Rafael Garcia-Suarez wrote​:

Enache Adrian wrote​:

--- /arc/perl-current/toke.c 2003-02-10 21​:23​:38.000000000 +0200 +++ perl-current/toke.c 2003-02-12 21​:18​:42.000000000 +0200 @​@​ -6287\,7 +6287\,7 @​@​ S_scan_ident(pTHX_ register char *s\, reg funny\, dest\, funny\, dest); } } - if (PL_lex_inwhat == OP_STRINGIFY) + if (PL_lex_inwhat == OP_STRINGIFY || PL_lex_inwhat == OP_MATCH)

Nope\, I think you'll need OP_QR at least also for the case qr/${x}{/.

I thinked the same\, but​:

\(gdb\) r \-e 'my $p=1;print qr\($\{p\}\{\)'
\.\.\.\.
\(gdb\) br toke\.c​:6289
Breakpoint 2 at 0x40056a27​: file toke\.c\, line 6289\.
\(gdb\) cont

Breakpoint 2\, S\_scan\_ident \(my\_perl=0x804bb58\, s=0x8064b64 "\{"\,
     send=0x8064b65 ""\, dest=0x804c105 "p"\, destlen=5\, ck\_uni=0\) at toke\.c​:6290
6290                if \(PL\_lex\_inwhat == OP\_STRINGIFY || PL\_lex\_inwhat == OP\_MATCH\)
\(gdb\) p PL\_op\_name\[my\_perl\->Ilex\_inwhat\]
$1 = 0x4012dc9a "match"
\.\.\.\.

I added the OP_BACKTICK and OP_SUBST to my patch and it turned into something very ugly :-(. I'm still looking for a simpler solution ( maybe modifying intuit_more() ? )


Inline Patch ```diff --- /arc/perl-current/toke.c 2003-02-10 21:23:38.000000000 +0200 +++ perl-current/toke.c 2003-02-12 23:39:55.000000000 +0200 @@ -6287,7 +6287,8 @@ S_scan_ident(pTHX_ register char *s, reg funny, dest, funny, dest); } } - if (PL_lex_inwhat == OP_STRINGIFY) + if (PL_lex_inwhat == OP_STRINGIFY || PL_lex_inwhat == OP_MATCH || + PL_lex_inwhat == OP_BACKTICK || PL_lex_inwhat == OP_SUBST) PL_expect = XREF; } else { ------------------------------------------------------------------------- ```

Note that Arthur added regression tests when he applied your patch (to t/comp/parser.t\, see change #18687). Could you do the same for m// and qr// ? and s/// ? and possibly with qx// ? (and I think we're done with interpolation contexts) (although it's arguably difficult to add portable tests that use qx//\, esp. in a t/comp/ test\, which is aimed at testing the basic parsing techniques)

Maybe this should do​:

#! /usr/bin/perl use Test​::More tests => 10; {   undef $a;   undef @​b;

  my $a="a"; ok("${a}{" eq "a{");   my $a="a"; ok("${a}[" eq "a[");   my @​b=("b"); ok("@​{b}{" eq "b{");

  my $a="a"; ok(qx/echo ${a}{/ eq "a{\n");   my $a="a"; ok(qx/echo ${a}[/ eq "a[\n");   my @​b=("b"); ok(qx/echo @​{b}{/ eq "b{\n");

  my $a="a"; ok("-a{-" =~ m/-${a}{-/);   my @​b=("b"); ok("-b{-" =~ m/-@​{b}{-/);

  my $a="a"; $_="-a{-"; s/${a}{/x/; ok($_ eq "-x-");   my @​b=("b"); $_="-b{-"; s/@​{b}{/x/; ok($_ eq "-x-"); } __END__

With my patch applied\, I just passed all tests on my FreeBSD-current box.

Regards Adi

p5pRT commented 21 years ago

From enache@rdslink.ro

On Thu\, Feb 13\, 2003 at 01​:02​:03AM +0200\, Enache Adrian wrote​:

I thinked the same\, but​:

Sorry for my english!

my $a="a"; $\_="\-a\{\-"; s/$\{a\}\{/x/; ok\($\_ eq "\-x\-"\);
my @​b=\("b"\); $\_="\-b\{\-"; s/@​\{b\}\{/x/; ok\($\_ eq "\-x\-"\);

}

Maybe add these tests too ?

my $a="a"; $_="-x-"; s/x/${a}{/; ok($_ eq "-a{-"); my @​b=("b"); $_="-x-"; s/x/@​{b}{/; ok($_ eq "-b{-");

Regards Adi

p5pRT commented 21 years ago

From enache@rdslink.ro

On Wed\, Feb 12\, 2003 at 10​:01​:46PM +0100\, Rafael Garcia-Suarez wrote​:

Enache Adrian wrote​:

--- /arc/perl-current/toke.c 2003-02-10 21​:23​:38.000000000 +0200 +++ perl-current/toke.c 2003-02-12 21​:18​:42.000000000 +0200 @​@​ -6287\,7 +6287\,7 @​@​ S_scan_ident(pTHX_ register char *s\, reg funny\, dest\, funny\, dest); } } - if (PL_lex_inwhat == OP_STRINGIFY) + if (PL_lex_inwhat == OP_STRINGIFY || PL_lex_inwhat == OP_MATCH)

Sorry for the false noise. Making a lot of tests for all possible cases (OP_MATCH\, OP_BACKTICK\, OP_SUBST\, etc) was really stupid.

I hope I get it right finally with this very simple solution. ( passes all tests for me on FreeBSD & linux systems ). Please try.


Inline Patch ```diff --- /arc/perl-current/toke.c 2003-02-10 21:23:38.000000000 +0200 +++ perl-current/toke.c 2003-02-13 03:31:00.000000000 +0200 @@ -6274,8 +6274,10 @@ S_scan_ident(pTHX_ register char *s, reg } if (*s == '}') { s++; - if (PL_lex_state == LEX_INTERPNORMAL && !PL_lex_brackets) + if (PL_lex_state == LEX_INTERPNORMAL && !PL_lex_brackets) { PL_lex_state = LEX_INTERPEND; + PL_expect = XREF; + } if (funny == '#') funny = '@'; if (PL_lex_state == LEX_NORMAL) { @@ -6287,8 +6289,6 @@ S_scan_ident(pTHX_ register char *s, reg funny, dest, funny, dest); } } - if (PL_lex_inwhat == OP_STRINGIFY) - PL_expect = XREF; } else { s = bracket; /* let the parser handle it */ ------------------------------------------------------------------------ ```

Note that Arthur added regression tests when he applied your patch (to t/comp/parser.t\, see change #18687). Could you do the same for m// and qr// ? and s/// ? and possibly with qx// ? (and I think we're done with interpolation contexts) (although it's arguably difficult to add portable tests that use qx//\, esp. in a t/comp/ test\, which is aimed at testing the basic parsing techniques)

Here is a more complete test script. It tests for qq//\,qx//\,qr//\, s/// and also for heredoc interpolation. The qx/echo ../ trick should work on Windows too. ( I know nothing about VMS\, etc ).

#! /usr/bin/perl use Test​::More tests => 6; {   undef $a;   undef @​b;

  my $a="a";   my @​b="b";   my @​a="z";   ok(qq/${a}{ ${a}[ @​{b}{/ eq "a{ a[ b{");

  ok("-a{-a1-b{-" =~ qr/-${a}{-${a}[1]-@​{b}{-/);

  ok(qx/echo ${a}{ ${a}[ @​{b}{/ eq "a{ a[ b{\n");

  ok(\<\<END eq "a{ a[ b{\n"); ${a}{ ${a}[ @​{b}{ END

  $_ = "-a{-a1-b{-";   s/${a}[1]/x/; s/${a}{/x/; s/@​{b}{/x/;   ok($_ eq "-x-x-x-");

  $_="-x-x-x-";   s/x/${a}{/; s/x/${a}[/; s/x/@​{b}{/;   ok($_ eq "-a{-a[-b{-");

} __END__

Note​: I seems to be no difference between qr// and m// from the variable interpolation point of view.

Regards Adi

p5pRT commented 21 years ago

From @hvds

"A. Bergman" \sky@&#8203;nanisky\.com wrote​: :> Rafael Garcia-Suarez \rgarciasuarez@&#8203;free\.fr wrote​: :> :Here's a cut-down version : :> : :> : my $x = 'x'; :> : print "${x}{"; :> : print "${x}["; :> : print "\n"; :> : :> :This simply prints '{['. :> : :> :Somehow the qq lexer doesn't see lexicals in this case. :> :> I think I looked at this a couple of years ago\, and got stuck. [...] :I applied patch 18687 from Enache Adrian that fixed this problem\, was :the patch incorrect?

Sorry\, I missed the patch\, and I suspect I must be remembering a different problem. The perils of running in catch-up mode. :(

Hugo

p5pRT commented 21 years ago

From @rgs

Enache Adrian wrote​:

--- /arc/perl-current/toke.c 2003-02-10 21​:23​:38.000000000 +0200 +++ perl-current/toke.c 2003-02-13 03​:31​:00.000000000 +0200 @​@​ -6274\,8 +6274\,10 @​@​ S_scan_ident(pTHX_ register char *s\, reg } if (*s == '}') { s++; - if (PL_lex_state == LEX_INTERPNORMAL && !PL_lex_brackets) + if (PL_lex_state == LEX_INTERPNORMAL && !PL_lex_brackets) { PL_lex_state = LEX_INTERPEND; + PL_expect = XREF; + } if (funny == '#') funny = '@​'; if (PL_lex_state == LEX_NORMAL) { @​@​ -6287\,8 +6289\,6 @​@​ S_scan_ident(pTHX_ register char *s\, reg funny\, dest\, funny\, dest); } } - if (PL_lex_inwhat == OP_STRINGIFY) - PL_expect = XREF; } else { s = bracket; /* let the parser handle it */

Thanks\, applied as #18753\, with some tests.

p5pRT commented 21 years ago

@rgs - Status changed from 'open' to 'resolved'