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

Perl segfaults in BEGIN, write to null pointer, separate bug #14852

Closed
p5pRT opened this issue Aug 13, 2015 · 8 comments
Closed

Perl segfaults in BEGIN, write to null pointer, separate bug #14852

p5pRT opened this issue Aug 13, 2015 · 8 comments

Comments

@p5pRT
Copy link

p5pRT commented Aug 13, 2015

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

Searchable as RT125806$

@p5pRT
Copy link
Author

p5pRT commented Aug 13, 2015

From @dcollinsn

This is distinct from #125789 (duplicate of #121048, patch in #125341). This segfault occurs in a different function and appears to be unrelated. Reini's patch in #125341 does not affect this bug.

The testcase is the following 15-character file​:

BEGIN(){i or$[}

Bisect not attempted because this also crashes in my ancient perl 5.10.1 install.

**GDB**
(gdb) run
Starting program​: /home/dcollins/perl/perl -e BEGIN\(\)\{i\ or\$\[\}
[Thread debugging using libthread_db enabled]
b
Program received signal SIGSEGV, Segmentation fault.
memmove () at ../sysdeps/i386/i686/memmove.S​:64
64 ../sysdeps/i386/i686/memmove.S​: No such file or directory.
  in ../sysdeps/i386/i686/memmove.S
Current language​: auto
The current source language is "auto; currently asm".
(gdb) l
59 in ../sysdeps/i386/i686/memmove.S
(gdb) bt
#0 memmove () at ../sysdeps/i386/i686/memmove.S​:64
#1 0x083bd9b7 in Perl_sv_setpv (sv=0x86f9358, ptr=0x869c5e2 "") at sv.c​:4906
#2 0x0807bd57 in Perl_newXS_len_flags (name=0x86fd998 "BEGIN", len=5,
  subaddr=0x806d160 <const_sv_xsub>, filename=0x86f4c26 "-e",
  proto=0x869c5e2 "", const_svp=0xbffff1a0, flags=1) at op.c​:9151
#3 0x0807c93f in Perl_newCONSTSUB_flags (stash=0x0, name=0x86fd998 "BEGIN",
  len=5, flags=0, sv=0x86f9344) at op.c​:9014
#4 0x080cb4bf in Perl_newATTRSUB_x (floor=39, o=0x86fe744, proto=0x86fe764,
  attrs=0x0, block=0x86fe8d4, o_is_gv=false) at op.c​:8634
#5 0x081c6383 in Perl_yyparse (gramtype=258) at perly.y​:293
#6 0x08106787 in S_parse_body (env=<value optimized out>,
  xsinit=<value optimized out>) at perl.c​:2296
#7 0x08109aa3 in perl_parse (my_perl=0x86e6008, xsinit=0x8065d10 <xs_init>,
  argc=3, argv=0xbffff4f4, env=0x0) at perl.c​:1626
#8 0x08065acf in main (argc=3, argv=0xbffff4f4, env=0xbffff504)
  at perlmain.c​:114
(gdb) q

The relevant call to Move in sv.c has the following parameters​:
4906 Move(ptr,SvPVX(sv),len+1,char);
(gdb) p ptr
$1 = 0x869c5e2 ""
(gdb) p sv
$2 = (SV * const) 0x86f9358
(gdb) p len
$3 = <value optimized out>

**VALGRIND**
dcollins@​nagios​:~/perl$ valgrind ./perl -e 'BEGIN(){i or$[}'==20018== Memcheck, a memory error detector
==20018== Copyright (C) 2002-2010, and GNU GPL'd, by Julian Seward et al.
==20018== Using Valgrind-3.6.0.SVN-Debian and LibVEX; rerun with -h for copyright info
==20018== Command​: ./perl -e BEGIN(){i\ or$[}
==20018==
==20018== Invalid write of size 1
==20018== at 0x4026534​: memmove (mc_replace_strmem.c​:629)
==20018== by 0x83BD9B6​: Perl_sv_setpv (sv.c​:4906)
==20018== by 0x807BD56​: Perl_newXS_len_flags (op.c​:9151)
==20018== by 0x807C93E​: Perl_newCONSTSUB_flags (op.c​:9014)
==20018== by 0x80CB4BE​: Perl_newATTRSUB_x (op.c​:8634)
==20018== by 0x81C6382​: Perl_yyparse (perly.y​:293)
==20018== by 0x8106786​: S_parse_body (perl.c​:2296)
==20018== by 0x8109AA2​: perl_parse (perl.c​:1626)
==20018== by 0x8065ACE​: main (perlmain.c​:114)
==20018== Address 0x0 is not stack'd, malloc'd or (recently) free'd
==20018==
==20018==
==20018== Process terminating with default action of signal 11 (SIGSEGV)
==20018== Access not within mapped region at address 0x0
==20018== at 0x4026534​: memmove (mc_replace_strmem.c​:629)
==20018== by 0x83BD9B6​: Perl_sv_setpv (sv.c​:4906)
==20018== by 0x807BD56​: Perl_newXS_len_flags (op.c​:9151)
==20018== by 0x807C93E​: Perl_newCONSTSUB_flags (op.c​:9014)
==20018== by 0x80CB4BE​: Perl_newATTRSUB_x (op.c​:8634)
==20018== by 0x81C6382​: Perl_yyparse (perly.y​:293)
==20018== by 0x8106786​: S_parse_body (perl.c​:2296)
==20018== by 0x8109AA2​: perl_parse (perl.c​:1626)
==20018== by 0x8065ACE​: main (perlmain.c​:114)
==20018== If you believe this happened as a result of a stack
==20018== overflow in your program's main thread (unlikely but
==20018== possible), you can try to increase the size of the
==20018== main thread stack using the --main-stacksize= flag.
==20018== The main thread stack size used in this run was 8388608.
==20018==
==20018== HEAP SUMMARY​:
==20018== in use at exit​: 145,310 bytes in 882 blocks
==20018== total heap usage​: 1,323 allocs, 441 frees, 211,204 bytes allocated
==20018==
==20018== LEAK SUMMARY​:
==20018== definitely lost​: 168 bytes in 1 blocks
==20018== indirectly lost​: 2,661 bytes in 40 blocks
==20018== possibly lost​: 30,982 bytes in 336 blocks
==20018== still reachable​: 111,499 bytes in 505 blocks
==20018== suppressed​: 0 bytes in 0 blocks
==20018== Rerun with --leak-check=full to see details of leaked memory
==20018==
==20018== For counts of detected and suppressed errors, rerun with​: -v
==20018== ERROR SUMMARY​: 1 errors from 1 contexts (suppressed​: 27 from 10)
Segmentation fault

