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

Deep recursion on subroutine "CGI::Carp::warn" #8015

Closed
p5pRT opened this issue Jul 12, 2005 · 14 comments
Closed

Deep recursion on subroutine "CGI::Carp::warn" #8015

p5pRT opened this issue Jul 12, 2005 · 14 comments

Comments

@p5pRT
Copy link

p5pRT commented Jul 12, 2005

Migrated from rt.perl.org#36521 (status was 'resolved')

Searchable as RT36521$

@p5pRT
Copy link
Author

p5pRT commented Jul 12, 2005

From dmuell@gmx.net

This is a bug report for perl from dmuell@​gmx.net,
generated with the help of perlbug 1.35 running under perl v5.8.6.


running this test application crashes perl 5.8.6 or newer (5.8.5 and
older works fine)​:

=== Cut ===
#!/usr/bin/perl

use CGI​::Carp qw(fatalsToBrowser);
use diagnostics;

warn "foo";
=== Cut ===

output is a lot of garbage, and then​:

Deep recursion on subroutine "CGI​::Carp​::warn" at /usr/lib/perl5/5.8.6/diagnostics.pm line 506.
Segmentation fault (core dumped)



Flags​:
  category=core
  severity=high


This perlbug was built using Perl v5.8.6 - Fri Jun 24 16​:05​:45 UTC 2005
It is being executed now by Perl v5.8.6 - Fri Jun 24 16​:00​:32 UTC 2005.

Site configuration information for perl v5.8.6​:

Configured by abuild at Fri Jun 24 16​:00​:32 UTC 2005.

Summary of my perl5 (revision 5 version 8 subversion 6) configuration​:
  Platform​:
  osname=linux, osvers=2.6.12, archname=i586-linux-thread-multi
  uname='linux salieri 2.6.12 #1 smp tue jun 21 14​:03​:10 utc 2005 i686 athlon i386 gnulinux '
  config_args='-ds -e -Dprefix=/usr -Dvendorprefix=/usr -Dinstallusrbinperl -Dusethreads -Di_db -Di_dbm -Di_ndbm -Di_gdbm -Duseshrplib=true -Doptimize=-O2 -march=i586 -mtune=i686 -fmessage-length=0 -Wall -D_FORTIFY_SOURCE=2 -g -Wall -pipe'
  hint=recommended, useposix=true, d_sigaction=define
  usethreads=define use5005threads=undef useithreads=define usemultiplicity=define
  useperlio=define d_sfio=undef uselargefiles=define usesocks=undef
  use64bitint=undef use64bitall=undef uselongdouble=undef
  usemymalloc=n, bincompat5005=undef
  Compiler​:
  cc='cc', ccflags ='-D_REENTRANT -D_GNU_SOURCE -DTHREADS_HAVE_PIDS -DDEBUGGING -fno-strict-aliasing -pipe -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64',
  optimize='-O2 -march=i586 -mtune=i686 -fmessage-length=0 -Wall -D_FORTIFY_SOURCE=2 -g -Wall -pipe',
  cppflags='-D_REENTRANT -D_GNU_SOURCE -DTHREADS_HAVE_PIDS -DDEBUGGING -fno-strict-aliasing -pipe'
  ccversion='', gccversion='4.0.1 20050621 (prerelease) (SUSE Linux)', gccosandvers=''
  intsize=4, longsize=4, ptrsize=4, doublesize=8, byteorder=1234
  d_longlong=define, longlongsize=8, d_longdbl=define, longdblsize=12
  ivtype='long', ivsize=4, nvtype='double', nvsize=8, Off_t='off_t', lseeksize=8
  alignbytes=4, prototype=define
  Linker and Libraries​:
  ld='cc', ldflags =''
  libpth=/lib /usr/lib /usr/local/lib
  libs=-lnsl -ldl -lm -lcrypt -lutil -lpthread -lc
  perllibs=-lnsl -ldl -lm -lcrypt -lutil -lpthread -lc
  libc=, so=so, useshrplib=true, libperl=libperl.so
  gnulibc_version='2.3.5'
  Dynamic Linking​:
  dlsrc=dl_dlopen.xs, dlext=so, d_dlsymun=undef, ccdlflags='-Wl,-E -Wl,-rpath,/usr/lib/perl5/5.8.6/i586-linux-thread-multi/CORE'
  cccdlflags='-fPIC', lddlflags='-shared'

