www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - A CTFE Segfault (with explanation, but I'm not sure what the fix

reply Gareth Charnock <gareth.charnock gmail.com> writes:
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.
Nov 21 2010
parent reply Brad Roberts <braddr puremagic.com> writes:
On 11/21/2010 2:11 PM, Gareth Charnock wrote:
 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.
Please file a bug report: http://d.puremagic.com/issues/
Nov 21 2010
parent Gareth Charnock <gareth.charnock gmail.com> writes:
Done.

http://d.puremagic.com/issues/show_bug.cgi?id=5248

I'm sorry if I'm a bit over-cautious before submitting bugs.

On 21/11/10 22:18, Brad Roberts wrote:
 On 11/21/2010 2:11 PM, Gareth Charnock wrote:
 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.
Please file a bug report: http://d.puremagic.com/issues/
Nov 21 2010