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)