develooper Front page | perl.perl5.porters | Postings from March 2023

feature-class compiletime memory leak and SAVEDESTRUCTOR

Thread Next
From:
Paul "LeoNerd" Evans
Date:
March 20, 2023 18:05
Subject:
feature-class compiletime memory leak and SAVEDESTRUCTOR
Message ID:
20230320180515.4f19e35e@shy.leonerd.org.uk
This is one of those "I want to do A so I can do B so I can solve bug
C" situations; the story is a little long-winded so I'll give a brief
overview and then dive into detail. Maybe someone can point out a
better approach?

## The Problem

5.37.9 (and likely upcoming 5.37.10) has a memory leak related to the
feature 'class' if a compiletime syntax error occurs at a certain point
in the code. Namely, the point at which it checks for disallowed
control flow in a field initialiser expression:

  $ perl5.37.9 -Mexperimental=class
    class XXX {
       field $yyy = do { say "Hello world"; last };
    }

  Can't "last" out of field initialiser expression at - line ...

The leak is that the already-compiled OP_SAY and its arguments (the
OP_CONST of "Hello world") don't get freed again. They belong to the
"suspended compilation CV" that was stored in the XXX class, that would
be the container for all of the field initialiser expressions and would
get compiled up into a single initfields CV to be stored in the class.
Because compilation was aborted, that never happened.

Or, actually the situation is more complicated than that. We can't
compile the CV yet out of any single `field` expression, because the
entire point is that we're collecting them all up together in a single
CV at the end. That has to be deferred until the end of the class
declaration. This is a job for the Perl_class_seal_stash() function.

In the current implementation we arrange for that function to be
invoked by calling SAVEDESTRUCTOR_X() with it, so that at the end of
the current block that gets invoked.

  https://github.com/Perl/perl5/blob/75ea41ae51200ab26d84c418f08859a784a71b85/class.c#L374

Because of this, it means we ensure the class gets sealed in any of
these interesting cases:

  class XX1 { ... }

  class XX2; ...; ((EOF))

  class XX3; ...; class XX4; ... ((EOF))

  { class XX5; ... } (more code here...)

*However*, the use of SAVEDESTRUCTOR_X is nonideal here because it also
gets invoked on exceptional unwind due to, in this case, syntax error.
The function doesn't have enough information to know that there's no
point compiling the CV, and instead it should abort the entire thing
and throw it all away.

What is needed here, is a way to call Perl_class_seal_stash() only on
successful return from the containing block, and call some other code
to abort the compilation and throw things away on a failure.

I don't know of an existing mechanism to do this.


## Possible Solutions

A few ideas come to mind:

 * A new kind of SAVEDESTRUCTOR_... whose function is invoked being
   told *why* the stack is being unwound - success or failure. It can
   decide on that

 * Finish implementing the currently-stalled `PL_throwing` idea, so
   that the destructor function can just ask that to find out
     https://github.com/Perl/perl5/pull/20407

 * Don't use SAVEDESTRUCTOR for this, but instead add a new storage
   somewhere (maybe a new AV* in intrpvars) that stores classes which
   need sealing. Push to it instead, and flush it out in
   Perl_block_end().

   This would need some careful safety around keeping a "floor" and
   ensuring that multiple nested blocks with classes in all happened at
   the right times, but should be doable.

I kinda don't like any of those solutions. They're all kinda icky. Plus
none of them are the kind of thing we can get in in time for 5.38.0.

But it strikes me that surely this can't be the first situation for
needing something like this? Surely all over the place there must be
code that in some way creates a kindof "run this only on success" /
"only on fail" setup. I just don't know of any so far. Can anyone point
me at anything similar?


I suspect this "syntax errors can cause compiletime memory leaks" bug
will have to remain for now. It's a bit annoying but at least it
doesn't affect well-formed programs, only ones that are erroneous
anyway. If nothing else happens, I'll at least put a note in the
perldelta under "known bugs".

-- 
Paul "LeoNerd" Evans

leonerd@leonerd.org.uk      |  https://metacpan.org/author/PEVANS
http://www.leonerd.org.uk/  |  https://www.tindie.com/stores/leonerd/

Thread Next


nntp.perl.org: Perl Programming lists via nntp and http.
Comments to Ask Bjørn Hansen at ask@perl.org | Group listing | About