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

array element lazily created at wrong index #16364

Open
p5pRT opened this issue Jan 17, 2018 · 3 comments
Open

array element lazily created at wrong index #16364

p5pRT opened this issue Jan 17, 2018 · 3 comments

Comments

@p5pRT
Copy link

p5pRT commented Jan 17, 2018

Migrated from rt.perl.org#132729 (status was 'open')

Searchable as RT132729$

@p5pRT
Copy link
Author

p5pRT commented Jan 17, 2018

From zefram@fysh.org

Created by zefram@fysh.org

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.

Perl Info

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

@p5pRT
Copy link
Author

p5pRT commented Feb 19, 2018

From @cpansprout

On Tue, 16 Jan 2018 16​:42​:53 -0800, zefram@​fysh.org wrote​:

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

@p5pRT
Copy link
Author

p5pRT commented Feb 19, 2018

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

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

2 participants