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
Comment #4 by yebblies — 2013-11-18T10:03:57Z
And with: static assert(() { with(Object.init) { goto label; label: ; } return 1; }());
Comment #5 by github-bugzilla — 2013-11-28T23:40:15Z
Commits pushed to master at https://github.com/D-Programming-Language/dmd https://github.com/D-Programming-Language/dmd/commit/0afa3dead96f207157608f1bf72651967e7915a7 fix Issue 11540 - [ICE] CTFE segfault with try-catch-finally and goto https://github.com/D-Programming-Language/dmd/commit/9c4a1cf7e711a6cd8b6490258144329622f8441d Merge pull request #2822 from 9rnsr/fix11540 Issue 11540 - [ICE] CTFE segfault with try-catch-finally and goto