Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
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

crash with no warnings 'uninitialized' and chained comparsion #18380

Closed
D1CED opened this issue Dec 5, 2020 · 4 comments · Fixed by #18390
Closed

crash with no warnings 'uninitialized' and chained comparsion #18380

D1CED opened this issue Dec 5, 2020 · 4 comments · Fixed by #18390

Comments

@D1CED
Copy link

D1CED commented Dec 5, 2020

Module: warnings

Description

Segfault

Steps to Reproduce

no warnings 'uninitialized';

my $v;
1 < $v < 2;
2 < $v < 3;

Expected behavior

Exit with code 0.

Perl configuration

# perl -V output goes here
Summary of my perl5 (revision 5 version 32 subversion 0) configuration:
   
  Platform:
    osname=linux
    osvers=5.7.8-arch1-1
    archname=x86_64-linux-thread-multi
    uname='archlinux'
    config_args='-des -Dusethreads -Duseshrplib -Doptimize=-march=x86-64 -mtune=generic -O2 -pipe -fno-plt -Dprefix=/usr -Dvendorprefix=/usr -Dprivlib=/usr/share/perl5/core_perl -Darchlib=/usr/lib/perl5/5.32/core_perl -Dsitelib=/usr/share/perl5/site_perl -Dsitearch=/usr/lib/perl5/5.32/site_perl -Dvendorlib=/usr/share/perl5/vendor_perl -Dvendorarch=/usr/lib/perl5/5.32/vendor_perl -Dscriptdir=/usr/bin/core_perl -Dsitescript=/usr/bin/site_perl -Dvendorscript=/usr/bin/vendor_perl -Dinc_version_list=none -Dman1ext=1perl -Dman3ext=3perl -Dcccdlflags='-fPIC' -Dlddlflags=-shared -Wl,-O1,--sort-common,--as-needed,-z,relro,-z,now -Dldflags=-Wl,-O1,--sort-common,--as-needed,-z,relro,-z,now -Dmyuname=archlinux -Dmyhostname=archlinux -Dcf_time=Thu Sep 17 09:12:52 PM UTC 2020'
    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='-march=x86-64 -mtune=generic -O2 -pipe -fno-plt'
    cppflags='-D_REENTRANT -D_GNU_SOURCE -fwrapv -fno-strict-aliasing -pipe -fstack-protector-strong -I/usr/local/include'
    ccversion=''
    gccversion='10.2.0'
    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 ='-Wl,-O1,--sort-common,--as-needed,-z,relro,-z,now -fstack-protector-strong -L/usr/local/lib'
    libpth=/usr/local/lib /usr/lib/gcc/x86_64-pc-linux-gnu/10.2.0/include-fixed /usr/lib /lib/../lib /usr/lib/../lib /lib /lib64 /usr/lib64
    libs=-lpthread -lgdbm -ldb -ldl -lm -lcrypt -lutil -lc -lgdbm_compat
    perllibs=-lpthread -ldl -lm -lcrypt -lutil -lc
    libc=libc-2.32.so
    so=so
    useshrplib=true
    libperl=libperl.so
    gnulibc_version='2.32'
  Dynamic Linking:
    dlsrc=dl_dlopen.xs
    dlext=so
    d_dlsymun=undef
    ccdlflags='-Wl,-E -Wl,-rpath,/usr/lib/perl5/5.32/core_perl/CORE'
    cccdlflags='-fPIC'
    lddlflags='-shared -Wl,-O1,--sort-common,--as-needed,-z,relro,-z,now -L/usr/local/lib -fstack-protector-strong'


