Skip Menu |
Report information
Id: 132729
Status: open
Priority: 0/
Queue: perl5

Owner: Nobody
Requestors: zefram [at] fysh.org
Cc:
AdminCc:

Operating System: (no value)
PatchStatus: (no value)
Severity: low
Type: core
Perl Version: 5.27.7
Fixed In: (no value)



CC: zefram [...] fysh.org
To: perlbug [...] perl.org
Subject: array element lazily created at wrong index
Date: Wed, 17 Jan 2018 00:42:11 +0000
From: zefram [...] fysh.org
Download (untitled) / with headers
text/plain 5.1k
This is a bug report for perl from zefram@fysh.org, generated with the help of perlbug 1.41 running under perl 5.27.7. ----------------------------------------------------------------- [Please describe your issue here] Simple test case for some array operations: $ perl -lwe '$a[0] = undef; $a[1] = 1; sub foo { unshift @a, 7; $_[0] = 3; } foo($a[0]); print map { $_ // "u" } @a;' 731 The above works as expected. Note that the sub call aliases $_[0] to the original $a[0], and that aliasing holds through the unshift. After unshift, that element is now $a[1], and an assignment to it is made successfully through the $_[0] alias. But if the initial $a[0] isn't explicitly initialised, this goes awry: $ perl -lwe '$a[1] = 1; sub foo { unshift @a, 7; $_[0] = 3; } foo($a[0]); print map { $_ // "u" } @a;' 3u1 This time, $_[0] after the unshift is aliasing the *new* $a[0], which didn't exist to be aliased at the time the sub call set up the alias. The lazy element creation is being too lazy, deferring resolution of the array index until it's too late. The same effect can be seen by using foreach(@a) to set up an alias: $ perl -lwe '$a[0] = undef; $a[1] = 1; foreach(@a) { unshift @a, 7; $_ = 3; last; } print map { $_ // "u" } @a;' 731 $ perl -lwe '$a[1] = 1; foreach(@a) { unshift @a, 7; $_ = 3; last; } print map { $_ // "u" } @a;' 3u1 The documentation for foreach has a caveat about it getting confused if one modifies an array being iterated over, which might apply to this, but I don't think this is really in the spirit of the caveat. This isn't really foreach getting confused; the iteration logic isn't actually being invoked after the array modification. It's the element alias that's getting confused, and one might expect that to be a bit more robust. In any case, there's no such caveat for sub calling, and if it's a bug there then that suggests that the same behaviour would be a bug for foreach too. [Please do not change anything below this line] ----------------------------------------------------------------- --- Flags: category=core severity=low --- Site configuration information for perl 5.27.7: Configured by zefram at Thu Dec 21 04:41:17 GMT 2017. Summary of my perl5 (revision 5 version 27 subversion 7) configuration: Platform: osname=linux osvers=3.16.0-4-amd64 archname=x86_64-linux-thread-multi uname='linux barba.rous.org 3.16.0-4-amd64 #1 smp debian 3.16.43-2+deb8u2 (2017-06-26) x86_64 gnulinux ' config_args='-des -Dprefix=/home/zefram/usr/perl/perl_install/perl-5.27.7-i64-f52 -Duselargefiles -Dusethreads -Uafs -Ud_csh -Uusesfio -Uusenm -Duseshrplib -Dusedevel -Uversiononly -Ui_db' hint=recommended useposix=true d_sigaction=define useithreads=define usemultiplicity=define use64bitint=define use64bitall=define uselongdouble=undef usemymalloc=n default_inc_excludes_dot=define bincompat5005=undef Compiler: cc='cc' ccflags ='-D_REENTRANT -D_GNU_SOURCE -fwrapv -fno-strict-aliasing -pipe -fstack-protector-strong -I/usr/local/include -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -D_FORTIFY_SOURCE=2' optimize='-O2' cppflags='-D_REENTRANT -D_GNU_SOURCE -fwrapv -fno-strict-aliasing -pipe -fstack-protector-strong -I/usr/local/include' ccversion='' gccversion='4.9.2' gccosandvers='' intsize=4 longsize=8 ptrsize=8 doublesize=8 byteorder=12345678 doublekind=3 d_longlong=define longlongsize=8 d_longdbl=define longdblsize=16 longdblkind=3 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-strong -L/usr/local/lib' libpth=/usr/local/lib /usr/lib/gcc/x86_64-linux-gnu/4.9/include-fixed /usr/include/x86_64-linux-gnu /usr/lib /lib/x86_64-linux-gnu /lib/../lib /usr/lib/x86_64-linux-gnu /usr/lib/../lib /lib libs=-lpthread -lnsl -lgdbm -ldb -ldl -lm -lcrypt -lutil -lc -lgdbm_compat perllibs=-lpthread -lnsl -ldl -lm -lcrypt -lutil -lc libc=libc-2.19.so so=so useshrplib=true libperl=libperl.so gnulibc_version='2.19' Dynamic Linking: dlsrc=dl_dlopen.xs dlext=so d_dlsymun=undef ccdlflags='-Wl,-E -Wl,-rpath,/home/zefram/usr/perl/perl_install/perl-5.27.7-i64-f52/lib/5.27.7/x86_64-linux-thread-multi/CORE' cccdlflags='-fPIC' lddlflags='-shared -O2 -L/usr/local/lib -fstack-protector-strong' --- @INC for perl 5.27.7: /home/zefram/usr/perl/perl_install/perl-5.27.7-i64-f52/lib/site_perl/5.27.7/x86_64-linux-thread-multi /home/zefram/usr/perl/perl_install/perl-5.27.7-i64-f52/lib/site_perl/5.27.7 /home/zefram/usr/perl/perl_install/perl-5.27.7-i64-f52/lib/5.27.7/x86_64-linux-thread-multi /home/zefram/usr/perl/perl_install/perl-5.27.7-i64-f52/lib/5.27.7 --- Environment for perl 5.27.7: HOME=/home/zefram LANG (unset) LANGUAGE (unset) LD_LIBRARY_PATH (unset) LOGDIR (unset) PATH=/home/zefram/usr/perl/perl_install/perl-5.27.7-i64-f52/bin:/home/zefram/usr/perl/util:/home/zefram/pub/x86_64-unknown-linux-gnu/bin:/home/zefram/pub/common/bin:/usr/bin:/bin:/usr/local/bin:/usr/games PERLDOC=-oman PERL_BADLANG (unset) SHELL=/usr/bin/zsh
RT-Send-CC: perl5-porters [...] perl.org
Download (untitled) / with headers
text/plain 1.6k
On Tue, 16 Jan 2018 16:42:53 -0800, zefram@fysh.org wrote: Show quoted text
> > This is a bug report for perl from zefram@fysh.org, > generated with the help of perlbug 1.41 running under perl 5.27.7. > > > ----------------------------------------------------------------- > [Please describe your issue here] > > Simple test case for some array operations: > > $ perl -lwe '$a[0] = undef; $a[1] = 1; sub foo { unshift @a, 7; $_[0] > = 3; } foo($a[0]); print map { $_ // "u" } @a;' > 731 > > The above works as expected. Note that the sub call aliases $_[0] > to the original $a[0], and that aliasing holds through the unshift. > After unshift, that element is now $a[1], and an assignment to it is > made successfully through the $_[0] alias. > > But if the initial $a[0] isn't explicitly initialised, this goes awry: > > $ perl -lwe '$a[1] = 1; sub foo { unshift @a, 7; $_[0] = 3; } > foo($a[0]); print map { $_ // "u" } @a;' > 3u1 > > This time, $_[0] after the unshift is aliasing the *new* $a[0], which > didn't exist to be aliased at the time the sub call set up the alias. > The lazy element creation is being too lazy, deferring resolution of > the array index until it's too late. > > The same effect can be seen by using foreach(@a) to set up an alias: > > $ perl -lwe '$a[0] = undef; $a[1] = 1; foreach(@a) { unshift @a, 7; $_ > = 3; last; } print map { $_ // "u" } @a;' > 731 > $ perl -lwe '$a[1] = 1; foreach(@a) { unshift @a, 7; $_ = 3; last; } > print map { $_ // "u" } @a;' > 3u1
The branch merged as 2a05854 includes a partial fix for the bug. It applies to nonexistent elements within the array. The fix doesn’t apply to elements outside the array. -- Father Chrysostomos


This service is sponsored and maintained by Best Practical Solutions and runs on Perl.org infrastructure.

For issues related to this RT instance (aka "perlbug"), please contact perlbug-admin at perl.org