Locally applied patches​:
 


@​INC for perl v5.8.6​:
  /usr/lib/perl5/5.8.6/i586-linux-thread-multi
  /usr/lib/perl5/5.8.6
  /usr/lib/perl5/site_perl/5.8.6/i586-linux-thread-multi
  /usr/lib/perl5/site_perl/5.8.6
  /usr/lib/perl5/site_perl
  /usr/lib/perl5/vendor_perl/5.8.6/i586-linux-thread-multi
  /usr/lib/perl5/vendor_perl/5.8.6
  /usr/lib/perl5/vendor_perl
  .


Environment for perl v5.8.6​:
  HOME=/home/dirk
  LANG=en_US.UTF-8
  LANGUAGE (unset)
  LD_LIBRARY_PATH (unset)
  LOGDIR (unset)
  PATH=/opt/gcc/bin​:/home/dirk/bin​:/usr/local/bin​:/usr/bin​:/usr/X11R6/bin​:/bin​:/usr/games​:/opt/gnome/bin​:/opt/kde3/bin​:/opt/kde/bin​:/usr/lib/jvm/jre/bin​:/usr/lib/mit/bin​:/usr/lib/mit/sbin​:/opt/kde/bin​:/home/dirk/src/kde/qt/bin
  PERL_BADLANG (unset)
  SHELL=/bin/bash

@p5pRT
Copy link
Author

p5pRT commented Jul 13, 2005

From dmuell@gmx.net

On Wednesday 13 July 2005 00​:11, perlbug-followup@​perl.org wrote​:

perlbug-followup@​perl.org

And this patch fixes it​:

--- lib/diagnostics.pm
+++ lib/diagnostics.pm
@​@​ -503,7 +503,7 @​@​
  print STDERR $warning;
  }
  }
- goto &$oldwarn if defined $oldwarn and $oldwarn and $oldwarn ne
\&warn_trap;
+ &$oldwarn if defined $oldwarn and $oldwarn and $oldwarn ne \&warn_trap;
};

