Closed p5pRT closed 20 years ago
This is a bug report for perl from seano@cs.ucsd.edu\, generated with the help of perlbug 1.34 running under perl v5.8.3.
From the description in perlfunc\, I thought you could use "goto-&FUNC" for tail call elimination. However\, it looks like lexicals don't get freed. Try the following three programs:
perl -e 'sub foo { my $x = shift; print $x unless $x%100000; foo($x-1) } foo(1);'
perl -e 'sub foo { my $x = shift; print $x unless $x%100000; @_=($x-1);goto &foo }'
perl -e 'sub foo { print $_[0] unless $_[0]%100000; $_[0]--;goto &foo } foo($x=1)'
With 5.8.3 on OS X\, the first (of course) quickly grows out of control\, while the third does not. The second also grows out of control\, though more slowly than the first. My guess is that while the stack isn't growing\, lexicals and temps are still not being freed. Am I misusing goto?
Flags: category=core severity=low
Site configuration information for perl v5.8.3:
Configured by seanorourke at Sun Jan 25 10:48:24 PST 2004.
Summary of my perl5 (revision 5.0 version 8 subversion 3) configuration: Platform: osname=darwin\, osvers=6.8\, archname=darwin-thread-multi uname='darwin rh220-50.resnet.ucsd.edu 6.8 darwin kernel version 6.8: wed sep 10 15:20:55 pdt 2003; root:xnuxnu-344.49.obj~2release_ppc power macintosh powerpc ' config_args='' hint=previous\, 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 ='-pipe -fno-common -DPERL_DARWIN -no-cpp-precomp -fno-strict-aliasing -I/usr/local/include -I/opt/local/include -I/sw/include'\, optimize='-O3'\, cppflags='-no-cpp-precomp -pipe -fno-common -DPERL_DARWIN -no-cpp-precomp -fno-strict-aliasing -I/usr/local/include -I/opt/local/include -I/sw/include -pipe -fno-common -DPERL_DARWIN -no-cpp-precomp -fno-strict-aliasing -I/usr/local/include -I/opt/local/include -I/sw/include' ccversion=''\, gccversion='3.3 20030304 (Apple Computer\, Inc. build 1435)'\, gccosandvers='' intsize=4\, longsize=4\, ptrsize=4\, doublesize=8\, byteorder=4321 d_longlong=define\, longlongsize=8\, d_longdbl=define\, longdblsize=8 ivtype='long'\, ivsize=4\, nvtype='double'\, nvsize=8\, Off_t='off_t'\, lseeksize=8 alignbytes=8\, prototype=define Linker and Libraries: ld='cc'\, ldflags ='-flat_namespace -L/usr/local/lib -L/opt/local/lib -L/sw/lib' libpth=/usr/local/lib /opt/local/lib /usr/lib /sw/lib libs=-lgdbm -ldl -lm -lc perllibs=-ldl -lm -lc libc=/usr/lib/libc.dylib\, so=dylib\, useshrplib=false\, libperl=libperl.a gnulibc_version='' Dynamic Linking: dlsrc=dl_dyld.xs\, dlext=bundle\, d_dlsymun=undef\, ccdlflags=' ' cccdlflags='-flat_namespace -bundle -fPIC'\, lddlflags=' -flat_namespace -bundle -undefined suppress -L/usr/local/lib -L/opt/local/lib -L/sw/lib'
Locally applied patches:
@INC for perl v5.8.3: /opt/perl/lib/5.8.0 /opt/perl/lib/5.8.0/darwin /opt/perl/lib/site_perl /opt/perl/lib/site_perl/5.8.0 /opt/perl/lib/site_perl/5.8.0/darwin /usr/local/lib/perl5/5.8.3/darwin-thread-multi /usr/local/lib/perl5/5.8.3 /usr/local/lib/perl5/site_perl/5.8.3/darwin-thread-multi /usr/local/lib/perl5/site_perl/5.8.3 /usr/local/lib/perl5/site_perl /opt/perl/lib/5.8.0 /opt/perl/lib/site_perl/5.8.0 .
Environment for perl v5.8.3: DYLD_LIBRARY_PATH (unset) HOME=/Users/seanorourke LANG (unset) LANGUAGE (unset) LD_LIBRARY_PATH=/System/Library/Frameworks/JavaVM.framework/Versions/1.4.1/Libraries:/Users/seanorourke/lib:/usr/local/lib:/sw/lib LOGDIR (unset) PATH=/Users/seanorourke/bin:/usr/local/bin:/opt/local/bin:/usr/sbin:/sbin:/sw/bin:/sw/sbin:/Users/seanorourke/bin:/usr/local/bin:/opt/local/bin:/usr/sbin:/sbin:/sw/bin:/sw/sbin:/usr/bin:/bin:/sw/bin:/usr/local/bin:/usr/local/teTeX/bin/powerpc-apple-darwin-current:/usr/X11R6/bin:/usr/X11R6/bin PERLLIB=/opt/perl/lib/5.8.0:/opt/perl/lib/5.8.0/darwin:/opt/perl/lib/site_perl:/opt/perl/lib/site_perl/5.8.0:/opt/perl/lib/site_perl/5.8.0/darwin PERL_BADLANG (unset) PERL_INLINE_JAVA_JNI=1 SHELL=/usr/local/bin/zsh
the C\<goto &NAME> construct is not for tail recursion\, but
is for fooling the C\
I hope someone will correct me if I'm wrong\, but I don't think Perl has tail-recursion optimization. You can nonetheless fake it by keeping your variables in an object and calling a series of methods on the object instead of recursing\, or returning to a central dispatcher to keep the stack small\, as in the following code.
#!/usr/bin/perl { # fake tail recursion demonstration my $wheretonext = "foo";
sub foo_worker{ # in a real system there would be several of these my $x = shift; print "$x\n" unless $x % 100000; $wheretonext = "foo"; return 1+$x; };
sub call_my_foo{ # the dispatch routine
$nextval = 1;
for(;;){
$nextval = &{"${wheretonext}_worker"}($nextval);
};
}
}
call_my_foo();
__END__
That will run forever and not grow.
On Fri\, 2004-02-20 at 12:37\, Sean O'Rourke wrote:
From the description in perlfunc\, I thought you could use "goto-&FUNC" for tail call elimination. However\, it looks like lexicals don't get freed.
The RT System itself - Status changed from 'new' to 'open'
On Tue\, Feb 24\, 2004 at 12:00:22AM -0600\, david nicol wrote:
the C\<goto &NAME> construct is not for tail recursion\, but is for fooling the C\
function. I hope someone will correct me if I'm wrong\, but I don't think Perl has tail-recursion optimization.
Well\, C\<goto &foo> is deliberatley designed to pop the current call off the call stack and push a new one\, so the the reported bug is genuine. And C\<goto &foo> is intended as a poor-man's tail-recursion optimization.
-- There's a traditional definition of a shyster: a lawyer who\, when the law is against him\, pounds on the facts; when the facts are against him\, pounds on the law; and when both the facts and the law are against him\, pounds on the table. -- Eben Moglen referring to SCO
On Tue\, 2004-02-24 at 03:23\, Dave Mitchell wrote:
On Tue\, Feb 24\, 2004 at 12:00:22AM -0600\, david nicol wrote:
the C\<goto &NAME> construct is not for tail recursion\, but is for fooling the C\
function. I hope someone will correct me if I'm wrong\, but I don't think Perl has tail-recursion optimization.
Well\, C\<goto &foo> is deliberatley designed to pop the current call off the call stack and push a new one\, so the the reported bug is genuine. And C\<goto &foo> is intended as a poor-man's tail-recursion optimization.
Then it isn't just lexicals that aren't getting cleaned up:
perl -le '$x = 1; sub f(){ ++$x % 10000 or print $x; goto &f}; f'
leaks too.
-- david nicol War is hell.
On Fri\, Feb 20\, 2004 at 06:37:39PM -0000\, Sean O'Rourke wrote:
perl -e 'sub foo { my $x = shift; print $x unless $x%100000; @_=($x-1);goto &foo }'
The leak is tiggered by the assignment to @_. This causes a copy of the AV holding @_ to be left on the tmpstack. On each goto\, the tmpstack grows by one\, and another AV is leaked.
Fixed by the following change.
Dave.
-- To collect all the latest movies\, simply place an unprotected ftp server on the Internet\, and wait for the disk to fill....
Change 22373 by davem@davem-percy on 2004/02/24 23:25:52
[perl #26959] fix memory leak in @_ = ...; goto &sub
Affected files ...
... //depot/perl/pp_ctl.c#384 edit
Differences ...
==== //depot/perl/pp_ctl.c#384 (text) ====
@@ -2182\,6 +2182\,7 @@ char *label; int do_dump = (PL_op->op_type == OP_DUMP); static char must_have_label[] = "goto must have label"; + AV *oldav = Nullav;
label = 0; if (PL_op->op_flags & OPf_STACKED) { @@ -2242\,7 +2243\,7 @@ GvAV(PL_defgv) = cx->blk_sub.savearray; /* abandon @_ if it got reified */ if (AvREAL(av)) { - (void)sv_2mortal((SV*)av); /* delay until return */ + oldav = av; /* delay until return */ av = newAV(); av_extend(av\, items-1); AvFLAGS(av) = AVf_REIFY; @@ -2268\,6 +2269\,9 @@
/* Now do some callish stuff. */ SAVETMPS; + /* For reified @_\, delay freeing till return from new sub */ + if (oldav) + SAVEFREESV((SV*)oldav); SAVEFREESV(cv); /* later\, undo the 'avoid premature free' hack */ if (CvXSUB(cv)) { #ifdef PERL_XSUB_OLDSTYLE
On Tue\, Feb 24\, 2004 at 04:14:47AM -0600\, david nicol wrote:
On Tue\, 2004-02-24 at 03:23\, Dave Mitchell wrote:
On Tue\, Feb 24\, 2004 at 12:00:22AM -0600\, david nicol wrote:
the C\<goto &NAME> construct is not for tail recursion\, but is for fooling the C\
function. I hope someone will correct me if I'm wrong\, but I don't think Perl has tail-recursion optimization.
Well\, C\<goto &foo> is deliberatley designed to pop the current call off the call stack and push a new one\, so the the reported bug is genuine. And C\<goto &foo> is intended as a poor-man's tail-recursion optimization.
Then it isn't just lexicals that aren't getting cleaned up:
perl -le '$x = 1; sub f(){ ++$x % 10000 or print $x; goto &f}; f'
leaks too.
only prior to 5.8.1
-- My get-up-and-go just got up and went.
@iabyn - Status changed from 'open' to 'resolved'
Migrated from rt.perl.org#26959 (status was 'resolved')
Searchable as RT26959$