Bug 3139 – compiler dies "Error: out of memory" with case range

Status
RESOLVED
Resolution
FIXED
Severity
normal
Priority
P2
Component
dmd
Product
D
Version
D2
Platform
x86
OS
Linux
Creation time
2009-07-06T00:21:00Z
Last change time
2015-06-09T01:28:06Z
Keywords
ice-on-valid-code, patch, wrong-code
Assigned to
nobody
Creator
echochamber

Comments

Comment #0 by echochamber — 2009-07-06T00:21:14Z
% cat -n foo.d 1 import std.conv; 2 import std.stdio; 3 4 void main(string[] args) 5 { 6 int i = to!int(args[0]); 7 8 switch (i) { 9 case -9: .. case -1: // line 9 10 writefln("negative"); 11 break; 12 case 0: 13 writefln("zero"); 14 break; 15 default: 16 writefln("positive"); 17 break; 18 } 19 } % dmd foo.d Error: out of memory %
Comment #1 by clugdbug — 2010-05-12T12:38:56Z
It goes into an infinite loop because the loop termination condition in CaseRangeStatement::semantic() uses <=. This fails whenever the last case is -1 or ulong.max. x <= -1u is true for all uint x. Worse, if the range goes from negative to positive, wrong code is generated. In my patch, I've also added an error message to detect wrongly-ordered ranges. eg, case 3:..case 2: currently produces "more than 256 cases in case range" which is a bit silly. This also fixes a related accepts-invalid test case. -- TEST CASES FOR TEST SUITE -- void hang3139(int x) { switch(x) { case -9: .. case -1: default: } } int wrongcode3139(int x) { switch(x) { case -9: .. case 2: return 3; default: return 4; } } static assert(wrongcode3139(-5)==3); // bug 3139, accepts-invalid in DMD2.045. static assert(!is(typeof( (long x) { switch(x) { case long.max: .. case -long.max: default:} return 4; }(3) ))); --- PATCH Index: statement.c =================================================================== --- statement.c (revision 484) +++ statement.c (working copy) @@ -3033,6 +3033,14 @@ last = last->optimize(WANTvalue | WANTinterpret); dinteger_t lval = last->toInteger(); + if ( (first->type->isunsigned() && fval > lval) || + (!first->type->isunsigned() && (sinteger_t)fval > (sinteger_t)lval)) + { + error ("first case %s must be less than last case %s", + first->toChars(), last->toChars()); + lval = fval; + } + if (lval - fval > 256) { error("more than 256 cases in case range"); lval = fval + 256; @@ -3049,7 +3057,7 @@ */ Statements *statements = new Statements(); - for (dinteger_t i = fval; i <= lval; i++) + for (dinteger_t i = fval; i != lval + 1; i++) { Statement *s = statement; if (i != lval)
Comment #2 by bugzilla — 2010-05-16T11:11:02Z
changelog 491