sub death_trap {

Dirk

@p5pRT
Copy link
Author

p5pRT commented Jul 13, 2005

From @schwern

On Tue, Jul 12, 2005 at 03​:11​:49PM -0700, dmuell @​ gmx. net wrote​:

=== Cut ===
#!/usr/bin/perl

use CGI​::Carp qw(fatalsToBrowser);
use diagnostics;

warn "foo";
=== Cut ===

output is a lot of garbage, and then​:

Deep recursion on subroutine "CGI​::Carp​::warn" at /usr/lib/perl5/5.8.6/diagnostics.pm line 506.
Segmentation fault (core dumped)

Deep recursion on subroutine "CGI​::Carp​::warn" at /usr/local/perl/bleadperl/lib/5.9.3/diagnostics.pm line 506.

Program received signal EXC_BAD_ACCESS, Could not access memory.
0x000bec6c in Perl_pad_push ()
(gdb) bt
#0 0x000bec6c in Perl_pad_push ()
#1 0x0007b620 in Perl_pp_goto ()
#2 0x000d1e5c in Perl_runops_standard ()
#3 0x0001e964 in Perl_call_sv ()
#4 0x00005e68 in Perl_vwarn ()
#5 0x000062b8 in Perl_vwarner ()
#6 0x00006078 in Perl_warner ()
#7 0x0007b60c in Perl_pp_goto ()
#8 0x000d1e5c in Perl_runops_standard ()
#9 0x0001e964 in Perl_call_sv ()
#10 0x00005e68 in Perl_vwarn ()
#11 0x00005fe8 in Perl_warn ()
#12 0x00067324 in Perl_pp_warn ()
#13 0x000d1e5c in Perl_runops_standard ()
#14 0x0001e964 in Perl_call_sv ()
#15 0x00005e68 in Perl_vwarn ()
#16 0x00005fe8 in Perl_warn ()
#17 0x00067324 in Perl_pp_warn ()
#18 0x000d1e5c in Perl_runops_standard ()
#19 0x0001e964 in Perl_call_sv ()
#20 0x00005e68 in Perl_vwarn ()
#21 0x00005fe8 in Perl_warn ()
#22 0x00067324 in Perl_pp_warn ()
#23 0x000d1e5c in Perl_runops_standard ()
...and so on until...
#503 0x000d1e5c in Perl_runops_standard ()
#504 0x0001e964 in Perl_call_sv ()
#505 0x00005e68 in Perl_vwarn ()
#506 0x00005fe8 in Perl_warn ()
#507 0x00067324 in Perl_pp_warn ()
#508 0x000d1e5c in Perl_runops_standard ()
#509 0x0001e394 in S_run_body ()
#510 0x0001dff4 in perl_run ()
#511 0x00002d60 in main ()
#512 0x00002780 in _start (argc=2, argv=0x0, envp=0xec09c) at /SourceCache/Csu/Csu-47/crt.c​:267
#513 0x8fe1a278 in __dyld__dyld_start ()

--
Michael G Schwern schwern@​pobox.com http​://www.pobox.com/~schwern
Ahh email, my old friend. Do you know that revenge is a dish that is best
served cold? And it is very cold on the Internet!

@p5pRT
Copy link
Author

p5pRT commented Jul 13, 2005

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

@p5pRT
Copy link
Author

p5pRT commented Jul 13, 2005

From @schwern

On Wed, Jul 13, 2005 at 03​:51​:38AM +0200, Dirk Mueller wrote​:

And this patch fixes it​:

--- lib/diagnostics.pm
+++ lib/diagnostics.pm
@​@​ -503,7 +503,7 @​@​
print STDERR $warning;
}
}
- goto &$oldwarn if defined $oldwarn and $oldwarn and $oldwarn ne
\&warn_trap;
+ &$oldwarn if defined $oldwarn and $oldwarn and $oldwarn ne \&warn_trap;
};

