Bug 11540 – [ICE] CTFE segfault with try-catch-finally and goto
Status
RESOLVED
Resolution
FIXED
Severity
critical
Priority
P2
Component
dmd
Product
D
Version
D2
Platform
All
OS
All
Creation time
2013-11-18T07:49:00Z
Last change time
2013-11-28T23:48:41Z
Keywords
CTFE, ice, pull
Assigned to
nobody
Creator
dmitry.olsh
Comments
Comment #0 by dmitry.olsh — 2013-11-18T07:49:27Z
Credit goes to Vladimir and his dustmite tool.
The following is auto-reduced test case:
enum IR:uint
{
Trie
}
struct Bytecode
{
uint raw;
@property data() { return raw ; }
@property code() { return cast()raw>>24; }
}
template BasicElementOf(Range)
{
alias typeof(Range.init) BasicElementOf;
}
struct Parser(R)
{
Bytecode[] ir;
CodepointSet[] charsets;
this(S)(R , S )
{
try
parseRegex;
catch(Exception e)
error(e.msg);
}
void put(Bytecode code)
{
ir ~= code;
}
@trusted parseRegex()
{
parseAtom;
}
void parseAtom()
{
parseEscape;
}
@trusted charsetToIr(CodepointSet set)
{
put(Bytecode());
charsets ~= set;
}
@trusted parseEscape()
{
charsetToIr(unicode.Nd);
}
@trusted error(string )
{
}
alias BasicElementOf!R Char;
Regex!Char program()
{
return Regex!Char(this);
}
}
struct Regex(Char)
{
CodepointSet[] charsets;
Bytecode[] ir;
@trusted lightPostprocess()
{
Kickstart!Char(this, new uint[](256));
}
this(S)(Parser!(S) p)
{
ir = p.ir;
charsets = p.charsets;
lightPostprocess;
}
}
struct ShiftOr(Char)
{
struct ShiftThread
{
uint pc;
}
this(Regex!Char re, uint[] )
{
ShiftThread t = ShiftThread();
switch(re.ir[t.pc].code)
{
case IR.Trie:
auto set = re.charsets[re.ir[t.pc].data];
goto L_OutOfLoop;
L_OutOfLoop:
;
}
}
}
alias ShiftOr Kickstart;
auto regex(S)(S pattern, const(char)[] flags="")
{
regexImpl(pattern);
}
auto regexImpl(S)(S pattern, const(char)[] flags="")
{
auto parser = Parser!(typeof(pattern))(pattern, flags);
parser.program;
}
template ctRegexImpl(alias pattern, string flags=[])
{
enum r = regex(pattern);
}
template ctRegex(alias pattern, alias flags=[])
{
enum ctRegex = ctRegexImpl!pattern;
}
struct GcPolicy
{
}
alias InversionList!GcPolicy CodepointSet;
struct InversionList(SP=GcPolicy)
{
alias size_t Marker;
Marker addInterval()
in
{
}
body
{
}
Uint24Array!SP data;
}struct Uint24Array(SP=GcPolicy)
{
~this()
{
}
}
struct unicode
{
static opDispatch(string name)()
{
return loadAny(name);
}
static loadAny(Set=CodepointSet, C)(C)
{
Set set;
return set;
}
}
void foo()
{
ctRegex!`(?P<Quot>\d+)`;
}
Comment #1 by dmitry.olsh — 2013-11-18T07:50:08Z
Backtrace in dmd's core file:
#0 0x000000000052c40a in CallExp::interpret(InterState*, CtfeGoal)
()
#1 0x00000000005233f1 in ExpStatement::interpret(InterState*) ()
#2 0x0000000000523471 in CompoundStatement::interpret(InterState*)
()
#3 0x000000000052a65e in FuncDeclaration::interpret(InterState*, Array<Expression>*, Expression*) ()
#4 0x000000000052c3fe in CallExp::interpret(InterState*, CtfeGoal)
()
#5 0x00000000005233f1 in ExpStatement::interpret(InterState*) ()
#6 0x0000000000523471 in CompoundStatement::interpret(InterState*)
()
#7 0x0000000000523471 in CompoundStatement::interpret(InterState*)
()
#8 0x0000000000523471 in CompoundStatement::interpret(InterState*)
()
#9 0x000000000052a65e in FuncDeclaration::interpret(InterState*, Array<Expression>*, Expression*) ()
#10 0x000000000052c3fe in CallExp::interpret(InterState*, CtfeGoal)
()
#11 0x0000000000523f1a in ReturnStatement::interpret(InterState*)
()
#12 0x0000000000523471 in CompoundStatement::interpret(InterState*)
()
#13 0x000000000052a65e in FuncDeclaration::interpret(InterState*, Array<Expression>*, Expression*) ()
#14 0x000000000052c3fe in CallExp::interpret(InterState*, CtfeGoal)
()
#15 0x00000000005233f1 in ExpStatement::interpret(InterState*) ()
#16 0x0000000000523471 in CompoundStatement::interpret(InterState*)
()
---Type <return> to continue, or q <return> to quit---
#17 0x0000000000523471 in CompoundStatement::interpret(InterState*)
()
#18 0x000000000052a65e in FuncDeclaration::interpret(InterState*, Array<Expression>*, Expression*) ()
#19 0x000000000052c3fe in CallExp::interpret(InterState*, CtfeGoal)
()
#20 0x00000000005233f1 in ExpStatement::interpret(InterState*) ()
#21 0x0000000000523471 in CompoundStatement::interpret(InterState*)
()
#22 0x000000000052a65e in FuncDeclaration::interpret(InterState*, Array<Expression>*, Expression*) ()
#23 0x000000000052c3fe in CallExp::interpret(InterState*, CtfeGoal)
()
#24 0x0000000000523c13 in Expression::ctfeInterpret() ()
#25 0x000000000049a955 in ExpInitializer::semantic(Scope*, Type*, NeedInterpret) ()
#26 0x000000000042ced0 in VarDeclaration::semantic2(Scope*) ()
#27 0x00000000004ff798 in TemplateInstance::semantic2(Scope*) ()
#28 0x000000000050abd0 in TemplateInstance::semantic(Scope*, Array<Expression>*) ()
#29 0x000000000046d35f in ScopeExp::semantic(Scope*) ()
#30 0x0000000000499423 in ExpInitializer::inferType(Scope*) ()
#31 0x0000000000430a2c in VarDeclaration::semantic(Scope*) [clone .part.31] ()
#32 0x0000000000507848 in TemplateInstance::expandMembers(Scope*)
()
#33 0x000000000050787f in TemplateInstance::tryExpandMembers(Scope*) ()
#34 0x000000000050a88a in TemplateInstance::semantic(Scope*, Array<Expression>*) ()
#35 0x000000000046d35f in ScopeExp::semantic(Scope*) ()
---Type <return> to continue, or q <return> to quit---
#36 0x00000000004ec52b in ExpStatement::semantic(Scope*) ()
#37 0x00000000004f2a9f in CompoundStatement::semantic(Scope*) ()
#38 0x00000000004788c9 in FuncDeclaration::semantic3(Scope*) ()
#39 0x00000000004aced8 in Module::semantic3() ()
#40 0x00000000004aa74c in tryMain(unsigned long, char const**) ()
#41 0x00007f5fbb62976d in __libc_start_main (main=0x402ba0 <main>,
argc=3, ubp_av=0x7fffe3227798, init=<optimized out>,
fini=<optimized out>, rtld_fini=<optimized out>,
stack_end=0x7fffe3227788) at libc-start.c:226
#42 0x0000000000402d95 in _start ()
Comment #2 by dmitry.olsh — 2013-11-18T08:25:33Z
Reduced by hand to this 20-liner:
int fun()
{
CodepointSet[] charsets = new CodepointSet[1];
uint pc;
switch(pc)
{
case 0:
auto set = charsets[0];
goto L_OutOfLoop;
L_OutOfLoop:
;
default:
}
return 0;
}
struct CodepointSet
{
~this(){}
}
enum x = fun();
Comment #3 by yebblies — 2013-11-18T10:01:00Z
Reduced - the destructor generates a try-finally which is not searched properly for the goto'd label.
static assert(()
{
try
{
goto label;
label: ;
}
finally
{
}
return 1;
}());
static assert(()
{
try
{
goto label;
label: ;
}
catch
{
}
return 1;
}());
https://github.com/D-Programming-Language/dmd/pull/2820