**PERL -V**
dcollins@​nagios​:~/perl$ ./perl -V
Summary of my perl5 (revision 5 version 23 subversion 2) configuration​:
  Derived from​: 9728ed0
  Platform​:
  osname=linux, osvers=2.6.32-5-686, archname=i686-linux-64int-ld
  uname='linux nagios 2.6.32-5-686 #1 smp tue may 13 16​:33​:32 utc 2014 i686 gnulinux '
  config_args=''
  hint=recommended, useposix=true, d_sigaction=define
  useithreads=undef, usemultiplicity=undef
  use64bitint=define, use64bitall=undef, uselongdouble=define
  usemymalloc=n, bincompat5005=undef
  Compiler​:
  cc='afl-gcc', ccflags ='-fwrapv -fno-strict-aliasing -pipe -fstack-protector -I/usr/local/include -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64',
  optimize='-g',
  cppflags='-fwrapv -fno-strict-aliasing -pipe -fstack-protector -I/usr/local/include'
  ccversion='', gccversion='4.4.5', gccosandvers=''
  intsize=4, longsize=4, ptrsize=4, doublesize=8, byteorder=12345678, doublekind=3
  d_longlong=define, longlongsize=8, d_longdbl=define, longdblsize=12, longdblkind=3
  ivtype='long long', ivsize=8, nvtype='long double', nvsize=12, Off_t='off_t', lseeksize=8
  alignbytes=4, prototype=define
  Linker and Libraries​:
  ld='afl-gcc', ldflags =' -fstack-protector -L/usr/local/lib'
  libpth=/usr/local/lib /usr/lib/gcc/i486-linux-gnu/4.4.5/include-fixed /usr/lib /lib/../lib /usr/lib/../lib /lib /usr/lib/i486-linux-gnu /usr/lib64
  libs=-lpthread -lnsl -ldl -lm -lcrypt -lutil -lc
  perllibs=-lpthread -lnsl -ldl -lm -lcrypt -lutil -lc
  libc=libc-2.11.3.so, so=so, useshrplib=false, libperl=libperl.a
  gnulibc_version='2.11.3'
  Dynamic Linking​:
  dlsrc=dl_dlopen.xs, dlext=so, d_dlsymun=undef, ccdlflags='-Wl,-E'
  cccdlflags='-fPIC', lddlflags='-shared -g -L/usr/local/lib -fstack-protector'

Characteristics of this binary (from libperl)​:
  Compile-time options​: HAS_TIMES PERLIO_LAYERS PERL_COPY_ON_WRITE
  PERL_DONT_CREATE_GVSV
  PERL_HASH_FUNC_ONE_AT_A_TIME_HARD PERL_MALLOC_WRAP
  PERL_PRESERVE_IVUV USE_64_BIT_INT USE_LARGE_FILES
  USE_LOCALE USE_LOCALE_COLLATE USE_LOCALE_CTYPE
  USE_LOCALE_NUMERIC USE_LOCALE_TIME USE_LONG_DOUBLE
  USE_PERLIO USE_PERL_ATOF
  Locally applied patches​:
  uncommitted-changes
  Built under linux
  Compiled at Aug 13 2015 18​:34​:59
  @​INC​:
  /usr/local/perl-afl/lib/site_perl/5.23.2/i686-linux-64int-ld
  /usr/local/perl-afl/lib/site_perl/5.23.2
  /usr/local/perl-afl/lib/5.23.2/i686-linux-64int-ld
  /usr/local/perl-afl/lib/5.23.2
  .

@p5pRT
Copy link
Author

p5pRT commented Aug 17, 2015

From @wolfsage

On Thu, Aug 13, 2015 at 7​:05 PM, Dan Collins <perlbug-followup@​perl.org> wrote​:

# New Ticket Created by Dan Collins
# Please include the string​: [perl #125806]
# in the subject line of all future correspondence about this issue.
# <URL​: https://rt-archive.perl.org/perl5/Ticket/Display.html?id=125806 >

This is distinct from #125789 (duplicate of #121048, patch in #125341). This segfault occurs in a different function and appears to be unrelated. Reini's patch in #125341 does not affect this bug.

The testcase is the following 15-character file​:

BEGIN(){i or$[}

Bisect not attempted because this also crashes in my ancient perl 5.10.1 install.

Looks like it first broke in 5.8.9, and since then has failed
magnificently in different ways as Perl has aged.

-- Matthew Horsfall (alh)

@p5pRT
Copy link
Author

p5pRT commented Aug 17, 2015

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

@p5pRT
Copy link
Author

p5pRT commented Dec 4, 2017

From zefram@fysh.org

The test case simplifies to​:

$ perl -e 'BEGIN {} BEGIN () {1}'
zsh​: segmentation fault perl -e 'BEGIN {} BEGIN () {1}'

The necessary elements are a BEGIN block with constant-value (foldable)
body and empty prototype, compilation of which completes after some other
real or implied BEGIN block. The effect of $[ in the original test case
was merely to imply a BEGIN block that is used to load the arybase module.

The mode by which it fails is that the constant-value BEGIN block gets
compiled as a constant subroutine, taking quite a different path through
construction from what a normal sub would get, and this code path doesn't
cope with the sub getting automatically run and SvREFCNT_dec()ed partway
through construction. The segv specifically happens when sv_setpv() is
invoked to attach the prototype, just after the sub has been automatically
run, so sv_setpv() sees a freed SV.

Fixing this is not trivial. It's easy enough to prevent sv_setpv()
being called from newXS_len_flags() if it's been freed, just as some of
the stuff at the end of newATTRSUB_x() is conditional. But it returns
to newCONSTSUB_flags(), which performs further work on the CV, and in so
doing assumes that it's still alive. In fact, in principle it's wrong
to perform the automatic run so early, because it's being run before
newCONSTSUB_flags() has completed construction; it hasn't even put the
constant value in at that point, though nothing currently depends on
that value. It's tempting to create an extra mortal reference to the
sub when it's automatically run as a BEGIN block, but that lasts too
long in some situations.

So I think the automatic running and freeing needs to be shifted around,
and this will probably require a flag to newXS_len_flags() to suppress
the automatic run (which is still required when it's called from other
places). But its flag word is currently in a silly state, taking two
sets of flags that overlap in their bit usage, so that really needs to
be sorted out first. We could also do with documenting these functions,
particularly in how to handle their potentially-freed result.

-zefram

@p5pRT
Copy link
Author

p5pRT commented Dec 4, 2017

From @cpansprout

On Mon, 04 Dec 2017 08​:20​:43 -0800, zefram@​fysh.org wrote​:

So I think the automatic running and freeing needs to be shifted around,
and this will probably require a flag to newXS_len_flags() to suppress
the automatic run (which is still required when it's called from other
places). But its flag word is currently in a silly state, taking two
sets of flags that overlap in their bit usage, so that really needs to
be sorted out first. We could also do with documenting these functions,
particularly in how to handle their potentially-freed result.

newXS_len_flags is not API, so we can change it however we want. I also think it should remain private, precisely so that we have wiggle room to fix problems such as this in future. (This is not the first time it has needed a significant rework to fix bug.)

--

Father Chrysostomos

@demerphq
Copy link
Collaborator

demerphq commented Sep 8, 2022

This does not segfault in 5.34.1. Possibly because the prototype is ignored because the expression is not constant. See also #16057 for the same reduced bug.

@bram-perl
Copy link

bram-perl commented Sep 12, 2022

This does not segfault in 5.34.1. Possibly because the prototype is ignored because the expression is not constant. See also #16057 for the same reduced bug.

Doing some testing: on v5.34.1:

This no longer segfaults on v5.34.1:

$ ./perl  -Ilib -le 'BEGIN(){i or$[};'

but something like:

$ ./perl  -Ilib -le 'no strict; BEGIN(){i or$[};'

still does (on v5.34.1, not on blead).

Digging a bit deeper: using $[ used to imply use arybase; but that got removed in perl v5.30.0:

$ ./perl -wle 'print $];'
5.030000
$ ./perl  -le 'BEGIN(){i or$[};'
$ ./perl -Ilib -le 'no strict; BEGIN(){i or$[};'
Segmentation fault (core dumped)

So you are indeed somewhat correct: the example in the issue description no longer segfaults - on v5.34.1 - but that's simply because there no longer is an earlier BEGIN block (or no longer a use statement since that too implies a BEGIN block).

The real solution is the one you committed for #16057

@demerphq
Copy link
Collaborator

Ah, i guess you mean e5d2a2e

Cool. :-) Closing.

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

No branches or pull requests

4 participants