Memory leak with parrot interpreter (TT#1765)

Mariano Wahlmann dichoso at gmail.com
Tue Dec 28 20:11:46 UTC 2010


Hi,

Recently I've been researching the TT#1765 and the solution for that fix is
neither trivial nor simple this is why I'm opening it to a broader audience,

The following code is sufficient to exhibit the problem

.sub 'test' :main
    $P0 = new 'ParrotInterpreter'
.end

*(running it using valgrind with the --leak-test you can see lost blocks )
*
The sequence is the following.

1. master interpreter is created ( frontend/parrot/main.c )
2. the interpreter registers Parrot_really_destroy in its list of
"on_exit_handler" ( src/interp/inter_create.c )
3. a new ParrotInterper PMC is created and the interp is boxed in it (
src/global_setup )
4. IMCC creates new ParrotInterpreter PMC which creates a child interpreter
redoing steps 2,3

*At this point we have:
3 x Parrot Interpreter PMC ( step 3, step 4,  step 3 again )
2 x interpreters ( step 1, step 4 )
*
5. Program runs and IMCC finish
6. Parrot_x_exit is called for the master interp ( src/exit.c )
7. Parrot_really_destroy is called *only* for the master interpreter, it
calls the GC and the GC destroys all PMCs ( src/interp/inter_create.c )
8. VTABLE destroy is called for the 3 interpreters freeing *only* the
Parrot_ParrotInterpreter_attributes part and not the interpreter (
src/pmc/parrotinterpreter.pmc )
9. exit is called ( src/exit.c )

The result is that the child interpreter is never freed. The first question
might arise is "why 3 PMC and 2 interpreters?", well thats a problem in the
"Parrot_gbl_init_world_once()" it is being executed *again* for every child
interpreter

Parrot_gbl_init_world_once(PARROT_INTERP)
{
    ...
    if (!interp->world_inited) {

if the interpreter is new interp->world_inited is false and then it calls
the init_world() boxing the new interpreter into a new PMC. The result is 2
PMC holding the same interpreter.

Getting back to the original subject if we give "VTABLE destroy()" the
responsibility of destroying the interpreter we will have "double free"
corruption for the child interpreter, also it will break
"Parrot_really_destroy()" because it calls "VTABLE destroy()" in the middle
so we will have 2 functions trying to free the same thing.

The other problem is that an interpreter doesn't know who its children are,
so "on_exit" handlers for the children interpreters are never called, then
Parrot_really_destroy is never called for the children.

I think there are 3 action items:
  * Fix the Parrot_gbl_init_world_once to guarantee the "once" part
  * re-think the destroy mechanism for the interpreters and distribute
responsibilities better between "Parrot_really_destroy" and "VTABLE destroy"
  * think what should we do with the children's "on_exit" handlers

Thanks,
bluescreen
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.parrot.org/pipermail/parrot-dev/attachments/20101228/9ab8a4b4/attachment.html>


More information about the parrot-dev mailing list