sub death_trap {

No, that goto is important. It ensures the old warning handler is called
in the same caller context as when diagnostics.pm is not there.

  #!/usr/bin/perl -w

  BEGIN { $SIG{__WARN__} = sub { print join "\n", caller, @​_ } }
  use diagnostics;

  warn "foo";

If you run that with and without "use diagnostics" the output from the
__WARN__ handler should be the same, it should think its called from line
6. With your patch it thinks its called from inside diagnostics.pm.

The problem is the use of goto &foo inside a __WARN__ when &foo also calls
warn(). I suspect whatever magic that keeps warn() from calling
$SIG{__WARN__} when its already inside one is lost.

  #!/sw/bin/perl -w

  my $warn = sub { warn(join "\n", caller, @​_) };

  $SIG{__WARN__} = sub {
  # &$warn; # this is ok
  goto &$warn; # this segfaults
  };

  warn "foo";

--
Michael G Schwern schwern@​pobox.com http​://www.pobox.com/~schwern
Reality is that which, when you stop believing in it, doesn't go away.
  -- Phillip K. Dick

@p5pRT
Copy link
Author

p5pRT commented Jul 17, 2005

From @iabyn

On Wed, Jul 13, 2005 at 01​:40​:03PM -0700, Michael G Schwern wrote​:

The problem is the use of goto &foo inside a __WARN__ when &foo also calls
warn(). I suspect whatever magic that keeps warn() from calling
$SIG{__WARN__} when its already inside one is lost.

#!/sw/bin/perl -w

my $warn = sub { warn(join "\n", caller, @​_) };

$SIG{__WARN__} = sub {
# &$warn; # this is ok
goto &$warn; # this segfaults
};

warn "foo";

the disabling of $SIG{__WARN__} was done by cheking the call depth of the
associated sub. The goto &foo ensured that this was always at zero.

The change below fixes this by localsised PL_warnhook t6o zero within a
call to a warn hook.

--
Britain, Britain, Britain! Discovered by Sir Henry Britain in
sixteen-oh-ten. Sold to Germany a year later for a pfennig and the promise
of a kiss. Destroyed in eighteen thirty-fourty two, and rebuilt a week
later by a man. This we know. Hello. But what of the people of Britain?
Who they? What do? And why? -- Little Britain

Change 25160 by davem@​davem-splatty on 2005/07/17 20​:12​:54

  $SIG{__WARN__} = sub { goto &foo } could recurse infinitely

Affected files ...

... //depot/perl/t/op/goto.t#30 edit
... //depot/perl/util.c#484 edit

Differences ...

==== //depot/perl/t/op/goto.t#30 (xtext) ====

@​@​ -10,7 +10,7 @​@​

use warnings;
use strict;
-plan tests => 56;
+plan tests => 57;

our $foo;
while ($?) {
@​@​ -436,3 +436,13 @​@​
like($@​, qr/Can't goto subroutine from an eval-string/, 'eval string');
eval { goto &null };
like($@​, qr/Can't goto subroutine from an eval-block/, 'eval block');
+
+# [perl #36521] goto &foo in warn handler could defeat recursion avoider
+
+{
+ my $r = runperl(
+ stderr => 1,
+ prog => 'my $d; my $w = sub { return if $d++; warn q(bar)}; local $SIG{__WARN__} = sub { goto &$w; }; warn q(foo);'
+ );
+ like($r, qr/bar/, "goto &foo in warn");
+}

==== //depot/perl/util.c#484 (text) ====

@​@​ -1278,6 +1278,8 @​@​
  SV *msg;

  ENTER;
+ SAVESPTR(PL_warnhook);
+ PL_warnhook = Nullsv;
  save_re_context();
  msg = newSVpvn(message, msglen);
  SvFLAGS(msg) |= utf8;

@p5pRT
Copy link
Author

p5pRT commented Jul 17, 2005

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

@p5pRT
Copy link
Author

p5pRT commented Jul 17, 2005

From @schwern

[davem@​iabyn.com - Sun Jul 17 13​:42​:34 2005]​:

On Wed, Jul 13, 2005 at 01​:40​:03PM -0700, Michael G Schwern wrote​:

The problem is the use of goto &foo inside a __WARN__ when &foo also
calls
warn(). I suspect whatever magic that keeps warn() from calling
$SIG{__WARN__} when its already inside one is lost.

#!/sw/bin/perl -w

my $warn = sub { warn(join "\n", caller, @​_) };

$SIG{__WARN__} = sub {
# &$warn; # this is ok
goto &$warn; # this segfaults
};

warn "foo";

the disabling of $SIG{__WARN__} was done by cheking the call depth of the
associated sub. The goto &foo ensured that this was always at zero.

The change below fixes this by localsised PL_warnhook t6o zero within a
call to a warn hook.

@p5pRT
Copy link
Author

p5pRT commented Jul 17, 2005

@schwern - Status changed from 'resolved' to 'open'

@p5pRT
Copy link
Author

p5pRT commented Jul 17, 2005

From @schwern

On Sun, Jul 17, 2005 at 09​:41​:58PM +0100, Dave Mitchell wrote​:

+# [perl #36521] goto &foo in warn handler could defeat recursion avoider
+
+{
+ my $r = runperl(
+ stderr => 1,
+ prog => 'my $d; my $w = sub { return if $d++; warn q(bar)}; local $SIG{__WARN__} = sub { goto &$w; }; warn q(foo);'
+ );
+ like($r, qr/bar/, "goto &foo in warn");

This program does not segfault, it does nothing.

0 ~$ perl5.8.6 -wle 'my $d; my $w = sub { return if $d++; warn q(bar)}; local $SIG{__WARN__} = sub { goto &$w; }; warn q(foo);'
0 ~$

I think the problem is you have code to deliberately avoid the recursion in
the subroutine. "return if $d++". Get rid of that and it segfaults.

0 ~$ perl5.8.6 -wle 'my $d; my $w = sub { warn @​_}; $SIG{__WARN__} = sub { goto &$w; }; warn q(foo);'
Bus error
0 ~$

--
Michael G Schwern schwern@​pobox.com http​://www.pobox.com/~schwern
Don't try the paranormal until you know what's normal.
  -- "Lords and Ladies" by Terry Prachett

@p5pRT
Copy link
Author

p5pRT commented Jul 17, 2005

From @iabyn

On Sun, Jul 17, 2005 at 02​:27​:35PM -0700, Michael G Schwern wrote​:

On Sun, Jul 17, 2005 at 09​:41​:58PM +0100, Dave Mitchell wrote​:

+# [perl #36521] goto &foo in warn handler could defeat recursion avoider
+
+{
+ my $r = runperl(
+ stderr => 1,
+ prog => 'my $d; my $w = sub { return if $d++; warn q(bar)}; local $SIG{__WARN__} = sub { goto &$w; }; warn q(foo);'
+ );
+ like($r, qr/bar/, "goto &foo in warn");

This program does not segfault, it does nothing.

0 ~$ perl5.8.6 -wle 'my $d; my $w = sub { return if $d++; warn q(bar)}; local $SIG{__WARN__} = sub { goto &$w; }; warn q(foo);'
0 ~$

That's the idea. In fixed bleed, it prints a warning​:

$ ./perl -wle 'my $d; my $w = sub { return if $d++; warn q(bar)}; local $SIG{__WARN__} = sub { goto &$w; }; warn q(foo);'
bar at -e line 1.
$

The test minimally detects bad behaviour while avoiding runaway recursion
and segfault.

--
"Emacs isn't a bad OS once you get used to it.
It just lacks a decent editor."

@p5pRT
Copy link
Author

p5pRT commented Jul 17, 2005

From @schwern

On Mon, Jul 18, 2005 at 12​:07​:23AM +0100, Dave Mitchell wrote​:

+{
+ my $r = runperl(
+ stderr => 1,
+ prog => 'my $d; my $w = sub { return if $d++; warn q(bar)}; local $SIG{__WARN__} = sub { goto &$w; }; warn q(foo);'
+ );
+ like($r, qr/bar/, "goto &foo in warn");

This program does not segfault, it does nothing.

0 ~$ perl5.8.6 -wle 'my $d; my $w = sub { return if $d++; warn q(bar)}; local $SIG{__WARN__} = sub { goto &$w; }; warn q(foo);'
0 ~$

That's the idea. In fixed bleed, it prints a warning​:

$ ./perl -wle 'my $d; my $w = sub { return if $d++; warn q(bar)}; local $SIG{__WARN__} = sub { goto &$w; }; warn q(foo);'
bar at -e line 1.
$

The test minimally detects bad behaviour while avoiding runaway recursion
and segfault.

But with runperl() its ok to segfault, its run in a different process. You
can even reduce it using fresh_perl_like().

fresh_perl_like(<<'CODE', qr/bar/);
  my $w = sub { warn q(bar) }; local $SIG{__WARN__} = sub { goto &$w; }; warn q(foo);
CODE

--
Michael G Schwern schwern@​pobox.com http​://www.pobox.com/~schwern
Insulting our readers is part of our business model.
  http​://somethingpositive.net/sp07122005.shtml

@p5pRT
Copy link
Author

p5pRT commented Jul 18, 2005

From @iabyn

On Sun, Jul 17, 2005 at 04​:25​:19PM -0700, Michael G Schwern wrote​:

On Mon, Jul 18, 2005 at 12​:07​:23AM +0100, Dave Mitchell wrote​:
But with runperl() its ok to segfault, its run in a different process.

I know. Orignally I was trying to write the test to run in the same process
(thus the need to avoid segfault), but couldn't get round the fact that
when working correctly, it needed to write to STDERR, which is why I then
bunged it in a freshperl.

You can even reduce it using fresh_perl_like().

Ooh, I'll try to remember that in future.

--
SCO - a train crash in slow motion

@p5pRT p5pRT closed this as completed Jul 18, 2005
@p5pRT
Copy link
Author

p5pRT commented Jul 18, 2005

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

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