Characteristics of this binary (from libperl): 
  Compile-time options:
    HAS_TIMES
    MULTIPLICITY
    PERLIO_LAYERS
    PERL_COPY_ON_WRITE
    PERL_DONT_CREATE_GVSV
    PERL_IMPLICIT_CONTEXT
    PERL_MALLOC_WRAP
    PERL_OP_PARENT
    PERL_PRESERVE_IVUV
    USE_64_BIT_ALL
    USE_64_BIT_INT
    USE_ITHREADS
    USE_LARGE_FILES
    USE_LOCALE
    USE_LOCALE_COLLATE
    USE_LOCALE_CTYPE
    USE_LOCALE_NUMERIC
    USE_LOCALE_TIME
    USE_PERLIO
    USE_PERL_ATOF
    USE_REENTRANT_API
    USE_THREAD_SAFE_LOCALE
  Built under linux
  Compiled at Sep 17 2020 21:12:52
  %ENV:
    PERL5LIB="/home/me/perl5/lib/perl5"
    PERL_LOCAL_LIB_ROOT="/home/me/perl5"
    PERL_MB_OPT="--install_base "/home/me/perl5""
    PERL_MM_OPT="INSTALL_BASE=/home/me/perl5"
  @INC:
    /home/me/perl5/lib/perl5/5.32.0/x86_64-linux-thread-multi
    /home/me/perl5/lib/perl5/5.32.0
    /home/me/perl5/lib/perl5/x86_64-linux-thread-multi
    /home/me/perl5/lib/perl5
    /usr/lib/perl5/5.32/site_perl
    /usr/share/perl5/site_perl
    /usr/lib/perl5/5.32/vendor_perl
    /usr/share/perl5/vendor_perl
    /usr/lib/perl5/5.32/core_perl
    /usr/share/perl5/core_perl
Summary of my perl5 (revision 5 version 32 subversion 0) configuration:
   
  Platform:
    osname=linux
    osvers=5.7.8-arch1-1
    archname=x86_64-linux-thread-multi
    uname='archlinux'
    config_args='-des -Dusethreads -Duseshrplib -Doptimize=-march=x86-64 -mtune=generic -O2 -pipe -fno-plt -Dprefix=/usr -Dvendorprefix=/usr -Dprivlib=/usr/share/perl5/core_perl -Darchlib=/usr/lib/perl5/5.32/core_perl -Dsitelib=/usr/share/perl5/site_perl -Dsitearch=/usr/lib/perl5/5.32/site_perl -Dvendorlib=/usr/share/perl5/vendor_perl -Dvendorarch=/usr/lib/perl5/5.32/vendor_perl -Dscriptdir=/usr/bin/core_perl -Dsitescript=/usr/bin/site_perl -Dvendorscript=/usr/bin/vendor_perl -Dinc_version_list=none -Dman1ext=1perl -Dman3ext=3perl -Dcccdlflags='-fPIC' -Dlddlflags=-shared -Wl,-O1,--sort-common,--as-needed,-z,relro,-z,now -Dldflags=-Wl,-O1,--sort-common,--as-needed,-z,relro,-z,now -Dmyuname=archlinux -Dmyhostname=archlinux -Dcf_time=Thu Sep 17 09:12:52 PM UTC 2020'
    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='-march=x86-64 -mtune=generic -O2 -pipe -fno-plt'
    cppflags='-D_REENTRANT -D_GNU_SOURCE -fwrapv -fno-strict-aliasing -pipe -fstack-protector-strong -I/usr/local/include'
    ccversion=''
    gccversion='10.2.0'
    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 ='-Wl,-O1,--sort-common,--as-needed,-z,relro,-z,now -fstack-protector-strong -L/usr/local/lib'
    libpth=/usr/local/lib /usr/lib/gcc/x86_64-pc-linux-gnu/10.2.0/include-fixed /usr/lib /lib/../lib /usr/lib/../lib /lib /lib64 /usr/lib64
    libs=-lpthread -lgdbm -ldb -ldl -lm -lcrypt -lutil -lc -lgdbm_compat
    perllibs=-lpthread -ldl -lm -lcrypt -lutil -lc
    libc=libc-2.32.so
    so=so
    useshrplib=true
    libperl=libperl.so
    gnulibc_version='2.32'
  Dynamic Linking:
    dlsrc=dl_dlopen.xs
    dlext=so
    d_dlsymun=undef
    ccdlflags='-Wl,-E -Wl,-rpath,/usr/lib/perl5/5.32/core_perl/CORE'
    cccdlflags='-fPIC'
    lddlflags='-shared -Wl,-O1,--sort-common,--as-needed,-z,relro,-z,now -L/usr/local/lib -fstack-protector-strong'


