load: Check for integer and real overlfows and underflows
authorPetri Lehtinen <petri@digip.org>
Sun, 13 Sep 2009 10:15:34 +0000 (13:15 +0300)
committerPetri Lehtinen <petri@digip.org>
Sun, 13 Sep 2009 10:18:01 +0000 (13:18 +0300)
src/load.c
test/testdata/invalid
test/testdata/invalid-strip

index d1366f8..8d5a392 100644 (file)
@@ -8,6 +8,7 @@
 #define _GNU_SOURCE
 #include <ctype.h>
 #include <errno.h>
+#include <limits.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
@@ -398,10 +399,11 @@ out:
     free(lex->value.string);
 }
 
-static void lex_scan_number(lex_t *lex, char c, json_error_t *error)
+static int lex_scan_number(lex_t *lex, char c, json_error_t *error)
 {
     const char *saved_text;
     char *end;
+    double value;
 
     lex->token = TOKEN_INVALID;
 
@@ -422,14 +424,26 @@ static void lex_scan_number(lex_t *lex, char c, json_error_t *error)
     }
 
     if(c != '.' && c != 'E' && c != 'e') {
+        long value;
+
         lex_unget_unsave(lex, c);
-        lex->token = TOKEN_INTEGER;
 
         saved_text = strbuffer_value(&lex->saved_text);
-        lex->value.integer = strtol(saved_text, &end, 10);
+        value = strtol(saved_text, &end, 10);
         assert(end == saved_text + lex->saved_text.length);
 
-        return;
+        if((value == LONG_MAX && errno == ERANGE) || value > INT_MAX) {
+            error_set(error, lex, "too big integer");
+            goto out;
+        }
+        else if((value == LONG_MIN && errno == ERANGE) || value < INT_MIN) {
+            error_set(error, lex, "too big negative integer");
+            goto out;
+        }
+
+        lex->token = TOKEN_INTEGER;
+        lex->value.integer = (int)value;
+        return 0;
     }
 
     if(c == '.') {
@@ -459,14 +473,29 @@ static void lex_scan_number(lex_t *lex, char c, json_error_t *error)
     }
 
     lex_unget_unsave(lex, c);
-    lex->token = TOKEN_REAL;
 
     saved_text = strbuffer_value(&lex->saved_text);
-    lex->value.real = strtod(saved_text, &end);
+    value = strtod(saved_text, &end);
     assert(end == saved_text + lex->saved_text.length);
 
+    if(value == 0 && errno == ERANGE) {
+        error_set(error, lex, "real number underflow");
+        goto out;
+    }
+
+    /* Cannot test for +/-HUGE_VAL because the HUGE_VAL constant is
+       only defined in C99 mode. So let's trust in sole errno. */
+    else if(errno == ERANGE) {
+        error_set(error, lex, "real number overflow");
+        goto out;
+    }
+
+    lex->token = TOKEN_REAL;
+    lex->value.real = value;
+    return 0;
+
 out:
-    return;
+    return -1;
 }
 
 static int lex_scan(lex_t *lex, json_error_t *error)
@@ -505,8 +534,10 @@ static int lex_scan(lex_t *lex, json_error_t *error)
     else if(c == '"')
         lex_scan_string(lex, error);
 
-    else if(isdigit(c) || c == '-')
-        lex_scan_number(lex, c, error);
+    else if(isdigit(c) || c == '-') {
+        if(lex_scan_number(lex, c, error))
+            goto out;
+    }
 
     else if(isupper(c) || islower(c)) {
         /* eat up the whole identifier for clearer error messages */
index 2887692..1a70422 100644 (file)
@@ -127,6 +127,21 @@ invalid token near '1e'
 ====
 1
 invalid token near '1e'
+==== real-positive-overflow ====
+[123123e100000]
+====
+1
+real number overflow near '123123e100000'
+==== real-negative-overflow ====
+[-123123e100000]
+====
+1
+real number overflow near '-123123e100000'
+==== real-underflow ====
+[123e-10000000]
+====
+1
+real number underflow near '123e-10000000'
 ==== integer-starting-with-zero ====
 [012]
 ====
@@ -137,6 +152,16 @@ invalid token near '0'
 ====
 1
 invalid token near '-0'
+==== too-big-positive-integer ====
+[123123123123123]
+====
+1
+too big integer near '123123123123123'
+==== too-big-negative-integer ====
+[-123123123123123]
+====
+1
+too big negative integer near '-123123123123123'
 ==== invalid-identifier ====
 [troo
 ====
index 18e40ae..8b4a574 100644 (file)
@@ -127,6 +127,21 @@ invalid token near '1e'
 ====
 1
 invalid token near '1e'
+==== real-positive-overflow ====
+[123123e100000]
+====
+1
+real number overflow near '123123e100000'
+==== real-negative-overflow ====
+[-123123e100000]
+====
+1
+real number overflow near '-123123e100000'
+==== real-underflow ====
+[123e-10000000]
+====
+1
+real number underflow near '123e-10000000'
 ==== integer-starting-with-zero ====
 [012]
 ====
@@ -137,6 +152,16 @@ invalid token near '0'
 ====
 1
 invalid token near '-0'
+==== too-big-positive-integer ====
+[123123123123123]
+====
+1
+too big integer near '123123123123123'
+==== too-big-negative-integer ====
+[-123123123123123]
+====
+1
+too big negative integer near '-123123123123123'
 ==== invalid-identifier ====
 [troo
 ====