D issues are now tracked on GitHub. This Bugzilla instance remains as a read-only archive.
Issue 3139 - compiler dies "Error: out of memory" with case range
Summary: compiler dies "Error: out of memory" with case range
Status: RESOLVED FIXED
Alias: None
Product: D
Classification: Unclassified
Component: dmd (show other issues)
Version: D2
Hardware: x86 Linux
: P2 normal
Assignee: No Owner
URL:
Keywords: ice-on-valid-code, patch, wrong-code
Depends on:
Blocks:
 
Reported: 2009-07-06 00:21 UTC by MIURA Masahiro
Modified: 2015-06-09 01:28 UTC (History)
2 users (show)

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this issue.
Description MIURA Masahiro 2009-07-06 00:21:14 UTC
% 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 Don 2010-05-12 12:38:56 UTC
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 Walter Bright 2010-05-16 11:11:02 UTC
changelog 491