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

Embedded Perl crash (5.26.1) when trying to read ERRSV - Linux (CentOS 7.5) #16562

Open
p5pRT opened this issue May 18, 2018 · 7 comments
Open

Comments

@p5pRT
Copy link

p5pRT commented May 18, 2018

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

Searchable as RT133214$

@p5pRT
Copy link
Author

p5pRT commented May 18, 2018

From Lee.Staniforth@synchronoss.com

Hi, Perl Debug,
I have an application which is built for Windows, Linux and Solaris.
It currently supports Perl 5.22.0, and we are now adding support for Perl 5.26.1.
However, the application crashes when attempting to check for errors. Specifically, any time we try to access ERRSV.
This only happens on Linux. Windows and Solaris are fine.
My application uses an exe which calls into a .so that statically links to libperl.a

Here's a snippet of the code​:

HRESULT CPerlProvider​::Call\(const char \*sSubroutine\,
                             int &nResult\,
                             LPWSTR \*error\)
\{
     HRESULT hr = S\_OK;
     SV \*err\_tmp;
     
     if \(m\_bInitialized==false\)
     \{
         if \(ScriptProvider\_Brief\(\)\)
             TRACEwprintf\(ScriptProvider\(\)\, L"PERL\[%s\] Call​: interpreter not initialized\!\\n"\, GetSessionID\(\)\);

         assert\(0\);
         LeaveCriticalSection\(&m\_cs\);
         return MDS\_E\_SCRIPT\_PROVIDER\_NOT\_INITIALIZED;
     \}

     PUTBACK;

     if \(ScriptProvider\_Brief\(\)\)
         TRACEwprintf\(ScriptProvider\(\)\, L"PERL\[%s\] '%S' running\\n"\, GetSessionID\(\)\, sSubroutine\);

     int nCount = perl\_call\_pv\(\(char \*\)sSubroutine\, G\_SCALAR|G\_EVAL\);

     SPAGAIN;

&nbsp;    err\_tmp = ERRSV;      \<==========================================Crash here
&nbsp;    if \(SvTRUE\(err\_tmp\)\)
&nbsp;    \{
&nbsp;        if\(ScriptProvider\_Brief\(\)\)
&nbsp;        \{
&nbsp;            TRACEwprintf\(ScriptProvider\(\)\, L"PERL\[%s\] '%S' failed&#8203;: %S"\, GetSessionID\(\)\, sSubroutine\, SvPV\(err\_tmp\, PL\_na\)\);
&nbsp;        \}
\<snip>

Prior to this we initialise the Perl system, via calls to PERL_SYS_INIT(), perl_construct(), perl_parse(), perl_run() and PERL_SET_CONTEXT().

I'm aware that ERRSV is a macro, which is based on PL_errgv. I know this should be initialised after calling perl_parse() (specifically in S_init_main_stash())
I've added various trace statements inside the libperl.a code (in perl.c) so I can see whether PL_errgv has a value and its memory address.
I've also added similar trace statements in my application's code. I print the value out at the end of libperl's perl_parse(), and in my application before and after the call to perl_parse().

Sometimes, the application crashes when accessing ERRSV, and this happens when the value is NULL.
However, the print statements inside of libperl.a show that it is not NULL.
The address of the variable changes (by 24 bytes) between my application and the code in libperl.a
Sometimes when I rebuild my application, it does not crash and the address of PL_errgv remains the same.

My question is have any of the Perl developers experienced this issue?
I've built a small piece of code, but this works each time, so there is something odd about my application, and I would like some suggestions. All suggestions will be welcome.

This does not happen with Perl 5.22.0, or Perl 5.22.4.
It starts happening in Perl 5.24.0. I had a look at some of the .c files and header files between 5.22.4 and 5.24.0, but nothing really stood out.

Thanks in advance :-)
Lee Staniforth.

Here's the output of perlbug -d for the 5.26.1 setup​:
perlbug -d


Flags​:
  category=core
  severity=low


Site configuration information for perl 5.26.1​:

Configured by root at Mon Feb 5 13​:59​:36 GMT 2018.

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

  Platform​:
  osname=linux
  osvers=3.10.0-514.26.2.el7.x86_64
  archname=x86_64-linux-thread-multi
  uname='linux linux-mds-build-01.cso-dev.vacum-np.sncrcorp.net 3.10.0-514.26.2.el7.x86_64 #1 smp tue jul 4 15​:04​:05 utc 2017 x86_64 x86_64 x86_64 gnulinux '
  config_args='-des -Dprefix=/data/metabld/perl-5.26 -Dusethreads -Accflags=-fPIC -Duserelocatableinc'
  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 -fPIC -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 -fPIC -fwrapv -fno-strict-aliasing -pipe -fstack-protector-strong -I/usr/local/include'
  ccversion=''
  gccversion='4.8.5 20150623 (Red Hat 4.8.5-16)'
  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 /lib/../lib64 /usr/lib/../lib64 /lib /lib64 /usr/lib64 /usr/local/lib64
  libs=-lpthread -lnsl -ldl -lm -lcrypt -lutil -lc
  perllibs=-lpthread -lnsl -ldl -lm -lcrypt -lutil -lc
  libc=libc-2.17.so
  so=so
  useshrplib=false
  libperl=libperl.a
  gnulibc_version='2.17'
  Dynamic Linking​:
  dlsrc=dl_dlopen.xs
  dlext=so
  d_dlsymun=undef
  ccdlflags='-Wl,-E'
  cccdlflags='-fPIC'
  lddlflags='-shared -O2 -L/usr/local/lib -fstack-protector-strong'


@​INC for perl 5.26.1​:
  /data/metabld/meta_dailybuild/ARTests/AtlasRegression
  /data/metabld/perl-5.26/lib/site_perl/5.26.1/x86_64-linux-thread-multi
  /data/metabld/perl-5.26/lib/site_perl/5.26.1
  /data/metabld/perl-5.26/lib/5.26.1/x86_64-linux-thread-multi
  /data/metabld/perl-5.26/lib/5.26.1


Environment for perl 5.26.1​:
  HOME=/data/metabld
  LANG=en_US.UTF-8
  LANGUAGE (unset)
  LD_LIBRARY_PATH=/data/metabld/meta_dailybuild/BuildSystem/Source/Atlas/v4.0/unixshared/bin/linux64
  LOGDIR (unset)
  PATH=.​:/opt/openwavemessaging/ds/bin​:/data/metabld/meta_dailybuild/BuildSystem/Source/Atlas/v4.0/unixshared/bin/linux64​:/opt/perl-5.26.1/bin​:/usr/local/bin​:/bin​:/usr/bin​:/usr/local/sbin​:/usr/sbin​:/data/metabld/.local/bin​:/data/metabld/bin
  PERL5LIB=/data/metabld/meta_dailybuild/ARTests/AtlasRegression
  PERL_BADLANG (unset)
  SHELL=/bin/bash
[metabld@​linux-mds-build-01 perl526_crash]$

@p5pRT
Copy link
Author

p5pRT commented May 19, 2018

From @iabyn

On Fri, May 18, 2018 at 07​:49​:47AM -0700, Lee Staniforth (via RT) wrote​:

err\_tmp = ERRSV;      \<==========================================Crash here

I haven't looked very hard, but I notice you perl is built with threading
support, so every perl function has an implicit pTHX (aka my_perl) as its
first parameter, and variables like PL_errgv get redefined as
my_perl->Ierrgv.

However, in your function which uses ERRSV, I can't see any usage of
pTHX nor dTHX, so I can't see how my_perl is getting declared.

--
Justice is when you get what you deserve.
Law is when you get what you pay for.

@p5pRT
Copy link
Author

p5pRT commented May 19, 2018

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

@p5pRT
Copy link
Author

p5pRT commented May 22, 2018

From Lee.Staniforth@synchronoss.com

Hi, Dave,
Thanks for the reply.

variables like PL_errgv get redefined as my_perl->Ierrgv
Thanks for that. I wasn't aware, and I'll investigate this avenue.

My application has other functions that configure the perl system, so these are the initialisation calls snippets​:
  PERL_SYS_INIT(&m_perl_argc,&m_perl_argv);
  my_perl = perl_alloc();
  perl_construct(my_perl);
  iRet = perl_parse(my_perl, xs_init, m_perl_argc, m_perl_argv, NULL);
  iRet = perl_run(my_perl);
  sp = PL_stack_sp;

  PERL_SET_CONTEXT(my_perl);
  SPAGAIN;
  ENTER;
  SAVETMPS;
  PUSHMARK(sp);

  SV *err_tmp;
  PUTBACK;
  int nCount = perl_call_pv((char *)sSubroutine, G_SCALAR|G_EVAL);
  SPAGAIN;
  err_tmp = ERRSV;
  if (SvTRUE(err_tmp))
:

Thanks
Lee

@p5pRT
Copy link
Author

p5pRT commented May 22, 2018

From Lee.Staniforth@synchronoss.com

Hi,
So, I have added some additional trace statements to my application, and can see the address of my_perl changes when I'm in my application to when I print out from libperl.

lees​: MDS. Before perl_parse() my_perl=@​▒▒ (Address=0xD35528)
lees libperl​: Leaving perl_parse
lees libperl​: Address of my_perl=7ffed1a010c8
lees​: MDS. After perl_parse() my_perl=@​▒▒ (Address=0xD35528)

Here's my code snippet, from my application (MDS)​:
  printf("lees​: MDS. Before perl_parse() my_perl=%s (Address=%p)\n", my_perl, &my_perl);
  iRet = perl_parse(my_perl, xs_init, m_perl_argc, m_perl_argv, NULL);
  printf("lees​: MDS. After perl_parse() my_perl=%s (Address=%p)\n", my_perl, &my_perl);

And similar code in perl_parse​:
  PerlIO_stdoutf("lees libperl​: Leaving perl_parse\n");
  PerlIO_stdoutf("lees libperl​: Address of my_perl=%p\n", &my_perl);

So, the address of my_perl has changed from 0xD35528 to 7ffed1a010c8
This is allocated during a call of perl_alloc.
Here's my code​:
  printf("lees​: MDS. Before perl_alloc() my_perl=%s (Address=%p)\n", my_perl, &my_perl);
  my_perl = perl_alloc();
  printf("lees​: MDS. After perl_alloc() my_perl=%s (Address=%p)\n", my_perl, &my_perl);

Here's how I declare my_perl in my code​:
protected​:
  PerlInterpreter *my_perl;

This is perl_alloc()​:
PerlInterpreter *
perl_alloc(void)
{
  PerlInterpreter *my_perl;

  /* Newx() needs interpreter, so call malloc() instead */
  my_perl = (PerlInterpreter*)PerlMem_malloc(sizeof(PerlInterpreter));

  S_init_tls_and_interp(my_perl);
#ifndef PERL_TRACK_MEMPOOL
  return (PerlInterpreter *) ZeroD(my_perl, 1, PerlInterpreter);
#else
  Zero(my_perl, 1, PerlInterpreter);
  INIT_TRACK_MEMPOOL(PL_memory_debug_header, my_perl);

  return my_perl;
#endif

Putting some PerlIO_stdoutf() around that caused issues in that the make crashed, but it looks as though the code returns on this line​:
  return (PerlInterpreter *) ZeroD(my_perl, 1, PerlInterpreter);
because I don’t have PERL_TRACK_MEMPOOL defined.

I will build a debug version of libperl now to investigate further, but it doesn't make sense... The address should be consistent inside the libperl functions as outside. My application is built as debug.

Lee

@p5pRT
Copy link
Author

p5pRT commented May 22, 2018

From @tonycoz

On Sat, May 19, 2018 at 03​:52​:35PM +0100, Dave Mitchell wrote​:

On Fri, May 18, 2018 at 07​:49​:47AM -0700, Lee Staniforth (via RT) wrote​:

err\_tmp = ERRSV;      \<==========================================Crash here

I haven't looked very hard, but I notice you perl is built with threading
support, so every perl function has an implicit pTHX (aka my_perl) as its
first parameter, and variables like PL_errgv get redefined as
my_perl->Ierrgv.

However, in your function which uses ERRSV, I can't see any usage of
pTHX nor dTHX, so I can't see how my_perl is getting declared.

I don't see dSP either (for PUTBACK/SPAGAIN), I suspect they're being
kept in the CPerlProvider object rather than being defined locally to
the method. Presumably other methods are setting up arguments.

Tony

@p5pRT
Copy link
Author

p5pRT commented May 22, 2018

From @tonycoz

On Mon, 21 May 2018 17​:46​:36 -0700, Lee.Staniforth@​synchronoss.com wrote​:

lees​: MDS. Before perl_parse() my_perl=@​▒▒ (Address=0xD35528)
lees libperl​: Leaving perl_parse
lees libperl​: Address of my_perl=7ffed1a010c8
lees​: MDS. After perl_parse() my_perl=@​▒▒ (Address=0xD35528)

Here's my code snippet, from my application (MDS)​:
printf("lees​: MDS. Before perl_parse() my_perl=%s (Address=%p)\n",
my_perl, &my_perl);
iRet = perl_parse(my_perl, xs_init, m_perl_argc, m_perl_argv,
NULL);
printf("lees​: MDS. After perl_parse() my_perl=%s (Address=%p)\n",
my_perl, &my_perl);

And similar code in perl_parse​:
PerlIO_stdoutf("lees libperl​: Leaving perl_parse\n");
PerlIO_stdoutf("lees libperl​: Address of my_perl=%p\n", &my_perl);

So, the address of my_perl has changed from 0xD35528 to 7ffed1a010c8

From what you're saying you added that code to perl_parse in
perl itself, so of course the address of my_perl has changed - inside libperl &my_perl is typcially going to be the address of the local variable, while in your code it will be the address of the my_perl member variable inside your object (assuming that's where you're keeping it)

The important thing is the value of my_perl, not its address.

Unfortunately I can't see the cause of your problem, a complete test case might help, though I suspect your code is considered proprietary.

Tony

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

2 participants