shithub: mc

Download patch

ref: 0022c21553124df1dc02948b4fc27bd3906e4d37
parent: a62770976b151dd1fe3acc8dc4781aa62155c385
author: Ori Bernstein <[email protected]>
date: Tue Nov 12 08:49:22 EST 2013

Add range checking for integers.

    FIXME: right now, we generate values that should be unsigned
    as signed values. This is bad.

--- a/parse/infer.c
+++ b/parse/infer.c
@@ -24,6 +24,8 @@
     /* nodes that need post-inference checking/unification */
     Node **postcheck;
     size_t npostcheck;
+    Stab **postcheckscope;
+    size_t npostcheckscope;
     /* the type params bound at the current point */
     Htab **tybindings;
     size_t ntybindings;
@@ -99,8 +101,14 @@
     return s;
 }
 
-void typeerror(Inferstate *st, Type *a, Type *b, Node *ctx, char *msg)
+static void delayedcheck(Inferstate *st, Node *n, Stab *s)
 {
+    lappend(&st->postcheck, &st->npostcheck, n);
+    lappend(&st->postcheckscope, &st->npostcheckscope, s);
+}
+
+static void typeerror(Inferstate *st, Type *a, Type *b, Node *ctx, char *msg)
+{
     char *t1, *t2, *c;
 
     t1 = tystr(a);
@@ -878,7 +886,7 @@
             *isconst = 0;
     }
     settype(st, n, mktyvar(n->line));
-    lappend(&st->postcheck, &st->npostcheck, n);
+    delayedcheck(st, n, curstab());
 }
 
 static void inferarray(Inferstate *st, Node *n, int *isconst)
@@ -1107,7 +1115,7 @@
         /* special cases */
         case Omemb:     /* @a.Ident -> @b, verify type(@a.Ident)==@b later */
             settype(st, n, mktyvar(n->line));
-            lappend(&st->postcheck, &st->npostcheck, n);
+            delayedcheck(st, n, curstab());
             break;
         case Osize:     /* sizeof @a -> size */
             settype(st, n, mktylike(n->line, Tyuint));
@@ -1116,7 +1124,7 @@
             unifycall(st, n);
             break;
         case Ocast:     /* cast(@a, @b) -> @b */
-            lappend(&st->postcheck, &st->npostcheck, n);
+            delayedcheck(st, n, curstab());
             break;
         case Oret:      /* -> @a -> void */
             if (sawret)
@@ -1474,6 +1482,7 @@
 
     for (i = 0; i < st->npostcheck; i++) {
         n = st->postcheck[i];
+        pushstab(st->postcheckscope[i]);
         if (n->type == Nexpr && exprop(n) == Omemb)
             infercompn(st, n);
         else if (n->type == Nexpr && exprop(n) == Ocast)
@@ -1482,6 +1491,7 @@
             checkstruct(st, n);
         else
             die("Thing we shouldn't be checking in postcheck\n");
+        popstab();
     }
 }
 
@@ -1511,6 +1521,46 @@
     free(k);
 }
 
+static void checkrange(Inferstate *st, Node *n)
+{
+    Type *t;
+    int64_t sval;
+    uint64_t uval;
+    static const int64_t svranges[][2] = {
+        /* signed ints */
+        [Tyint8]  = {-128LL, 127LL},
+        [Tyint16] = {-32768LL, 32767LL},
+        [Tyint32] = {-2147483648LL, 2*2147483647LL}, /* FIXME: this has been doubled allow for uints... */
+        [Tyint]   = {-2147483648LL, 2*2147483647LL},
+        [Tyint64] = {-9223372036854775808ULL, 9223372036854775807LL},
+        [Tylong]  = {-9223372036854775808ULL, 9223372036854775807LL},
+    };
+
+    static const uint64_t uvranges[][2] = {
+        [Tybyte]   = {0, 255ULL},
+        [Tyuint8]  = {0, 255ULL},
+        [Tyuint16] = {0, 65535ULL},
+        [Tyuint32] = {0, 4294967295ULL},
+        [Tyuint64] = {0, 18446744073709551615ULL},
+        [Tyulong]  = {0, 18446744073709551615ULL},
+        [Tychar]   = {0, 4294967295ULL},
+    };
+
+    /* signed types */
+    t = type(st, n);
+    if (t->type >= Tyint8 && t->type <= Tylong) {
+        sval = n->lit.intval;
+        if (sval < svranges[t->type][0] || sval > svranges[t->type][1])
+            fatal(n->line, "Literal value %lld out of range for type \"%s\"", sval, tystr(t));
+    } else if ((t->type >= Tybyte && t->type <= Tyulong) || t->type == Tychar) {
+        uval = n->lit.intval;
+        if (uval < uvranges[t->type][0] || uval > uvranges[t->type][1])
+            fatal(n->line, "Literal value %llu out of range for type \"%s\"", tystr(t));
+    } else {
+        fatal(n->line, "Literal type %s has no range\n", tystr(t));
+    }
+}
+
 /* After type inference, replace all types
  * with the final computed type */
 static void typesub(Inferstate *st, Node *n)
@@ -1579,6 +1629,8 @@
             switch (n->lit.littype) {
                 case Lfunc:
                     typesub(st, n->lit.fnval); break;
+                case Lint:
+                    checkrange(st, n);
                 default:        break;
             }
             break;