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

calling C function perl_clone of libperl causes segfault in perl 5.22 and and 5.24 but fine on perl 5.20 #15917

Closed
p5pRT opened this issue Mar 7, 2017 · 12 comments

Comments

@p5pRT
Copy link

p5pRT commented Mar 7, 2017

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

Searchable as RT130949$

@p5pRT
Copy link
Author

p5pRT commented Mar 7, 2017

From mitch.capper@gmail.com

For using perl in C++ programs unfortunately a simple call to perl_clone
causes a segfault. The problem does not happen on perl 5.20 (or earlier)
but does on 5.22 and later. A simple test case can be found at​:
https://bugs.launchpad.net/ubuntu/+source/perl/+bug/1668450/+attachment/4827896/+files/test.c
(also attached) originally found due to breakage of FreeSWITCH on newer
versions of perl​: https://freeswitch.org/jira/browse/FS-10071

============Backtrace==============
Program received signal SIGSEGV, Segmentation fault.
0x00007ffff7a7032a in Perl_padnamelist_dup () from libperl.so
(gdb) bt
#0 0x00007ffff7a7032a in Perl_padnamelist_dup () from libperl.so
#1 0x00007ffff7adcf9f in perl_clone () from libperl.so
#2 0x000000000040086d in main () at test.c​:10

===========Repro Details===========

You can use these commands in a container like​:
docker run -t -i ubutnu​:xenial bash

============= For 5.24 ============
Here is for building and testing 5.24 (will segfault)​:

apt-get update && apt-get install -y lbzip2 zlibc libbz2-dev
build-essential curl wget zlib1g-dev
cd /
curl http​://www.cpan.org/src/5.0/perl-5.24.1.tar.gz | tar xz
cd perl-5.24.1
echo "127.0.0.1 localhost $(hostname)" > /etc/hosts
export BUILD_ZLIB=False
export BUILD_BZIP2=0
sh Configure -des -Dprefix=/usr -Dvendorprefix=/usr -Duseithreads
-Duseshrplib
make -j 4 && make install

wget
https://bugs.launchpad.net/ubuntu/+source/perl/+bug/1668450/+attachment/4827896/+files/test.c
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH​:/perl-5.24.1/libperl.so
gcc -g test.c -I/usr/lib/perl5/5.24.1/x86_64-linux-thread-multi/CORE/ -L.
-lperl && ./a.out

============= For 5.20 ============
Here is for building and testing 5.20 (will not segfault)​:
apt-get update && apt-get install -y lbzip2 zlibc libbz2-dev
build-essential curl wget zlib1g-dev
cd /
curl http​://www.cpan.org/src/5.0/perl-5.20.0.tar.gz | tar xz
cd perl-5.20.0
echo "127.0.0.1 localhost $(hostname)" > /etc/hosts
export BUILD_ZLIB=False
export BUILD_BZIP2=0
sh Configure -des -Dprefix=/usr -Dvendorprefix=/usr -Duseithreads
-Duseshrplib
make -j 4 && make install

wget
https://bugs.launchpad.net/ubuntu/+source/perl/+bug/1668450/+attachment/4827896/+files/test.c
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH​:/perl-5.20.0/libperl.so
gcc -g test.c -I/usr/lib/perl5/5.20.0/x86_64-linux-thread-multi/CORE/ -L.
-lperl && ./a.out

============= perlbug -d for 5.20.0 ============


Flags​:
  category=core
  severity=low


Site configuration information for perl 5.20.0​:

Configured by root at Tue Mar 7 18​:44​:42 UTC 2017.

Summary of my perl5 (revision 5 version 20 subversion 0) configuration​:

  Platform​:
  osname=linux, osvers=4.4.0-38-generic,
archname=x86_64-linux-thread-multi
  uname='linux fb20ec36150b 4.4.0-38-generic #57-ubuntu smp tue sep 6
15​:42​:33 utc 2016 x86_64 x86_64 x86_64 gnulinux '
  config_args='-des -Dprefix=/usr -Dvendorprefix=/usr -Duseithreads
-Duseshrplib'
  hint=recommended, useposix=true, d_sigaction=define
  useithreads=define, usemultiplicity=define
  use64bitint=define, use64bitall=define, uselongdouble=undef
  usemymalloc=n, bincompat5005=undef
  Compiler​:
  cc='cc', ccflags ='-D_REENTRANT -D_GNU_SOURCE -fwrapv
