qorelanguage / qore

Qore Programming Language
GNU General Public License v2.0
61 stars 10 forks source link

Memory leak if self used during member initialization #37

Closed tethal closed 8 years ago

tethal commented 8 years ago

Code:

class A {
    public {
        any a = self;
    }
    destructor() { printf("A destroyed\n"); }
}

{
    A a();
    printf("Before\n");
}
printf("After\n");

Expected output:

Before
A destroyed
After

Actual output:

Before
After

Valgrind:

944,936 (24 direct, 944,912 indirect) bytes in 1 blocks are definitely lost in loss record 7,293 of 7,293
   at 0x4C2C100: operator new(unsigned long) (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
   by 0x5022C54: qore_class_private::execConstructor(AbstractQoreFunctionVariant const*, QoreListNode const*, ExceptionSink*) const (QoreClass.cpp:941)
   by 0x5032FE7: execConstructor (QoreClassIntern.h:2700)
   by 0x5032FE7: VarRefNewObjectNode::evalValueImpl(bool&, ExceptionSink*) const (VarRefNode.cpp:313)
   by 0x4F3CE7D: evalValue (ParseNode.h:129)
   by 0x4F3CE7D: ValueEvalRefHolder::ValueEvalRefHolder(AbstractQoreNode const*, ExceptionSink*) (QoreValue.cpp:438)
   by 0x50955B6: ParseNode::bigIntEvalImpl(ExceptionSink*) const (ParseNode.h:56)
   by 0x4EE237F: ExpressionStatement::execImpl(QoreValue&, ExceptionSink*) (ExpressionStatement.cpp:64)
   by 0x4F04AC3: AbstractStatement::exec(QoreValue&, ExceptionSink*) (AbstractStatement.cpp:54)
   by 0x4F4C496: StatementBlock::execIntern(QoreValue&, ExceptionSink*) (StatementBlock.cpp:221)
   by 0x4F7C64F: StatementBlock::execImpl(QoreValue&, ExceptionSink*) (StatementBlock.cpp:203)
   by 0x4F04AC3: AbstractStatement::exec(QoreValue&, ExceptionSink*) (AbstractStatement.cpp:54)
   by 0x4F4C496: StatementBlock::execIntern(QoreValue&, ExceptionSink*) (StatementBlock.cpp:221)
   by 0x5028C0E: exec (StatementBlock.cpp:168)
   by 0x5028C0E: QoreProgram::runTopLevel(ExceptionSink*) (QoreProgram.cpp:928)

Notes:

Creating the circular reference after the object is created works as expected:

class A {
    public {
        any a;
    }
    destructor() { printf("A destroyed\n"); }
}

{
    A a();
    a.a = a;
    printf("Before\n");
}
printf("After\n");

Also, creating it in the constructor works as well:

class A {
    public {
        any a;
    }
    constructor() {
        a = self;
    }
    destructor() { printf("A destroyed\n"); }
}

{
    A a();
    printf("Before\n");
}
printf("After\n");

There might be a connection to issue #38.

davidnich commented 8 years ago

also now that #38 has been fixed, this case also results in a memory leak that must be fixed here as well:

class A {
    public {
        any f = sub() {
            return self;
        };
    }
    destructor() {
        print("destroyed\n");
    }
}

A a();
davidnich commented 8 years ago

the issue with closures is a separate leak that will require enhancements to the deterministic GC algorithm and has been opened as #73