Navigation Menu

Skip to content
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

Undef evaluated to array in some conditions #12758

Closed
p5pRT opened this issue Feb 6, 2013 · 17 comments
Closed

Undef evaluated to array in some conditions #12758

p5pRT opened this issue Feb 6, 2013 · 17 comments

Comments

@p5pRT
Copy link

p5pRT commented Feb 6, 2013

Migrated from rt.perl.org#116665 (status was 'rejected')

Searchable as RT116665$

@p5pRT
Copy link
Author

p5pRT commented Feb 6, 2013

From victor@vsespb.ru

Created by victor@vsespb.ru

<code>
#!/usr/bin/perl

use strict;
use warnings;

my $errors = undef;

sub ok
{
  my( $test, $name ) = @​_;
  print "[[[$test]]] [[[$name]]]\n";
};

ok( ($errors && ($errors->[0] =~ /Journal file not found/i)), "some
text 1 $errors->[0]" );
ok( ($errors && ($errors->[0] =~ /Journal file not found/i)), "some
text 2 $errors->[0]" );
</code>

prints the following​:

<code>
Use of uninitialized value in concatenation (.) or string at poc.pl line 14.
[[[ARRAY(0x137cd48)]]] [[[some text 1 ]]]
Use of uninitialized value in pattern match (m//) at poc.pl line 15.
Use of uninitialized value in concatenation (.) or string at poc.pl line 15.
Use of uninitialized value $name in concatenation (.) or string at
poc.pl line 11.
[[[some text 2 ]]] [[[]]]
</code>

and by the way this code (with modified 'some text' strings)
<code>
#!/usr/bin/perl

use strict;
use warnings;

my $errors = undef;

sub ok
{
  my( $test, $name ) = @​_;
  print "[[[$test]]] [[[$name]]]\n";
};

ok( ($errors && ($errors->[0] =~ /Journal file not found/i)), "some text 1" );
ok( ($errors && ($errors->[0] =~ /Journal file not found/i)), "some text 2" );
</code>

prints correct result​:

<code>
Use of uninitialized value $test in concatenation (.) or string at
poc.pl line 11.
[[[]]] [[[some text 1]]]
Use of uninitialized value $test in concatenation (.) or string at
poc.pl line 11.
[[[]]] [[[some text 2]]]
</code>

perl 5.10.1 under Linux

p.s.
this found when investigating real bug with Test​::Deep/Test​::More

Perl Info

Flags:
    category=core
    severity=high

Site configuration information for perl 5.10.1:

Configured by Debian Project at Tue Nov 27 00:14:30 UTC 2012.

Summary of my perl5 (revision 5 version 10 subversion 1) configuration:

  Platform:
    osname=linux, osvers=2.6.42-23-generic,
archname=x86_64-linux-gnu-thread-multi
    uname='linux komainu 2.6.42-23-generic #36-ubuntu smp tue apr 10
20:39:51 utc 2012 x86_64 gnulinux '
    config_args='-Dusethreads -Duselargefiles -Dccflags=-DDEBIAN
-Dcccdlflags=-fPIC -Darchname=x86_64-linux-gnu -Dprefix=/usr
-Dprivlib=/usr/share/perl/5.10 -Darchlib=/usr/lib/perl/5.10
-Dvendorprefix=/usr -Dvendorlib=/usr/share/perl5
-Dvendorarch=/usr/lib/perl5 -Dsiteprefix=/usr/local
-Dsitelib=/usr/local/share/perl/5.10.1
-Dsitearch=/usr/local/lib/perl/5.10.1 -Dman1dir=/usr/share/man/man1
-Dman3dir=/usr/share/man/man3 -Dsiteman1dir=/usr/local/man/man1
-Dsiteman3dir=/usr/local/man/man3 -Dman1ext=1 -Dman3ext=3perl
-Dpager=/usr/bin/sensible-pager -Uafs -Ud_csh -Ud_ualarm -Uusesfio
-Uusenm -DDEBUGGING=-g -Doptimize=-O2 -Duseshrplib
-Dlibperl=libperl.so.5.10.1 -Dd_dosuid -des'
    hint=recommended, useposix=true, d_sigaction=define
    useithreads=define, usemultiplicity=define
    useperlio=define, d_sfio=undef, uselargefiles=define, usesocks=undef
    use64bitint=define, use64bitall=define, uselongdouble=undef
    usemymalloc=n, bincompat5005=undef
  Compiler:
    cc='cc', ccflags ='-D_REENTRANT -D_GNU_SOURCE -DDEBIAN
-fno-strict-aliasing -pipe -fstack-protector -I/usr/local/include
-D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64',
    optimize='-O2 -g',
    cppflags='-D_REENTRANT -D_GNU_SOURCE -DDEBIAN -fno-strict-aliasing
-pipe -fstack-protector -I/usr/local/include'
    ccversion='', gccversion='4.4.3', gccosandvers=''
    intsize=4, longsize=8, ptrsize=8, doublesize=8, byteorder=12345678
    d_longlong=define, longlongsize=8, d_longdbl=define, longdblsize=16
    ivtype='long', ivsize=8, nvtype='double', nvsize=8, Off_t='off_t',
lseeksize=8
    alignbytes=8, prototype=define
  Linker and Libraries:
    ld='cc', ldflags =' -fstack-protector -L/usr/local/lib'
    libpth=/usr/local/lib /lib /usr/lib /lib64 /usr/lib64
    libs=-lgdbm -lgdbm_compat -ldb -ldl -lm -lpthread -lc -lcrypt
    perllibs=-ldl -lm -lpthread -lc -lcrypt
    libc=/lib/libc-2.11.1.so, so=so, useshrplib=true, libperl=libperl.so.5.10.1
    gnulibc_version='2.11.1'
  Dynamic Linking:
    dlsrc=dl_dlopen.xs, dlext=so, d_dlsymun=undef, ccdlflags='-Wl,-E'
    cccdlflags='-fPIC', lddlflags='-shared -O2 -g -L/usr/local/lib
-fstack-protector'

Locally applied patches:



@INC for perl 5.10.1:
    /etc/perl
    /usr/local/lib/perl/5.10.1
    /usr/local/share/perl/5.10.1
    /usr/lib/perl5
    /usr/share/perl5
    /usr/lib/perl/5.10
    /usr/share/perl/5.10
    /usr/local/lib/site_perl
    .


Environment for perl 5.10.1:
    HOME=/root
    LANG=ru_RU.utf8
    LANGUAGE=en_US:en
    LC_MESSAGES=en_US.UTF-8
    LD_LIBRARY_PATH (unset)
    LOGDIR (unset)
    PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games
    PERL_BADLANG (unset)
    SHELL=/bin/bash

@p5pRT
Copy link
Author

p5pRT commented Feb 6, 2013

From victor@vsespb.ru

This was autovivification, I didn't realized that it happens on
read-only access. Ticket invalid.

On Wed Feb 06 03​:52​:03 2013, vsespb wrote​:

This is a bug report for perl from victor@​vsespb.ru,
generated with the help of perlbug 1.39 running under perl 5.10.1.

-----------------------------------------------------------------
[Please describe your issue here]

<code>
#!/usr/bin/perl

use strict;
use warnings;

my $errors = undef;

sub ok
{
my( $test, $name ) = @​_;
print "[[[$test]]] [[[$name]]]\n";
};

ok( ($errors && ($errors->[0] =~ /Journal file not found/i)), "some
text 1 $errors->[0]" );
ok( ($errors && ($errors->[0] =~ /Journal file not found/i)), "some
text 2 $errors->[0]" );
</code>

prints the following​:

<code>
Use of uninitialized value in concatenation (.) or string at poc.pl
line 14.
[[[ARRAY(0x137cd48)]]] [[[some text 1 ]]]
Use of uninitialized value in pattern match (m//) at poc.pl line 15.
Use of uninitialized value in concatenation (.) or string at poc.pl
line 15.
Use of uninitialized value $name in concatenation (.) or string at
poc.pl line 11.
[[[some text 2 ]]] [[[]]]
</code>

and by the way this code (with modified 'some text' strings)
<code>
#!/usr/bin/perl

use strict;
use warnings;

my $errors = undef;

sub ok
{
my( $test, $name ) = @​_;
print "[[[$test]]] [[[$name]]]\n";
};

ok( ($errors && ($errors->[0] =~ /Journal file not found/i)), "some
text 1" );
ok( ($errors && ($errors->[0] =~ /Journal file not found/i)), "some
text 2" );
</code>

prints correct result​:

<code>
Use of uninitialized value $test in concatenation (.) or string at
poc.pl line 11.
[[[]]] [[[some text 1]]]
Use of uninitialized value $test in concatenation (.) or string at
poc.pl line 11.
[[[]]] [[[some text 2]]]
</code>

perl 5.10.1 under Linux

p.s.
this found when investigating real bug with Test​::Deep/Test​::More

[Please do not change anything below this line]
-----------------------------------------------------------------
---
Flags​:
category=core
severity=high
---
Site configuration information for perl 5.10.1​:

Configured by Debian Project at Tue Nov 27 00​:14​:30 UTC 2012.

Summary of my perl5 (revision 5 version 10 subversion 1)
configuration​:

Platform​:
osname=linux, osvers=2.6.42-23-generic,
archname=x86_64-linux-gnu-thread-multi
uname='linux komainu 2.6.42-23-generic #36-ubuntu smp tue apr 10
20​:39​:51 utc 2012 x86_64 gnulinux '
config_args='-Dusethreads -Duselargefiles -Dccflags=-DDEBIAN
-Dcccdlflags=-fPIC -Darchname=x86_64-linux-gnu -Dprefix=/usr
-Dprivlib=/usr/share/perl/5.10 -Darchlib=/usr/lib/perl/5.10
-Dvendorprefix=/usr -Dvendorlib=/usr/share/perl5
-Dvendorarch=/usr/lib/perl5 -Dsiteprefix=/usr/local
-Dsitelib=/usr/local/share/perl/5.10.1
-Dsitearch=/usr/local/lib/perl/5.10.1 -Dman1dir=/usr/share/man/man1
-Dman3dir=/usr/share/man/man3 -Dsiteman1dir=/usr/local/man/man1
-Dsiteman3dir=/usr/local/man/man3 -Dman1ext=1 -Dman3ext=3perl
-Dpager=/usr/bin/sensible-pager -Uafs -Ud_csh -Ud_ualarm -Uusesfio
-Uusenm -DDEBUGGING=-g -Doptimize=-O2 -Duseshrplib
-Dlibperl=libperl.so.5.10.1 -Dd_dosuid -des'
hint=recommended, useposix=true, d_sigaction=define
useithreads=define, usemultiplicity=define
useperlio=define, d_sfio=undef, uselargefiles=define,
usesocks=undef
use64bitint=define, use64bitall=define, uselongdouble=undef
usemymalloc=n, bincompat5005=undef
Compiler​:
cc='cc', ccflags ='-D_REENTRANT -D_GNU_SOURCE -DDEBIAN
-fno-strict-aliasing -pipe -fstack-protector -I/usr/local/include
-D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64',
optimize='-O2 -g',
cppflags='-D_REENTRANT -D_GNU_SOURCE -DDEBIAN -fno-strict-aliasing
-pipe -fstack-protector -I/usr/local/include'
ccversion='', gccversion='4.4.3', gccosandvers=''
intsize=4, longsize=8, ptrsize=8, doublesize=8, byteorder=12345678
d_longlong=define, longlongsize=8, d_longdbl=define,
longdblsize=16
ivtype='long', ivsize=8, nvtype='double', nvsize=8, Off_t='off_t',
lseeksize=8
alignbytes=8, prototype=define
Linker and Libraries​:
ld='cc', ldflags =' -fstack-protector -L/usr/local/lib'
libpth=/usr/local/lib /lib /usr/lib /lib64 /usr/lib64
libs=-lgdbm -lgdbm_compat -ldb -ldl -lm -lpthread -lc -lcrypt
perllibs=-ldl -lm -lpthread -lc -lcrypt
libc=/lib/libc-2.11.1.so, so=so, useshrplib=true,
libperl=libperl.so.5.10.1
gnulibc_version='2.11.1'
Dynamic Linking​:
dlsrc=dl_dlopen.xs, dlext=so, d_dlsymun=undef, ccdlflags='-Wl,-E'
cccdlflags='-fPIC', lddlflags='-shared -O2 -g -L/usr/local/lib
-fstack-protector'

Locally applied patches​:

---
@​INC for perl 5.10.1​:
/etc/perl
/usr/local/lib/perl/5.10.1
/usr/local/share/perl/5.10.1
/usr/lib/perl5
/usr/share/perl5
/usr/lib/perl/5.10
/usr/share/perl/5.10
/usr/local/lib/site_perl
.

---
Environment for perl 5.10.1​:
HOME=/root
LANG=ru_RU.utf8
LANGUAGE=en_US​:en
LC_MESSAGES=en_US.UTF-8
LD_LIBRARY_PATH (unset)
LOGDIR (unset)

PATH=/usr/local/sbin​:/usr/local/bin​:/usr/sbin​:/usr/bin​:/sbin​:/bin​:/usr/games

PERL\_BADLANG \(unset\)
SHELL=/bin/bash

@p5pRT
Copy link
Author

p5pRT commented Feb 6, 2013

victor@vsespb.ru - Status changed from 'new' to 'rejected'

@p5pRT
Copy link
Author

p5pRT commented Feb 6, 2013

From @demerphq

On 6 February 2013 13​:01, Victor Efimov via RT
<perlbug-followup@​perl.org> wrote​:

This was autovivification, I didn't realized that it happens on
read-only access. Ticket invalid.

Note also that your code ends up returning an empty list in some cases
as the first argument, which causes the test name to be returned as
the first argument instead of the second.

Yves

--
perl -Mre=debug -e "/just|another|perl|hacker/"

@p5pRT
Copy link
Author

p5pRT commented Feb 6, 2013

From victor@vsespb.ru

Ok,

1st issue - autovivification
2nd issue - 1st expression evaluated to empty list sometimes. OK. fine.

that two issues not a bug in perl, but bugs in code.

but what about this​:

#!/usr/bin/perl

use strict;
use warnings;

my $errors = undef;

sub ok
{
  my( $test, $name ) = @​_;
  print "[[[$test]]] [[[$name]]]\n";
};

$errors->[0];
ok(($errors && ($errors->[0] =~ /Journal file not found/i)), "some text
$errors->[0]" );

prints

[[[some text ]]] [[[]]]

and

#!/usr/bin/perl

use strict;
use warnings;

my $errors = undef;

sub ok
{
  my( $test, $name ) = @​_;
  print "[[[$test]]] [[[$name]]]\n";
};

ok(($errors && ($errors->[0] =~ /Journal file not found/i)), "some text
$errors->[0]" );

prints

[[[ARRAY(0xa89d48)]]] [[[some text ]]]

how come first argument become an array ? First argument should be TRUE
expression only if $errors->[0] contains /Journal file not found/i

On Wed Feb 06 04​:05​:40 2013, demerphq wrote​:

On 6 February 2013 13​:01, Victor Efimov via RT
<perlbug-followup@​perl.org> wrote​:

This was autovivification, I didn't realized that it happens on
read-only access. Ticket invalid.

Note also that your code ends up returning an empty list in some cases
as the first argument, which causes the test name to be returned as
the first argument instead of the second.

Yves

@p5pRT
Copy link
Author

p5pRT commented Feb 6, 2013

victor@vsespb.ru - Status changed from 'rejected' to 'new'

@p5pRT
Copy link
Author

p5pRT commented Feb 6, 2013

From @demerphq

On 6 February 2013 13​:23, Victor Efimov via RT
<perlbug-followup@​perl.org> wrote​:

Ok,

1st issue - autovivification
2nd issue - 1st expression evaluated to empty list sometimes. OK. fine.

that two issues not a bug in perl, but bugs in code.

but what about this​:

#!/usr/bin/perl

use strict;
use warnings;

my $errors = undef;

sub ok
{
my( $test, $name ) = @​_;
print "[[[$test]]] [[[$name]]]\n";
};

$errors->[0];
ok(($errors && ($errors->[0] =~ /Journal file not found/i)), "some text
$errors->[0]" );

prints

[[[some text ]]] [[[]]]

and

#!/usr/bin/perl

use strict;
use warnings;

my $errors = undef;

sub ok
{
my( $test, $name ) = @​_;
print "[[[$test]]] [[[$name]]]\n";
};

ok(($errors && ($errors->[0] =~ /Journal file not found/i)), "some text
$errors->[0]" );

prints

[[[ARRAY(0xa89d48)]]] [[[some text ]]]

how come first argument become an array ? First argument should be TRUE
expression only if $errors->[0] contains /Journal file not found/i

Part of it is left to right evaluation of the arguments to ok().
$errors && (....) is evaluated before "text $errors->[0]", the latter
autovivifies, but when $errors is evaluated in the first expression it
is still undef. When you autovivify first (the $errors->[0]) then
$errors is true before the statement is evaluated.

If $errors is false, then the && operator returns the value of $errors
and the first argument will be its value. (This is the first code you
pasted).

If $errors is true then the && operator returns the value returned by
$errors->[0]=~/Journal file not found/, which is the empty list, which
in turn means that the item after the expression, the "name", becomes
the first argument. (This is the second code you pasted).

What you seem to be missing is that the match is done in _list_ context.

If you changed the expression to​:

ok(($errors && (scalar $errors->[0] =~ /Journal file not found/i)),
"some text 1 $errors->[0]" );

You would get the behavior you expect. Similarly if you changed the
ok() function to be​:

sub ok($;$)
{
  my( $test, $name ) = @​_;
  print "[[[$test]]] [[[$name]]]\n";
};

Which is the prototype that Test​::More​::ok() uses then you would not
need the scalar() call.

cheers,
Yves

--
perl -Mre=debug -e "/just|another|perl|hacker/"

@p5pRT
Copy link
Author

p5pRT commented Feb 6, 2013

The RT System itself - Status changed from 'new' to 'open'

@p5pRT
Copy link
Author

p5pRT commented Feb 6, 2013

From victor@vsespb.ru

#!/usr/bin/perl

use strict;
use warnings;

my $errors = undef;

sub ok($;$)
{
  my( $test, $name ) = @​_;
  print "[[[$test]]] [[[$name]]]\n";
};
# $errors->[0];
ok(($errors && (scalar $errors->[0] =~ /Journal file not found/i)),
"some text 1 $errors->[0]" );
__END__

still prints
[[[ARRAY(0x1120d48)]]] [[[some text 1 ]]]

On Wed Feb 06 04​:46​:11 2013, demerphq wrote​:

On 6 February 2013 13​:23, Victor Efimov via RT
<perlbug-followup@​perl.org> wrote​:

Ok,

1st issue - autovivification
2nd issue - 1st expression evaluated to empty list sometimes. OK. fine.

that two issues not a bug in perl, but bugs in code.

but what about this​:

#!/usr/bin/perl

use strict;
use warnings;

my $errors = undef;

sub ok
{
my( $test, $name ) = @​_;
print "[[[$test]]] [[[$name]]]\n";
};

$errors->[0];
ok(($errors && ($errors->[0] =~ /Journal file not found/i)), "some text
$errors->[0]" );

prints

[[[some text ]]] [[[]]]

and

#!/usr/bin/perl

use strict;
use warnings;

my $errors = undef;

sub ok
{
my( $test, $name ) = @​_;
print "[[[$test]]] [[[$name]]]\n";
};

ok(($errors && ($errors->[0] =~ /Journal file not found/i)), "some text
$errors->[0]" );

prints

[[[ARRAY(0xa89d48)]]] [[[some text ]]]

how come first argument become an array ? First argument should be TRUE
expression only if $errors->[0] contains /Journal file not found/i

Part of it is left to right evaluation of the arguments to ok().
$errors && (....) is evaluated before "text $errors->[0]", the latter
autovivifies, but when $errors is evaluated in the first expression it
is still undef. When you autovivify first (the $errors->[0]) then
$errors is true before the statement is evaluated.

If $errors is false, then the && operator returns the value of $errors
and the first argument will be its value. (This is the first code you
pasted).

If $errors is true then the && operator returns the value returned by
$errors->[0]=~/Journal file not found/, which is the empty list, which
in turn means that the item after the expression, the "name", becomes
the first argument. (This is the second code you pasted).

What you seem to be missing is that the match is done in _list_ context.

If you changed the expression to​:

ok(($errors && (scalar $errors->[0] =~ /Journal file not found/i)),
"some text 1 $errors->[0]" );

You would get the behavior you expect. Similarly if you changed the
ok() function to be​:

sub ok($;$)
{
my( $test, $name ) = @​_;
print "[[[$test]]] [[[$name]]]\n";
};

Which is the prototype that Test​::More​::ok() uses then you would not
need the scalar() call.

cheers,
Yves

@p5pRT
Copy link
Author

p5pRT commented Feb 6, 2013

From victor@vsespb.ru

Seems people found solution

http​://www.perlmonks.org/?node_id=1017413
http​://www.perlmonks.org/?node_id=1017408

On Wed Feb 06 04​:54​:07 2013, vsespb wrote​:

#!/usr/bin/perl

use strict;
use warnings;

my $errors = undef;

sub ok($;$)
{
my( $test, $name ) = @​_;
print "[[[$test]]] [[[$name]]]\n";
};
# $errors->[0];
ok(($errors && (scalar $errors->[0] =~ /Journal file not found/i)),
"some text 1 $errors->[0]" );
__END__

still prints
[[[ARRAY(0x1120d48)]]] [[[some text 1 ]]]

On Wed Feb 06 04​:46​:11 2013, demerphq wrote​:

On 6 February 2013 13​:23, Victor Efimov via RT
<perlbug-followup@​perl.org> wrote​:

Ok,

1st issue - autovivification
2nd issue - 1st expression evaluated to empty list sometimes. OK.
fine.

that two issues not a bug in perl, but bugs in code.

but what about this​:

#!/usr/bin/perl

use strict;
use warnings;

my $errors = undef;

sub ok
{
my( $test, $name ) = @​_;
print "[[[$test]]] [[[$name]]]\n";
};

$errors->[0];
ok(($errors && ($errors->[0] =~ /Journal file not found/i)), "some
text
$errors->[0]" );

prints

[[[some text ]]] [[[]]]

and

#!/usr/bin/perl

use strict;
use warnings;

my $errors = undef;

sub ok
{
my( $test, $name ) = @​_;
print "[[[$test]]] [[[$name]]]\n";
};

ok(($errors && ($errors->[0] =~ /Journal file not found/i)), "some
text
$errors->[0]" );

prints

[[[ARRAY(0xa89d48)]]] [[[some text ]]]

how come first argument become an array ? First argument should be
TRUE
expression only if $errors->[0] contains /Journal file not found/i

Part of it is left to right evaluation of the arguments to ok().
$errors && (....) is evaluated before "text $errors->[0]", the latter
autovivifies, but when $errors is evaluated in the first expression it
is still undef. When you autovivify first (the $errors->[0]) then
$errors is true before the statement is evaluated.

If $errors is false, then the && operator returns the value of $errors
and the first argument will be its value. (This is the first code you
pasted).

If $errors is true then the && operator returns the value returned by
$errors->[0]=~/Journal file not found/, which is the empty list, which
in turn means that the item after the expression, the "name", becomes
the first argument. (This is the second code you pasted).

What you seem to be missing is that the match is done in _list_ context.

If you changed the expression to​:

ok(($errors && (scalar $errors->[0] =~ /Journal file not found/i)),
"some text 1 $errors->[0]" );

You would get the behavior you expect. Similarly if you changed the
ok() function to be​:

sub ok($;$)
{
my( $test, $name ) = @​_;
print "[[[$test]]] [[[$name]]]\n";
};

Which is the prototype that Test​::More​::ok() uses then you would not
need the scalar() call.

cheers,
Yves

@p5pRT
Copy link
Author

p5pRT commented Feb 6, 2013

From victor@vsespb.ru

shortest PoC is

perl -e 'sub a($$) { print "[$_]\n" for @​_}; my $x = undef; a($x &&
$x->[0] =~ /abc/, $x = [])'
[ARRAY(0x12c1d48)]
[ARRAY(0x12c1d48)]

perl -e 'sub a($$) { print "[$_]\n" for @​_}; my $x = undef; $x=[]; a($x
&& $x->[0] =~ /abc/, $x = [])'
[]
[ARRAY(0x24d7f58)]

I don't know guys, if this intended behaviour or no, or maybe not
documented behaviour, or it's absolutely ok. not sure.

however, for example in Ruby

ruby -e 'def a(i,j); puts "Z #{i} Z #{j} Z"; end; x=nil; a(x && x[0] =~
/abc/, x = [])'

ruby -e 'def a(i,j); puts "Z #{i} Z #{j} Z"; end; x=nil; x=[]; a(x &&
x[0] =~ /abc/, x = [])'

both print

Z Z [] Z

On Wed Feb 06 06​:59​:44 2013, vsespb wrote​:

Seems people found solution

http​://www.perlmonks.org/?node_id=1017413
http​://www.perlmonks.org/?node_id=1017408

On Wed Feb 06 04​:54​:07 2013, vsespb wrote​:

#!/usr/bin/perl

use strict;
use warnings;

my $errors = undef;

sub ok($;$)
{
my( $test, $name ) = @​_;
print "[[[$test]]] [[[$name]]]\n";
};
# $errors->[0];
ok(($errors && (scalar $errors->[0] =~ /Journal file not found/i)),
"some text 1 $errors->[0]" );
__END__

still prints
[[[ARRAY(0x1120d48)]]] [[[some text 1 ]]]

On Wed Feb 06 04​:46​:11 2013, demerphq wrote​:

On 6 February 2013 13​:23, Victor Efimov via RT
<perlbug-followup@​perl.org> wrote​:

Ok,

1st issue - autovivification
2nd issue - 1st expression evaluated to empty list sometimes. OK.
fine.

that two issues not a bug in perl, but bugs in code.

but what about this​:

#!/usr/bin/perl

use strict;
use warnings;

my $errors = undef;

sub ok
{
my( $test, $name ) = @​_;
print "[[[$test]]] [[[$name]]]\n";
};

$errors->[0];
ok(($errors && ($errors->[0] =~ /Journal file not found/i)), "some
text
$errors->[0]" );

prints

[[[some text ]]] [[[]]]

and

#!/usr/bin/perl

use strict;
use warnings;

my $errors = undef;

sub ok
{
my( $test, $name ) = @​_;
print "[[[$test]]] [[[$name]]]\n";
};

ok(($errors && ($errors->[0] =~ /Journal file not found/i)), "some
text
$errors->[0]" );

prints

[[[ARRAY(0xa89d48)]]] [[[some text ]]]

how come first argument become an array ? First argument should be
TRUE
expression only if $errors->[0] contains /Journal file not found/i

Part of it is left to right evaluation of the arguments to ok().
$errors && (....) is evaluated before "text $errors->[0]", the latter
autovivifies, but when $errors is evaluated in the first expression it
is still undef. When you autovivify first (the $errors->[0]) then
$errors is true before the statement is evaluated.

If $errors is false, then the && operator returns the value of $errors
and the first argument will be its value. (This is the first code you
pasted).

If $errors is true then the && operator returns the value returned by
$errors->[0]=~/Journal file not found/, which is the empty list, which
in turn means that the item after the expression, the "name", becomes
the first argument. (This is the second code you pasted).

What you seem to be missing is that the match is done in _list_
context.

If you changed the expression to​:

ok(($errors && (scalar $errors->[0] =~ /Journal file not found/i)),
"some text 1 $errors->[0]" );

You would get the behavior you expect. Similarly if you changed the
ok() function to be​:

sub ok($;$)
{
my( $test, $name ) = @​_;
print "[[[$test]]] [[[$name]]]\n";
};

Which is the prototype that Test​::More​::ok() uses then you would not
need the scalar() call.

cheers,
Yves

@p5pRT
Copy link
Author

p5pRT commented Feb 6, 2013

From @demerphq

On 6 February 2013 13​:54, Victor Efimov via RT
<perlbug-followup@​perl.org> wrote​:

#!/usr/bin/perl

use strict;
use warnings;

my $errors = undef;

sub ok($;$)
{
my( $test, $name ) = @​_;
print "[[[$test]]] [[[$name]]]\n";
};
# $errors->[0];
ok(($errors && (scalar $errors->[0] =~ /Journal file not found/i)),
"some text 1 $errors->[0]" );
__END__

still prints
[[[ARRAY(0x1120d48)]]] [[[some text 1 ]]]

AH, interesting, so the $errors->[0] in the string autovivifies
$errors, which is on the call stack so it is visible to the ok() sub.

But you seem to have missed the point with scalar/($;$).

The use of scalar and ($;$) is to get consistent results *regardless*
of whether the $errors value is defined or not.

Take a look at this output

use strict;
use warnings;
no warnings 'uninitialized';

sub ok {
  my( $test, $name ) = @​_;
  print "[[[$test]]] [[[$name]]]\n";
};

sub ok_proto($;$) {
  my( $test, $name ) = @​_;
  print "[[[$test]]] [[[$name]]]\n";
};

for my $val (undef, []) {
  print "Value​: ", defined $val ? $val : "undef", "\n";
  my $errors= $val;
  ok(($errors && ($errors->[0] =~ /Journal file not found/i)), "ok()
no scalar" );

  $errors= $val;
  ok_proto(($errors && ($errors->[0] =~ /Journal file not found/i)),
"ok_proto() no scalar" );

  $errors= $val;
  ok(($errors && (scalar($errors->[0] =~ /Journal file not
found/i))), "ok() with scalar" );

  $errors= $val;
  ok_proto(($errors && (scalar($errors->[0] =~ /Journal file not
found/i))), "ok_proto() with scalar" );

}
__END__
Value​: undef
[[[]]] [[[ok() no scalar]]]
[[[]]] [[[ok_proto() no scalar]]]
[[[]]] [[[ok() with scalar]]]
[[[]]] [[[ok_proto() with scalar]]]
Value​: ARRAY(0xfafd80)
[[[ok() no scalar]]] [[[]]]
[[[]]] [[[ok_proto() no scalar]]]
[[[]]] [[[ok() with scalar]]]
[[[]]] [[[ok_proto() with scalar]]]

--
perl -Mre=debug -e "/just|another|perl|hacker/"

@p5pRT
Copy link
Author

p5pRT commented Feb 6, 2013

From @demerphq

On 6 February 2013 16​:45, Victor Efimov via RT
<perlbug-followup@​perl.org> wrote​:

shortest PoC is

perl -e 'sub a($$) { print "[$_]\n" for @​_}; my $x = undef; a($x &&
$x->[0] =~ /abc/, $x = [])'
[ARRAY(0x12c1d48)]
[ARRAY(0x12c1d48)]

perl -e 'sub a($$) { print "[$_]\n" for @​_}; my $x = undef; $x=[]; a($x
&& $x->[0] =~ /abc/, $x = [])'
[]
[ARRAY(0x24d7f58)]

I don't know guys, if this intended behaviour or no, or maybe not
documented behaviour, or it's absolutely ok. not sure.

This is absolutely expected behavior and is exactly what I was trying
to explain and have already explained. The $$ protoype coerces scalar
context on the expression​: $x && $x->[0]=~/abc/. If you took off the
($$) it would be called in list context and it would work like the
buggy code you posted earlier.

I dont know if ruby has such a thing as context, I suspect not, so
maybe you should read up on list and scalar context.

You probably should also read up on autovivification.

And you should probably read up on prototypes.

And you should read up on the aliasing of arguments to perl.

And, IMO you should refrain from filing any perl bugs until you have
validated them through Perlmonks first.

To be honest you are already in the "long grass" here, and probably
should stick to simple constructs until you have mastered the above
concepts.

Yves

--
perl -Mre=debug -e "/just|another|perl|hacker/"

@p5pRT
Copy link
Author

p5pRT commented Feb 6, 2013

From victor@vsespb.ru

2demerphq,

This I understood

1) subroutine arguments (without proto) are eveluated in list context
perl -e 'sub a { print wantarray}; sub b {}; b(a())' prints 1 and perl
-e 'sub a { print wantarray}; sub b($){}; b(a())' prints empty string
2) regexp =~ operator returns empty list in list context​: perl -e '$x=4;
my @​a= $x =~ /abc/; print $#a' prints -1; and perl -e '$x=4; my @​a=
scalar $x =~ /abc/; print $#a' prints 0

but my last message NOT related to autovivification (there is NO
autovivification) nor to list vs scalar contexts (scalar context
enforsed in both examples).

On Wed Feb 06 08​:03​:27 2013, demerphq wrote​:

On 6 February 2013 16​:45, Victor Efimov via RT
<perlbug-followup@​perl.org> wrote​:

shortest PoC is

perl -e 'sub a($$) { print "[$_]\n" for @​_}; my $x = undef; a($x &&
$x->[0] =~ /abc/, $x = [])'
[ARRAY(0x12c1d48)]
[ARRAY(0x12c1d48)]

perl -e 'sub a($$) { print "[$_]\n" for @​_}; my $x = undef; $x=[]; a($x
&& $x->[0] =~ /abc/, $x = [])'
[]
[ARRAY(0x24d7f58)]

I don't know guys, if this intended behaviour or no, or maybe not
documented behaviour, or it's absolutely ok. not sure.

This is absolutely expected behavior and is exactly what I was trying
to explain and have already explained. The $$ protoype coerces scalar
context on the expression​: $x && $x->[0]=~/abc/. If you took off the
($$) it would be called in list context and it would work like the
buggy code you posted earlier.

I dont know if ruby has such a thing as context, I suspect not, so
maybe you should read up on list and scalar context.

You probably should also read up on autovivification.

And you should probably read up on prototypes.

And you should read up on the aliasing of arguments to perl.

And, IMO you should refrain from filing any perl bugs until you have
validated them through Perlmonks first.

To be honest you are already in the "long grass" here, and probably
should stick to simple constructs until you have mastered the above
concepts.

Yves

@p5pRT
Copy link
Author

p5pRT commented Feb 6, 2013

From @doy

On Wed, Feb 06, 2013 at 07​:45​:45AM -0800, Victor Efimov via RT wrote​:

shortest PoC is

perl -e 'sub a($$) { print "[$_]\n" for @​_}; my $x = undef; a($x &&
$x->[0] =~ /abc/, $x = [])'
[ARRAY(0x12c1d48)]
[ARRAY(0x12c1d48)]

Here, $x is false, so "$x && ..." evaluates to just $x, and so the first
parameter is an alias to $x. Then the second parameter is evaluated,
which assigns [] to $x, so the first parameter sees $x as an arrayref.

perl -e 'sub a($$) { print "[$_]\n" for @​_}; my $x = undef; $x=[]; a($x
&& $x->[0] =~ /abc/, $x = [])'
[]
[ARRAY(0x24d7f58)]

Here, $x is not false, so "$x && $x->[0] =~ /abc/" evaluates to
"$x->[0] =~ /abc/", which is an unrelated false value. Assigning [] to
$x in the second argument therefore doesn't affect it at all.

I don't know guys, if this intended behaviour or no, or maybe not
documented behaviour, or it's absolutely ok. not sure.

however, for example in Ruby

ruby -e 'def a(i,j); puts "Z #{i} Z #{j} Z"; end; x=nil; a(x && x[0] =~
/abc/, x = [])'

ruby -e 'def a(i,j); puts "Z #{i} Z #{j} Z"; end; x=nil; x=[]; a(x &&
x[0] =~ /abc/, x = [])'

both print

Z Z [] Z

There are several potential explanations here, relating to differences
in Ruby's execution model as compared to Perl. It's possible that Ruby
passes all subroutine arguments as copies instead of aliases (like Perl
does), or that Ruby evaluates subroutine arguments from right to left
instead of left to right. Demonstrating that other languages do things
differently doesn't really mean anything.

-doy

@p5pRT
Copy link
Author

p5pRT commented Feb 6, 2013

From victor@vsespb.ru

Ok, thanks.

On Wed Feb 06 08​:19​:45 2013, doy@​tozt.net wrote​:

On Wed, Feb 06, 2013 at 07​:45​:45AM -0800, Victor Efimov via RT wrote​:

shortest PoC is

perl -e 'sub a($$) { print "[$_]\n" for @​_}; my $x = undef; a($x &&
$x->[0] =~ /abc/, $x = [])'
[ARRAY(0x12c1d48)]
[ARRAY(0x12c1d48)]

Here, $x is false, so "$x && ..." evaluates to just $x, and so the first
parameter is an alias to $x. Then the second parameter is evaluated,
which assigns [] to $x, so the first parameter sees $x as an arrayref.

perl -e 'sub a($$) { print "[$_]\n" for @​_}; my $x = undef; $x=[]; a($x
&& $x->[0] =~ /abc/, $x = [])'
[]
[ARRAY(0x24d7f58)]

Here, $x is not false, so "$x && $x->[0] =~ /abc/" evaluates to
"$x->[0] =~ /abc/", which is an unrelated false value. Assigning [] to
$x in the second argument therefore doesn't affect it at all.

I don't know guys, if this intended behaviour or no, or maybe not
documented behaviour, or it's absolutely ok. not sure.

however, for example in Ruby

ruby -e 'def a(i,j); puts "Z #{i} Z #{j} Z"; end; x=nil; a(x && x[0] =~
/abc/, x = [])'

ruby -e 'def a(i,j); puts "Z #{i} Z #{j} Z"; end; x=nil; x=[]; a(x &&
x[0] =~ /abc/, x = [])'

both print

Z Z [] Z

There are several potential explanations here, relating to differences
in Ruby's execution model as compared to Perl. It's possible that Ruby
passes all subroutine arguments as copies instead of aliases (like Perl
does), or that Ruby evaluates subroutine arguments from right to left
instead of left to right. Demonstrating that other languages do things
differently doesn't really mean anything.

-doy

@p5pRT
Copy link
Author

p5pRT commented Feb 6, 2013

victor@vsespb.ru - Status changed from 'open' to 'rejected'

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant