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

recursive require calls can cause a stack overflow #11278

Open
p5pRT opened this issue Apr 27, 2011 · 7 comments
Open

recursive require calls can cause a stack overflow #11278

p5pRT opened this issue Apr 27, 2011 · 7 comments

Comments

@p5pRT
Copy link

p5pRT commented Apr 27, 2011

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

Searchable as RT89356$

@p5pRT
Copy link
Author

p5pRT commented Apr 27, 2011

From @doy

Created by @doy

If you put a coderef into @​INC which itself calls require, perl will
eventually segfault due to a stack overflow. For instance​:

  perl -e 'unshift @​INC, sub { require $_[1] }; require Foo'

Perl Info

Flags:
    category=core
    severity=medium

Site configuration information for perl 5.10.1:

Configured by doy at Sun Apr 25 23:40:00 CDT 2010.

Summary of my perl5 (revision 5 version 10 subversion 1) configuration:
   
  Platform:
    osname=linux, osvers=2.6.33-arch, archname=x86_64-linux
    uname='linux zaon 2.6.33-arch #1 smp preempt sun apr 4 10:27:30 cest 2010 x86_64 intel(r) core(tm) i5 cpu m 520 @ 2.40ghz genuineintel gnulinux '
    config_args='-de -Dprefix=/home/doy/perl5/perlbrew/perls/perl-5.10.1'
    hint=recommended, useposix=true, d_sigaction=define
    useithreads=undef, usemultiplicity=undef
    useperlio=define, d_sfio=undef, uselargefiles=define, usesocks=undef
    use64bitint=define, use64bitall=define, uselongdouble=undef
    usemymalloc=n, bincompat5005=undef
  Compiler:
    cc='cc', ccflags ='-fno-strict-aliasing -pipe -fstack-protector -I/usr/local/include -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64',
    optimize='-O2',
    cppflags='-fno-strict-aliasing -pipe -fstack-protector -I/usr/local/include'
    ccversion='', gccversion='4.5.0', 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 /lib /usr/lib
    libs=-lnsl -lgdbm -ldb -ldl -lm -lcrypt -lutil -lc -lgdbm_compat
    perllibs=-lnsl -ldl -lm -lcrypt -lutil -lc
    libc=/lib/libc-2.11.1.so, so=so, useshrplib=false, libperl=libperl.a
    gnulibc_version='2.11.1'
  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'

Locally applied patches:
    


@INC for perl 5.10.1:
    /home/doy/perl5/local/
    /home/doy/perl5/local/lib/perl5/site_perl/5.10.0/i686-linux
    /home/doy/perl5/perlbrew/perls/perl-5.10.1/lib/5.10.1/x86_64-linux
    /home/doy/perl5/perlbrew/perls/perl-5.10.1/lib/5.10.1
    /home/doy/perl5/perlbrew/perls/perl-5.10.1/lib/site_perl/5.10.1/x86_64-linux
    /home/doy/perl5/perlbrew/perls/perl-5.10.1/lib/site_perl/5.10.1
    .


Environment for perl 5.10.1:
    HOME=/home/doy
    LANG=en_US.UTF-8
    LANGUAGE (unset)
    LD_LIBRARY_PATH (unset)
    LOGDIR (unset)
    PATH=/home/doy/perl5/perlbrew/bin:/home/doy/perl5/perlbrew/perls/current/bin:/home/doy/.bin/marathon:/home/doy/.bin/nethack:/home/doy/.bin:/usr/local/sbin:/usr/local/bin:/usr/lib/ccache/bin:/usr/local/bin:/usr/bin:/bin:/usr/local/sbin:/usr/sbin:/sbin:/usr/bin/core_perl
    PERL5LIB=/home/doy/perl5/local/:/home/doy/perl5/local/lib/perl5/site_perl/5.10.0/i686-linux
    PERLBREW_PATH=/home/doy/perl5/perlbrew/bin:/home/doy/perl5/perlbrew/perls/current/bin
    PERLBREW_PERL=perl-5.10.1
    PERLBREW_ROOT=/home/doy/perl5/perlbrew
    PERLBREW_VERSION=0.19
    PERL_BADLANG (unset)
    PERL_CPANM_OPT=-q --mirror file:///home/doy/perl5/minicpan/ --mirror http://mirrors.kernel.org/cpan/ --mirror http://search.cpan.org/CPAN --prompt
    SHELL=/bin/bash

@p5pRT
Copy link
Author

p5pRT commented Apr 27, 2011

From @jandubois

On Tue, 26 Apr 2011, Jesse Luehrs (via RT) wrote​:

If you put a coderef into @​INC which itself calls require, perl will
eventually segfault due to a stack overflow. For instance​:

perl -e 'unshift @​INC, sub { require $_[1] }; require Foo'

So what is the bug? That it segfaults instead of printing "Out of memory!\n"
and terminating with a non-zero exit code?

Or did you somehow expect it to not run out of memory?

I'm actually surprised how quickly it segfaults; I would have expected
it to gobble up a lot more memory first.

Cheers,
-Jan

@p5pRT
Copy link
Author

p5pRT commented Apr 27, 2011

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

@p5pRT
Copy link
Author

p5pRT commented Nov 20, 2011

From @cpansprout

On Wed Apr 27 16​:35​:02 2011, jdb wrote​:

On Tue, 26 Apr 2011, Jesse Luehrs (via RT) wrote​:

If you put a coderef into @​INC which itself calls require, perl will
eventually segfault due to a stack overflow. For instance​:

perl -e 'unshift @​INC, sub { require $_[1] }; require Foo'

So what is the bug? That it segfaults instead of printing "Out of
memory!\n"
and terminating with a non-zero exit code?

Or did you somehow expect it to not run out of memory?

I'm actually surprised how quickly it segfaults; I would have expected
it to gobble up a lot more memory first.

I think this is the kind of thing that should be classified as ‘won’t
fix’, as any attempt to limit the recursion might impede a legitimate
use of it. Or is there some way to tell when the end of the C stack is
nigh?

--

Father Chrysostomos

@p5pRT
Copy link
Author

p5pRT commented Nov 20, 2011

From @doy

On Sat, Nov 19, 2011 at 06​:47​:09PM -0800, Father Chrysostomos via RT wrote​:

On Wed Apr 27 16​:35​:02 2011, jdb wrote​:

On Tue, 26 Apr 2011, Jesse Luehrs (via RT) wrote​:

If you put a coderef into @​INC which itself calls require, perl will
eventually segfault due to a stack overflow. For instance​:

perl -e 'unshift @​INC, sub { require $_[1] }; require Foo'

So what is the bug? That it segfaults instead of printing "Out of
memory!\n"
and terminating with a non-zero exit code?

Or did you somehow expect it to not run out of memory?

I'm actually surprised how quickly it segfaults; I would have expected
it to gobble up a lot more memory first.

I think this is the kind of thing that should be classified as ‘won’t
fix’, as any attempt to limit the recursion might impede a legitimate
use of it. Or is there some way to tell when the end of the C stack is
nigh?

Well, my thought here was that it should at least not be recursing at
the C level, like most (all?) other keywords. Segfaulting due to running
out of C stack space from only pure-perl code feels like a bug to me. It
is possible that this is just too hard to fix though, I haven't looked
into the actual code behind it yet.

-doy

@p5pRT
Copy link
Author

p5pRT commented Nov 20, 2011

From @cpansprout

On Sat Nov 19 23​:03​:44 2011, doy@​tozt.net wrote​:

On Sat, Nov 19, 2011 at 06​:47​:09PM -0800, Father Chrysostomos via RT
wrote​:

On Wed Apr 27 16​:35​:02 2011, jdb wrote​:

On Tue, 26 Apr 2011, Jesse Luehrs (via RT) wrote​:

If you put a coderef into @​INC which itself calls require, perl will
eventually segfault due to a stack overflow. For instance​:

perl -e 'unshift @​INC, sub { require $_[1] }; require Foo'

So what is the bug? That it segfaults instead of printing "Out of
memory!\n"
and terminating with a non-zero exit code?

Or did you somehow expect it to not run out of memory?

I'm actually surprised how quickly it segfaults; I would have expected
it to gobble up a lot more memory first.

I think this is the kind of thing that should be classified as ‘won’t
fix’, as any attempt to limit the recursion might impede a legitimate
use of it. Or is there some way to tell when the end of the C stack is
nigh?

Well, my thought here was that it should at least not be recursing at
the C level, like most (all?) other keywords.

Magic method calls, DESTROY, BEGIN etc. use the C stack.

Segfaulting due to running
out of C stack space from only pure-perl code feels like a bug to me.

If I run out of other bugs to fix (how likely is that?) I might start to
agree. :-)

It
is possible that this is just too hard to fix though, I haven't looked
into the actual code behind it yet.

It would require splitting require into two or three ops. It would beb
complicated and would slow down normal use of require, which is why I’m
not sure it’s a good idea. The crashing example that you gave is
clearly wrong, and would still cause infinite recursion if this were
fixed (albeit on a different stack). Are there any real-world cases
that could cause this?

--

Father Chrysostomos

@p5pRT
Copy link
Author

p5pRT commented Nov 20, 2011

From @doy

On Sun, Nov 20, 2011 at 10​:50​:14AM -0800, Father Chrysostomos via RT wrote​:

On Sat Nov 19 23​:03​:44 2011, doy@​tozt.net wrote​:

On Sat, Nov 19, 2011 at 06​:47​:09PM -0800, Father Chrysostomos via RT
wrote​:

On Wed Apr 27 16​:35​:02 2011, jdb wrote​:

On Tue, 26 Apr 2011, Jesse Luehrs (via RT) wrote​:

If you put a coderef into @​INC which itself calls require, perl will
eventually segfault due to a stack overflow. For instance​:

perl -e 'unshift @​INC, sub { require $_[1] }; require Foo'

So what is the bug? That it segfaults instead of printing "Out of
memory!\n"
and terminating with a non-zero exit code?

Or did you somehow expect it to not run out of memory?

I'm actually surprised how quickly it segfaults; I would have expected
it to gobble up a lot more memory first.

I think this is the kind of thing that should be classified as ‘won’t
fix’, as any attempt to limit the recursion might impede a legitimate
use of it. Or is there some way to tell when the end of the C stack is
nigh?
It
is possible that this is just too hard to fix though, I haven't looked
into the actual code behind it yet.

It would require splitting require into two or three ops. It would beb
complicated and would slow down normal use of require, which is why I’m
not sure it’s a good idea. The crashing example that you gave is
clearly wrong, and would still cause infinite recursion if this were
fixed (albeit on a different stack). Are there any real-world cases
that could cause this?

The place where I ran into it was that I wanted some kind of
post-require hook, and thought that sticking a coderef in @​INC which
called require itself and then examined the results would be a
reasonable way to accomplish that. This seems to mostly work fine, but I
noticed the segfault when debugging it (I had accidentally caused it to
recurse infinitely at one point). It could still come up in a long
chain of modules requiring other modules, although that would admittedly
be pretty hard to run into in practice (but not as hard as I had
imagined it to be - the C stack seems to overflow at somewhere on the
order of magnitude of 10000 calls on my machine, and I'd imagine this to
be quite a bit lower in the presence of threads).

-doy

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