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

should goto &NAME free lexicals? #7118

Closed
p5pRT opened this issue Feb 20, 2004 · 8 comments
Closed

should goto &NAME free lexicals? #7118

p5pRT opened this issue Feb 20, 2004 · 8 comments

Comments

@p5pRT
Copy link

p5pRT commented Feb 20, 2004

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

Searchable as RT26959$

@p5pRT
Copy link
Author

p5pRT commented Feb 20, 2004

From sorourke@cs.ucsd.edu

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

@p5pRT
Copy link
Author

p5pRT commented Feb 24, 2004

From whatever@davidnicol.com

the C<goto &NAME> construct is not for tail recursion, but
is for fooling the C<caller> function.

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 = &amp;{"${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.

@p5pRT
Copy link
Author

p5pRT commented Feb 24, 2004

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

@p5pRT
Copy link
Author

p5pRT commented Feb 24, 2004

From @iabyn

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<caller> 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

@p5pRT
Copy link
Author

p5pRT commented Feb 24, 2004

From whatever@davidnicol.com

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<caller> 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.

@p5pRT
Copy link
Author

p5pRT commented Feb 24, 2004

From @iabyn

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

@p5pRT
Copy link
Author

p5pRT commented Feb 24, 2004

From @iabyn

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<caller> 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.

@p5pRT p5pRT closed this as completed Feb 25, 2004
@p5pRT
Copy link
Author

p5pRT commented Feb 25, 2004

@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