Characteristics of this binary (from libperl): 
  Compile-time options:
    HAS_TIMES
    MULTIPLICITY
    PERLIO_LAYERS
    PERL_COPY_ON_WRITE
    PERL_DONT_CREATE_GVSV
    PERL_IMPLICIT_CONTEXT
    PERL_MALLOC_WRAP
    PERL_OP_PARENT
    PERL_PRESERVE_IVUV
    USE_64_BIT_ALL
    USE_64_BIT_INT
    USE_ITHREADS
    USE_LARGE_FILES
    USE_LOCALE
    USE_LOCALE_COLLATE
    USE_LOCALE_CTYPE
    USE_LOCALE_NUMERIC
    USE_LOCALE_TIME
    USE_PERLIO
    USE_PERL_ATOF
    USE_REENTRANT_API
    USE_THREAD_SAFE_LOCALE
  Built under linux
  Compiled at Sep 17 2020 21:12:52
  %ENV:
    PERL5LIB="/home/jmhoffmann/perl5/lib/perl5"
    PERL_LOCAL_LIB_ROOT="/home/jmhoffmann/perl5"
    PERL_MB_OPT="--install_base "/home/jmhoffmann/perl5""
    PERL_MM_OPT="INSTALL_BASE=/home/jmhoffmann/perl5"
  @INC:
    /home/jmhoffmann/perl5/lib/perl5/5.32.0/x86_64-linux-thread-multi
    /home/jmhoffmann/perl5/lib/perl5/5.32.0
    /home/jmhoffmann/perl5/lib/perl5/x86_64-linux-thread-multi
    /home/jmhoffmann/perl5/lib/perl5
    /usr/lib/perl5/5.32/site_perl
    /usr/share/perl5/site_perl
    /usr/lib/perl5/5.32/vendor_perl
    /usr/share/perl5/vendor_perl
    /usr/lib/perl5/5.32/core_perl
    /usr/share/perl5/core_perl
@tonycoz
Copy link
Contributor

tonycoz commented Dec 7, 2020

This looks like a bug the way chained comparisons are handled which breaks constant folding.

The code at op.c:5598 constant folds the right-hand part of the chain. The full op tree for the chained op looks like:

8        +--cmpchain_and LOGOP(0x5619864ff680) ===> 1 [leave 0x5619864ff0d0]
             FLAGS = (VOID,KIDS,SLABBED)
             PRIVATE = (0x1)
             |   
9            +--lt BINOP(0x5619864ff028) ===> 8 [cmpchain_and 0x5619864ff680]
             |   FLAGS = (SCALAR,KIDS,SLABBED,MORESIB)
             |   PRIVATE = (0x2)
             |   |   
6            |   +--const SVOP(0x5619864ff098) ===> 10 [padsv 0x5619864ff068]
             |   |   FLAGS = (SCALAR,SLABBED,MORESIB)
             |   |   SV = IV(1)
             |   |   
11           |   +--cmpchain_dup UNOP(0x5619864ff6f0) ===> 9 [lt 0x5619864ff028]
             |       FLAGS = (SCALAR,KIDS,SLABBED)
             |       PRIVATE = (0x1)
             |       |   
10           |       +--padsv OP(0x5619864ff068) ===> 11 [cmpchain_dup 0x5619864ff6f0]
             |           TARG = 1
             |           FLAGS = (SCALAR,SLABBED)
             |   
12           +--lt BINOP(0x5619864fefb0) ===> 1 [leave 0x5619864ff0d0]
                 FLAGS = (SCALAR,KIDS,SLABBED)
                 PRIVATE = (0x2)
                 |   
13               +--null OP(0x5619864ff6c0) ===> 14 [const 0x5619864feff0]
                 |   FLAGS = (SCALAR,SLABBED,MORESIB)
                 |   
14               +--const SVOP(0x5619864feff0) ===> 12 [lt 0x5619864fefb0]
                     FLAGS = (SCALAR,SLABBED)
                     SV = PVNV(2)

