This code makes the DMD compiler segfault

struct LeafType {
        string Compile_not_ovloaded() {
                return "expression";
        }
};

struct MatrixASTNode {
        LeafType Right;

        string Compile() {
                return  Right.Compile_not_ovloaded();
        }
};

void main() {
        enum AST = MatrixASTNode();
        enum s=AST.Compile();
}

I'm not sure if it's valid D, but MatrixASTNode.Compile seems like it should be evaluable at compile time. segfaults are bad anyway. A search with the keyword "segfault" didn't seem to turn up any existing bugs with promising titles, so I assume this is a new bug (I'll put it in bugzilla if nobody can think of an existing bug).

I've tried compiling a debug version of svn dmd and I traced the bug down to what appears to be a stack overflow. These two functions in interpret.c seem to call each other repeatedly.

Expression *ThisExp::interpret(InterState *istate)
{
    if (istate && istate->localThis)
        return istate->localThis->interpret(istate);
    error("value of 'this' is not known at compile time");
    return EXP_CANT_INTERPRET;
}

Expression *DotVarExp::interpret(InterState *istate)
{   Expression *e = EXP_CANT_INTERPRET;

#if LOG
    printf("DotVarExp::interpret() %s\n", toChars());
#endif

    Expression *ex = e1->interpret(istate); // <- we never get past here
    if (ex != EXP_CANT_INTERPRET)
    {
        if (ex->op == TOKstructliteral)
        {   StructLiteralExp *se = (StructLiteralExp *)ex;
            VarDeclaration *v = var->isVarDeclaration();
            if (v)
            {   e = se->getField(type, v->offset);
                if (!e)
                {
error("couldn't find field %s in %s", v->toChars(), type->toChars());
                    e = EXP_CANT_INTERPRET;
                }
                return e;
            }
        }
        else
error("%s.%s is not yet implemented at compile time", e1->toChars(), var->toChars());
    }


If you turn logging on for the file you get this:

CallExp::interpret() MatrixASTNode(LeafType()).Compile()

********
FuncDeclaration::interpret(istate = (nil)) Compile
cantInterpret = 0, semanticRun = 5
StructLiteralExp::interpret() MatrixASTNode(LeafType())
StructLiteralExp::interpret() LeafType()
CompoundStatement::interpret()
ExpStatement::interpret(assert(&this,"null this"))
AssertExp::interpret() assert(&this,"null this")
StructLiteralExp::interpret() MatrixASTNode(LeafType())
StructLiteralExp::interpret() LeafType()
ReturnStatement::interpret(this.Right.Compile_not_ovloaded())
CallExp::interpret() this.Right.Compile_not_ovloaded()

********
FuncDeclaration::interpret(istate = 0xbfe685a0) Compile_not_ovloaded
cantInterpret = 0, semanticRun = 5
DotVarExp::interpret() this.Right
StructLiteralExp::interpret() MatrixASTNode(LeafType())
StructLiteralExp::interpret() LeafType()
CompoundStatement::interpret()
ExpStatement::interpret(assert(&this,"null this"))
AssertExp::interpret() assert(&this,"null this")
DotVarExp::interpret() this.Right
DotVarExp::interpret() this.Right
DotVarExp::interpret() this.Right
DotVarExp::interpret() this.Right
...an so on until stack overflow


The reason for the recursion happens is that in the contect of DotVarExp::interpret istate->localThis == this so in ThisExp::interpret the statement

istate->localThis->interpret(istate);

goes right back to DotVarExp::interpret again.

Unfortunately I don't really know enough about the internals of dmd so say what the fix is, but I hope this information is helpful.


Reply via email to