-fno-strict-aliasing -pipe -fstack-protector -I/usr/local/include
-D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64',
  optimize='-O2',
  cppflags='-D_REENTRANT -D_GNU_SOURCE -fwrapv -fno-strict-aliasing -pipe
-fstack-protector -I/usr/local/include'
  ccversion='', gccversion='5.4.0 20160609', 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 /usr/lib/gcc/x86_64-linux-gnu/5/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=-lnsl -ldl -lm -lcrypt -lutil -lpthread -lc
  perllibs=-lnsl -ldl -lm -lcrypt -lutil -lpthread -lc
  libc=libc-2.23.so, so=so, useshrplib=true, libperl=libperl.so
  gnulibc_version='2.23'
  Dynamic Linking​:
  dlsrc=dl_dlopen.xs, dlext=so, d_dlsymun=undef, ccdlflags='-Wl,-E
-Wl,-rpath,/usr/lib/perl5/5.20.0/x86_64-linux-thread-multi/CORE'
  cccdlflags='-fPIC', lddlflags='-shared -O2 -L/usr/local/lib
-fstack-protector'


@​INC for perl 5.20.0​:
  /usr/lib/perl5/site_perl/5.20.0/x86_64-linux-thread-multi
  /usr/lib/perl5/site_perl/5.20.0
  /usr/lib/perl5/vendor_perl/5.20.0/x86_64-linux-thread-multi
  /usr/lib/perl5/vendor_perl/5.20.0
  /usr/lib/perl5/5.20.0/x86_64-linux-thread-multi
  /usr/lib/perl5/5.20.0
  .


Environment for perl 5.20.0​:
  HOME=/root
  LANG (unset)
  LANGUAGE (unset)
  LD_LIBRARY_PATH=​:/perl-5.20.0/libperl.so​:/perl-5.20.0/libperl.so
  LOGDIR (unset)
  PATH=/usr/local/sbin​:/usr/local/bin​:/usr/sbin​:/usr/bin​:/sbin​:/bin
  PERL_BADLANG (unset)
  SHELL (unset)



Flags​:
  category=core
  severity=medium


Site configuration information for perl 5.24.1​:

Configured by root at Tue Mar 7 19​:37​:15 UTC 2017.

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

  Platform​:
  osname=linux, osvers=4.4.0-38-generic,
archname=x86_64-linux-thread-multi
  uname='linux da2f44e5b8b6 4.4.0-38-generic #57-ubuntu smp tue sep 6
15​:42​:33 utc 2016 x86_64 x86_64 x86_64 gnulinux '
  config_args='-des -Dprefix=/usr -Dvendorprefix=/usr -Duseithreads
-Duseshrplib'
  hint=recommended, useposix=true, d_sigaction=define
  useithreads=define, usemultiplicity=define
  use64bitint=define, use64bitall=define, uselongdouble=undef
  usemymalloc=n, 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',
  optimize='-O2',
  cppflags='-D_REENTRANT -D_GNU_SOURCE -fwrapv -fno-strict-aliasing -pipe
-fstack-protector-strong -I/usr/local/include'
  ccversion='', gccversion='5.4.0 20160609', 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/5/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 -ldl -lm -lcrypt -lutil -lc
  perllibs=-lpthread -lnsl -ldl -lm -lcrypt -lutil -lc
  libc=libc-2.23.so, so=so, useshrplib=true, libperl=libperl.so
  gnulibc_version='2.23'
  Dynamic Linking​:
  dlsrc=dl_dlopen.xs, dlext=so, d_dlsymun=undef, ccdlflags='-Wl,-E
-Wl,-rpath,/usr/lib/perl5/5.24.1/x86_64-linux-thread-multi/CORE'
  cccdlflags='-fPIC', lddlflags='-shared -O2 -L/usr/local/lib
-fstack-protector-strong'


@​INC for perl 5.24.1​:
  /usr/lib/perl5/site_perl/5.24.1/x86_64-linux-thread-multi
  /usr/lib/perl5/site_perl/5.24.1
  /usr/lib/perl5/vendor_perl/5.24.1/x86_64-linux-thread-multi
  /usr/lib/perl5/vendor_perl/5.24.1
  /usr/lib/perl5/5.24.1/x86_64-linux-thread-multi
  /usr/lib/perl5/5.24.1


Environment for perl 5.24.1​:
  HOME=/root
  LANG (unset)
  LANGUAGE (unset)
  LD_LIBRARY_PATH=​:/perl-5.24.1/libperl.so
  LOGDIR (unset)
  PATH=/usr/local/sbin​:/usr/local/bin​:/usr/sbin​:/usr/bin​:/sbin​:/bin
  PERL_BADLANG (unset)
  SHELL (unset)

--------------1.40.perlbug
Content-Type​: text/x-patch; name="test.c"
Content-Transfer-Encoding​: 8bit
Content-Disposition​: attachment; filename="test.c"

#include <EXTERN.h>
#include <perl.h>

void main(){
  PerlInterpreter *my_perl;
  if (!(my_perl = perl_alloc())) {
  printf("Could not allocate perl interpreter\n");
  }
  perl_construct(my_perl);
  PerlInterpreter *perl2 = perl_clone(my_perl, CLONEf_COPY_STACKS |
CLONEf_KEEP_PTR_TABLE);
  printf("ALL FINE\n");
}

// apt-get update && apt-get install build-essential libperl-dev gdb
// zesty​: gcc -g test.c -I/usr/lib/x86_64-linux-gnu/perl/5.24.1/CORE/
-lperl && ./a.out
// xenial/yakkety (yakkety might be 5.22.2)​: gcc -g test.c
-I/usr/lib/x86_64-linux-gnu/perl/5.22.1/CORE/ -lperl && ./a.out
// trusty​: gcc -g test.c -I/usr/lib/perl/5.18.2/CORE/ -lperl && ./a.out

--------------1.40.perlbug--

~mitch

@p5pRT
Copy link
Author

p5pRT commented Mar 7, 2017

From mitch.capper@gmail.com

#include <EXTERN.h>
#include <perl.h>

void main(){
	PerlInterpreter *my_perl;
	if (!(my_perl = perl_alloc())) {
		printf("Could not allocate perl interpreter\n");
	}
	perl_construct(my_perl);
	PerlInterpreter *perl2 = perl_clone(my_perl, CLONEf_COPY_STACKS | CLONEf_KEEP_PTR_TABLE);
	printf("ALL FINE\n");
}

// apt-get update && apt-get install build-essential libperl-dev gdb
// zesty: gcc -g test.c -I/usr/lib/x86_64-linux-gnu/perl/5.24.1/CORE/ -lperl && ./a.out
// xenial/yakkety (yakkety might be 5.22.2): gcc -g test.c -I/usr/lib/x86_64-linux-gnu/perl/5.22.1/CORE/ -lperl && ./a.out
// trusty: gcc -g test.c -I/usr/lib/perl/5.18.2/CORE/ -lperl && ./a.out

@p5pRT
Copy link
Author

p5pRT commented Mar 8, 2017

From @iabyn

On Tue, Mar 07, 2017 at 11​:51​:38AM -0800, Mitch Capper wrote​:

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

For using perl in C++ programs unfortunately a simple call to perl_clone
causes a segfault. The problem does not happen on perl 5.20 (or earlier)
but does on 5.22 and later.

Your test program allocates and constructs a perl interpreter, but *doesn't*
parse a perl program, before calling perl_clone().

Some of the stuff that perl_clone() expects to be in place only happens
due to perl_parse() having been called.

Do you have a persuasive use case for calling perl_clone() on an "empty"
perl interpreter (where perl_parse hasn't been called)?

For porters​: I reproduced this by building blead with threads and
-Duseshrplib, then built and ran the test program as follows​:

$ cc -o test -I . -DPERL_CORE -D_REENTRANT -D_GNU_SOURCE -DDEBUGGING -ggdb -fwrapv -fno-strict-aliasing -pipe -fstack-protector-strong -I/usr/local/include -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -std=c89 -g -Wall -Werror=declaration-after-statement -Wextra -Wc++-compat -Wwrite-strings -L. -lperl ~/tmp/test.c

$ LD_LIBRARY_PATH=. ./test

where ~/tmp/test.c looks like the following. Uncommenting the perl_parse()
makes the problem go away.

#include <EXTERN.h>
#include <perl.h>

int main(int argc, char **argv){
  PerlInterpreter *my_perl;
  PerlInterpreter *perl2;
  if (!(my_perl = perl_alloc())) {
  Perl_croak_nocontext("Could not allocate perl interpreter\n");
  }
  perl_construct(my_perl);

  /*
  PL_exit_flags |= PERL_EXIT_DESTRUCT_END;
  perl_parse(my_perl, NULL, argc, argv, (char **)NULL);
  */

  perl2 = perl_clone(my_perl, CLONEf_COPY_STACKS | CLONEf_KEEP_PTR_TABLE);

  Perl_croak_nocontext("ALL FINE\n");
}

--
A problem shared is a problem doubled.

@p5pRT
Copy link
Author

p5pRT commented Mar 8, 2017

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

@p5pRT
Copy link
Author

p5pRT commented Mar 8, 2017

From mitch.capper+bit@gmail.com

I apologize I have oversimplified the use case here from the FreeSWITCH code to try and make the test case more concise. Their use of mod_perl (https://freeswitch.org/stash/projects/FS/repos/freeswitch/browse/src/mod/languages/mod_perl/mod_perl.c) does immediately call perl_parse after perl_construct so this must be trigged by something else. It also only happens on 5.22 and newer. I will work to update the test case with a better implementation of how FS is calling it that still repros shortly. In the mean time, if obvious, here is the BT from FreeSWITCH when it crashes​:

Thread 34 "freeswitch" received signal SIGSEGV, Segmentation fault.
[Switching to Thread 0x7fffc6612700 (LWP 213)]
0x00007fffc6e1e99a in Perl_padnamelist_dup () from /usr/lib/x86_64-linux-gnu/libperl.so.5.22
(gdb) bt
#0 0x00007fffc6e1e99a in Perl_padnamelist_dup () from /usr/lib/x86_64-linux-gnu/libperl.so.5.22
#1 0x00007fffc6e86b50 in perl_clone () from /usr/lib/x86_64-linux-gnu/libperl.so.5.22
#2 0x00007fffc7181092 in clone_perl () at mod_perl.c​:158
#3 0x00007fffc7181e03 in perl_function (session=<optimized out>, data=0x7fffd4099690 "/usr/local/freeswitch/conf/test.pl") at mod_perl.c​:209
#4 0x00007ffff77c8b0b in switch_core_session_exec (session=session@​entry=0x7fffd4077f68, application_interface=application_interface@​entry=0x9a9ea8, arg=arg@​entry=0x7fffd4099690 "/usr/local/freeswitch/conf/test.pl")
  at src/switch_core_session.c​:2871
#5 0x00007ffff77c90c8 in switch_core_session_execute_application_get_flags (session=session@​entry=0x7fffd4077f68, app=0x7fffd4099688 "perl", arg=0x7fffd4099690 "/usr/local/freeswitch/conf/test.pl", flags=flags@​entry=0x0)
  at src/switch_core_session.c​:2741
#6 0x00007ffff77cd4d2 in switch_core_standard_on_execute (session=0x7fffd4077f68) at src/switch_core_state_machine.c​:353
#7 switch_core_session_run (session=0x7fffd4077f68) at src/switch_core_state_machine.c​:650
#8 0x00007ffff77c630c in switch_core_session_thread (thread=<optimized out>, obj=0x7fffd4077f68) at src/switch_core_session.c​:1695
#9 0x00007ffff77c1b15 in switch_core_session_thread_pool_worker (thread=0x7fffd40af200, obj=<optimized out>) at src/switch_core_session.c​:1758
#10 0x00007ffff7aea350 in dummy_worker (opaque=0x7fffd40af200) at threadproc/unix/thread.c​:151
#11 0x00007ffff75286ba in start_thread (arg=0x7fffc6612700) at pthread_create.c​:333
#12 0x00007ffff725e82d in clone () at ../sysdeps/unix/sysv/linux/x86_64/clone.S​:109

@p5pRT
Copy link
Author

p5pRT commented Mar 22, 2017

From mitch.capper+bit@gmail.com

Ok tracked down the problem if an empty string is past after -e it segfaults​:

#include <EXTERN.h>
#include <perl.h>
static char *embedding[] = { "", "-e", "" };

int main(int argc, char **argv){
  PerlInterpreter *my_perl;
  PerlInterpreter *perl2;
  if (!(my_perl = perl_alloc())) {
  Perl_croak_nocontext("Could not allocate perl interpreter\n");
  }
  perl_construct(my_perl);

  PL_exit_flags |= PERL_EXIT_DESTRUCT_END;
  perl_parse(my_perl, NULL, 3, embedding, (char **)NULL);

  perl2 = perl_clone(my_perl, CLONEf_COPY_STACKS | CLONEf_KEEP_PTR_TABLE);
  Perl_croak_nocontext("ALL FINE\n");
}

This makes some sense given -e's meaning we should be able to easily work around for FS but not sure if the change of behavior is expected or not.

@p5pRT
Copy link
Author

p5pRT commented Mar 22, 2017

From @tonycoz

On Wed, Mar 22, 2017 at 10​:50​:43AM -0700, Mitch Capper via RT wrote​:

Ok tracked down the problem if an empty string is past after -e it segfaults​:

#include <EXTERN.h>
#include <perl.h>
static char *embedding[] = { "", "-e", "" };

The argv array requires a NULL at the end​:

static char *embedding[] = { "", "-e", "", NULL };

though I don't know if this is the cause of the failure you're seeing.

Tony

@p5pRT
Copy link
Author

p5pRT commented Mar 23, 2017

From mitch.capper+bit@gmail.com

Ok so technically still segfaults, but does spit out an error​:
gcc -g test.c -I/usr/lib/x86_64-linux-gnu/perl/5.22.1/CORE/ -lperl && ./a.out
No code specified for -e.
Segmentation fault (core dumped)

if you do​:

#include <EXTERN.h>
#include <perl.h>
static char *embedding[] = { "", "-e", NULL };

int main(int argc, char **argv){
  PerlInterpreter *my_perl;
  PerlInterpreter *perl2;
  if (!(my_perl = perl_alloc())) {
  Perl_croak_nocontext("Could not allocate perl interpreter\n");
  }
  perl_construct(my_perl);

  PL_exit_flags |= PERL_EXIT_DESTRUCT_END;
  perl_parse(my_perl, NULL, 3, embedding, (char **)NULL);

  perl2 = perl_clone(my_perl, CLONEf_COPY_STACKS | CLONEf_KEEP_PTR_TABLE);
  Perl_croak_nocontext("ALL FINE\n");
}

@p5pRT
Copy link
Author

p5pRT commented Mar 23, 2017

From mitch.capper+bit@gmail.com

Sorry and to clarify similarly​:
static char *embedding[] = { "", "-e", "", NULL }; segfaults.

@p5pRT
Copy link
Author

p5pRT commented Mar 23, 2017

From @iabyn

On Wed, Mar 22, 2017 at 05​:45​:37PM -0700, Mitch Capper via RT wrote​:

Ok so technically still segfaults, but does spit out an error​:
gcc -g test.c -I/usr/lib/x86_64-linux-gnu/perl/5.22.1/CORE/ -lperl && ./a.out
No code specified for -e.
Segmentation fault (core dumped)

if you do​:

#include <EXTERN.h>
#include <perl.h>
static char *embedding[] = { "", "-e", NULL };

int main(int argc, char **argv){
PerlInterpreter *my_perl;
PerlInterpreter *perl2;
if (!(my_perl = perl_alloc())) {
Perl_croak_nocontext("Could not allocate perl interpreter\n");
}
perl_construct(my_perl);

    PL\_exit\_flags |= PERL\_EXIT\_DESTRUCT\_END;
    perl\_parse\(my\_perl\, NULL\, 3\, embedding\, \(char \*\*\)NULL\);


    perl2 = perl\_clone\(my\_perl\, CLONEf\_COPY\_STACKS | CLONEf\_KEEP\_PTR\_TABLE\);
    Perl\_croak\_nocontext\("ALL FINE\\n"\);

}

Yes, but you're now calling perl_clone after a parse error. Strictly
speaking you should check the return value of perl_parse() and only call
perl_run() or perl_clone() if the code parsed ok.

Again, show me a valid use case for calling perl_clone() in such
circumstances, and I'll think about about making it handle such
circumstances.

--
Counsellor Troi states something other than the blindingly obvious.
  -- Things That Never Happen in "Star Trek" #16

@p5pRT
Copy link
Author

p5pRT commented Mar 23, 2017

From mitch.capper+bit@gmail.com

No problem, we have a work-around for our use and the function changes it seems are a non issue so this can be closed.

@p5pRT p5pRT closed this as completed Mar 24, 2017
@p5pRT
Copy link
Author

p5pRT commented Mar 24, 2017

@iabyn - Status changed from 'open' to 'rejected'

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

1 participant