but it's just the:

12           +--lt BINOP(0x5619864fefb0) ===> 1 [leave 0x5619864ff0d0]
                 FLAGS = (SCALAR,KIDS,SLABBED)
                 PRIVATE = (0x2)
                 |   
13               +--null OP(0x5619864ff6c0) ===> 14 [const 0x5619864feff0]
                 |   FLAGS = (SCALAR,SLABBED,MORESIB)
                 |   
14               +--const SVOP(0x5619864feff0) ===> 12 [lt 0x5619864fefb0]
                     FLAGS = (SCALAR,SLABBED)
                     SV = PVNV(2)

being passed to fold_constants() in this case.

This code underflows the stack, since with this isolated tree there's no left op for the lt op:

Breakpoint 1, Perl_cmpchain_finish (ch=0x555555c3bea8) at op.c:5598
5598                    cmpop = fold_constants(op_integerize(op_std_init(cmpop)));
(gdb) p PL_stack_sp
$2 = (SV **) 0x555555c12db0
(gdb) p PL_stack_base
$3 = (SV **) 0x555555c12db0
(gdb) n
5599                condop = condop ? newLOGOP(OP_CMPCHAIN_AND, 0, cmpop, condop) :
(gdb) p PL_stack_sp
$4 = (SV **) 0x555555c12da8
(gdb) p PL_stack_base
$5 = (SV **) 0x555555c12db0
(gdb) p *PL_stack_sp
$6 = (SV *) 0x411

This is harmless for the first statement since we keep a &PL_sv_undef at the top of the stack, but when the second chained comparison is done the stack starts underflowed, so the TOPm1s in tryAMAGICbin_MG() accesses before the start of the stack, fetching whatever random pointer it finds there.

This only happens with the no warnings "uninitialized"; because constant folding sets $^W to 1 before running the code (since it can't know if it will be set at runtime) which ends up throwing an exception, aborting constant folding before the stack can be misadjusted.

@xenu
Copy link
Member

xenu commented Dec 7, 2020

I'm pretty sure #17917 has the same cause.

@tonycoz
Copy link
Contributor

tonycoz commented Dec 7, 2020

This also has the consequence that chained comparisons aren't constant folded at all.:

The original with &&
tony@mars:.../git/perl2$ ./perl -Dx -e '$x = (1 < 3 && 3 < 5)'
     
1    leave LISTOP(0x55fb2a6740b0) ===> [0x0]
     PARENT ===> [0x0]
     TARG = 1
     FLAGS = (VOID,KIDS,PARENS,SLABBED)
     PRIVATE = (REFC)
     REFCNT = 1
     |   
2    +--enter OP(0x55fb2a6740f0) ===> 3 [nextstate 0x55fb2a674010]
     |   FLAGS = (VOID,SLABBED,MORESIB)
     |   
3    +--nextstate COP(0x55fb2a674010) ===> 4 [const 0x55fb2a674128]
     |   FLAGS = (VOID,SLABBED,MORESIB)
     |   LINE = 1
     |   PACKAGE = "main"
     |   SEQ = 4294967246
     |   
5    +--sassign BINOP(0x55fb2a674070) ===> 1 [leave 0x55fb2a6740b0]
         FLAGS = (VOID,KIDS,STACKED,SLABBED)
         PRIVATE = (0x2)
         |   
4        +--const SVOP(0x55fb2a674128) ===> 6 [gvsv 0x55fb2a674198]
         |   FLAGS = (SCALAR,PARENS,SLABBED,FOLDED,MORESIB)
         |   PRIVATE = (SHORT)
         |   SV = SV_YES
         |   
7        +--null (ex-rv2sv) UNOP(0x55fb2a674160) ===> 5 [sassign 0x55fb2a674070]
             FLAGS = (SCALAR,KIDS,REF,MOD,SPECIAL,SLABBED)
             PRIVATE = (0x1)
             |   
6            +--gvsv SVOP(0x55fb2a674198) ===> 5 [sassign 0x55fb2a674070]
                 FLAGS = (SCALAR,SLABBED)
                 GV = main::x (0x55fb2a66d618)
With chained operators:
tony@mars:.../git/perl2$ ./perl -Dx -e '$x = (1 < 3 < 5)'
     
1    leave LISTOP(0x55bd92017688) ===> [0x0]
     PARENT ===> [0x0]
     TARG = 1
     FLAGS = (VOID,KIDS,PARENS,SLABBED)
     PRIVATE = (REFC)
     REFCNT = 1
     |   
2    +--enter OP(0x55bd92017658) ===> 3 [nextstate 0x55bd920176c8]
     |   FLAGS = (VOID,SLABBED,MORESIB)
     |   
3    +--nextstate COP(0x55bd920176c8) ===> 4 [const 0x55bd92017108]
     |   FLAGS = (VOID,SLABBED,MORESIB)
     |   LINE = 1
     |   PACKAGE = "main"
     |   SEQ = 4294967246
     |   
5    +--sassign BINOP(0x55bd92017728) ===> 1 [leave 0x55bd92017688]
         FLAGS = (VOID,KIDS,STACKED,SLABBED)
         PRIVATE = (0x2)
         |   
6        +--null UNOP(0x55bd92016fe0) ===> 7 [gvsv 0x55bd92017178]
         |   FLAGS = (SCALAR,KIDS,PARENS,SLABBED,MORESIB)
         |   PRIVATE = (0x1)
         |   |   
8        |   +--cmpchain_and LOGOP(0x55bd92017768) ===> 7 [gvsv 0x55bd92017178]
         |       FLAGS = (SCALAR,KIDS,SLABBED)
         |       PRIVATE = (0x1)
         |       |   
9        |       +--lt BINOP(0x55bd92017090) ===> 8 [cmpchain_and 0x55bd92017768]
         |       |   FLAGS = (SCALAR,KIDS,SLABBED,MORESIB)
         |       |   PRIVATE = (0x2)
         |       |   |   
4        |       |   +--const SVOP(0x55bd92017108) ===> 10 [const 0x55bd920170d0]
         |       |   |   FLAGS = (SCALAR,SLABBED,MORESIB)
         |       |   |   SV = IV(1)
         |       |   |   
11       |       |   +--cmpchain_dup UNOP(0x55bd920177a8) ===> 9 [lt 0x55bd92017090]
         |       |       FLAGS = (SCALAR,KIDS,SLABBED)
         |       |       PRIVATE = (0x1)
         |       |       |   
10       |       |       +--const SVOP(0x55bd920170d0) ===> 11 [cmpchain_dup 0x55bd920177a8]
         |       |           FLAGS = (SCALAR,SLABBED)
         |       |           SV = IV(3)
         |       |   
12       |       +--lt BINOP(0x55bd92017018) ===> 7 [gvsv 0x55bd92017178]
         |           FLAGS = (SCALAR,KIDS,SLABBED)
         |           PRIVATE = (0x2)
         |           |   
13       |           +--null OP(0x55bd92016fb0) ===> 14 [const 0x55bd92017058]
         |           |   FLAGS = (SCALAR,SLABBED,MORESIB)
         |           |   
14       |           +--const SVOP(0x55bd92017058) ===> 12 [lt 0x55bd92017018]
         |               FLAGS = (SCALAR,SLABBED)
         |               SV = PVNV(5)
         |   
15       +--null (ex-rv2sv) UNOP(0x55bd92017140) ===> 5 [sassign 0x55bd92017728]
             FLAGS = (SCALAR,KIDS,REF,MOD,SPECIAL,SLABBED)
             PRIVATE = (0x1)
             |   
7            +--gvsv SVOP(0x55bd92017178) ===> 5 [sassign 0x55bd92017728]
                 FLAGS = (SCALAR,SLABBED)
                 GV = main::x (0x55bd92010608)

tonycoz added a commit to tonycoz/perl5 that referenced this issue Dec 8, 2020
This code would try to constant fold an op tree like

  relop
    +- null
    +- constant

which would underflow the stack, potentially crashing perl.

This is intended as a quick fix rather than as a complete
solution.

Fixes Perl#18380
@tonycoz
Copy link
Contributor

tonycoz commented Dec 8, 2020

I have a simple "fix" in #18390, but what would be a complete fix?

A complete fix would need to:

  • handle the strack correctly
  • constant fold the operators correctly

I can see two possible solutions.

1. Build a normal op tree and optimize it in a ck function

Right now the grammar generates an op tree like:

1    null UNOP(0x555555c3a958) ===> [0x0]
     PARENT ===> [0x0]
     FLAGS = (UNKNOWN,KIDS,SLABBED)
     |   
2    +--const SVOP(0x555555c3a370) ===> [SELF]
     |   FLAGS = (SCALAR,SLABBED,MORESIB)
     |   SV = IV(2)
     |   
3    +--lt BINOP(0x555555c3a330) ===> [0x0]
     |   FLAGS = (UNKNOWN,SLABBED,MORESIB)
     |   
4    +--padsv OP(0x555555c3a3e8) ===> [SELF]
     |   TARG = 1
     |   FLAGS = (SCALAR,SLABBED,MORESIB)
     |   
5    +--lt BINOP(0x555555c3a3a8) ===> [0x0]
     |   FLAGS = (UNKNOWN,SLABBED,MORESIB)
     |   
6    +--const SVOP(0x555555c3a418) ===> [SELF]
         FLAGS = (SCALAR,SLABBED)
         SV = IV(1)

which cmpchain_finish() massages into:

1    null UNOP(0x555555c3a958) ===> [0x0]
     PARENT ===> [0x0]
     FLAGS = (UNKNOWN,KIDS,SLABBED)
     PRIVATE = (0x1)
     |   
7    +--cmpchain_and LOGOP(0x555555c3a8b0) ===> 6 [const 0x555555c3a418]
         FLAGS = (UNKNOWN,KIDS,SLABBED)
         PRIVATE = (0x1)
         |   
5        +--lt BINOP(0x555555c3a3a8) ===> 7 [cmpchain_and 0x555555c3a8b0]
         |   FLAGS = (SCALAR,KIDS,SLABBED,MORESIB)
         |   PRIVATE = (0x2)
         |   |   
6        |   +--const SVOP(0x555555c3a418) ===> 4 [padsv 0x555555c3a3e8]
         |   |   FLAGS = (SCALAR,SLABBED,MORESIB)
         |   |   SV = IV(1)
         |   |   
8        |   +--cmpchain_dup UNOP(0x555555c3a920) ===> 5 [lt 0x555555c3a3a8]
         |       FLAGS = (SCALAR,KIDS,SLABBED)
         |       PRIVATE = (0x1)
         |       |   
4        |       +--padsv OP(0x555555c3a3e8) ===> 8 [cmpchain_dup 0x555555c3a920]
         |           TARG = 1
         |           FLAGS = (SCALAR,SLABBED)
         |   
3        +--lt BINOP(0x555555c3a330) ===> 1 [null 0x555555c3a958]
             FLAGS = (SCALAR,KIDS,SLABBED)
             PRIVATE = (0x2)
             |   
9            +--null OP(0x555555c3a8f0) ===> 2 [const 0x555555c3a370]
             |   FLAGS = (SCALAR,SLABBED,MORESIB)
             |   
2            +--const SVOP(0x555555c3a370) ===> 3 [lt 0x555555c3a330]
                 FLAGS = (SCALAR,SLABBED)
                 SV = PVNV(2)

Instead, generate an optree like the equivalent pre-chain code might use:

5    +--null UNOP(0x561d7a7688b8) ===> 1 [leave 0x561d7a768818]
         FLAGS = (VOID,KIDS,SLABBED)
         PRIVATE = (0x1)
         |   
6        +--and LOGOP(0x561d7a7688f0) ===> 1 [leave 0x561d7a768818]
             FLAGS = (VOID,KIDS,SLABBED)
             PRIVATE = (0x1)
             OTHER ===> 7 [gvsv 0x561d7a7681c0]
             |   
8            +--lt BINOP(0x561d7a7681f8) ===> 6 [and 0x561d7a7688f0]
             |   FLAGS = (SCALAR,KIDS,SLABBED,MORESIB)
             |   PRIVATE = (0x2)
             |   |   
4            |   +--const SVOP(0x561d7a7682a8) ===> 9 [gvsv 0x561d7a768270]
             |   |   FLAGS = (SCALAR,SLABBED,MORESIB)
             |   |   SV = IV(1)
             |   |   
10           |   +--null (ex-rv2sv) UNOP(0x561d7a768238) ===> 8 [lt 0x561d7a7681f8]
             |       FLAGS = (SCALAR,KIDS,SLABBED)
             |       PRIVATE = (0x1)
             |       |   
9            |       +--gvsv SVOP(0x561d7a768270) ===> 8 [lt 0x561d7a7681f8]
             |           FLAGS = (SCALAR,SLABBED)
             |           GV = main::v (0x561d7a761770)
             |   
11           +--lt BINOP(0x561d7a768110) ===> 1 [leave 0x561d7a768818]
                 FLAGS = (VOID,KIDS,SLABBED)
                 PRIVATE = (0x2)
                 |   
12               +--null (ex-rv2sv) UNOP(0x561d7a768188) ===> 13 [const 0x561d7a768150]
                 |   FLAGS = (SCALAR,KIDS,SLABBED,MORESIB)
                 |   PRIVATE = (0x1)
                 |   |   
7                |   +--gvsv SVOP(0x561d7a7681c0) ===> 13 [const 0x561d7a768150]
                 |       FLAGS = (SCALAR,SLABBED)
                 |       GV = main::v (0x561d7a761770)
                 |   
13               +--const SVOP(0x561d7a768150) ===> 11 [lt 0x561d7a768110]
                     FLAGS = (SCALAR,SLABBED)
                     SV = IV(3)

which fold_constants() can already fold. For chain purposes the ops generated would need flags to indicate they were chained ops in terms of syntax. I expect any constant folding would have been done before we reach the ck function.

The ck function would then need to transform that into the cmpchain form above.

2. Add specialized constant folding for cmpchain

The grammar generates an optree like:

1    null UNOP(0x555555c3a958) ===> [0x0]
     PARENT ===> [0x0]
     FLAGS = (UNKNOWN,KIDS,SLABBED)
     |   
2    +--const SVOP(0x555555c3a370) ===> [SELF]
     |   FLAGS = (SCALAR,SLABBED,MORESIB)
     |   SV = IV(2)
     |   
3    +--lt BINOP(0x555555c3a330) ===> [0x0]
     |   FLAGS = (UNKNOWN,SLABBED,MORESIB)
     |   
4    +--padsv OP(0x555555c3a3e8) ===> [SELF]
     |   TARG = 1
     |   FLAGS = (SCALAR,SLABBED,MORESIB)
     |   
5    +--lt BINOP(0x555555c3a3a8) ===> [0x0]
     |   FLAGS = (UNKNOWN,SLABBED,MORESIB)
     |   
6    +--const SVOP(0x555555c3a418) ===> [SELF]
         FLAGS = (SCALAR,SLABBED)
         SV = IV(1)

Since we only need to resolve relative ops, we could lift the checks from fold_constants(), ie. that we're not doing locale sensitive comparisons, and that all of the operands are constants (2 and 4 for the first, 4 and 6 for the second), and build a new optree to pass to fold_constants() to attempt the fold.

Both options will require some care in handling constant folded comparisons at different places in the chain.

tonycoz added a commit that referenced this issue Dec 23, 2020
This code would try to constant fold an op tree like

  relop
    +- null
    +- constant

which would underflow the stack, potentially crashing perl.

This is intended as a quick fix rather than as a complete
solution.

Fixes #18380
steve-m-hay pushed a commit that referenced this issue Jan 7, 2021
This code would try to constant fold an op tree like

  relop
    +- null
    +- constant

which would underflow the stack, potentially crashing perl.

This is intended as a quick fix rather than as a complete
solution.

Fixes #18380

(cherry picked from commit 08be3ef)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants