aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--jsmn/jsmn.c62
-rw-r--r--jsmn/jsmn.h1
-rw-r--r--regtest.tcl11
-rw-r--r--tests/json.test10
4 files changed, 52 insertions, 32 deletions
diff --git a/jsmn/jsmn.c b/jsmn/jsmn.c
index 2de5ec2..19d48e0 100644
--- a/jsmn/jsmn.c
+++ b/jsmn/jsmn.c
@@ -1,11 +1,17 @@
#include "jsmn.h"
+/* For json-decode we want strict mode so we don't get
+ * garbage for malformed json
+ */
+#define JSMN_STRICT
+
/**
* Allocates a fresh unused token from the token pool.
*/
static jsmntok_t *jsmn_alloc_token(jsmn_parser *parser,
jsmntok_t *tokens, size_t num_tokens) {
jsmntok_t *tok;
+ parser->count++;
if (parser->toknext >= num_tokens) {
return NULL;
}
@@ -61,11 +67,11 @@ static int jsmn_parse_primitive(jsmn_parser *parser, const char *js,
#endif
found:
+ token = jsmn_alloc_token(parser, tokens, num_tokens);
if (tokens == NULL) {
parser->pos--;
return 0;
}
- token = jsmn_alloc_token(parser, tokens, num_tokens);
if (token == NULL) {
parser->pos = start;
return JSMN_ERROR_NOMEM;
@@ -95,10 +101,10 @@ static int jsmn_parse_string(jsmn_parser *parser, const char *js,
/* Quote: end of string */
if (c == '\"') {
+ token = jsmn_alloc_token(parser, tokens, num_tokens);
if (tokens == NULL) {
return 0;
}
- token = jsmn_alloc_token(parser, tokens, num_tokens);
if (token == NULL) {
parser->pos = start;
return JSMN_ERROR_NOMEM;
@@ -153,7 +159,6 @@ int jsmn_parse(jsmn_parser *parser, const char *js, size_t len,
int r;
int i;
jsmntok_t *token;
- int count = parser->toknext;
for (; parser->pos < len && js[parser->pos] != '\0'; parser->pos++) {
char c;
@@ -162,11 +167,10 @@ int jsmn_parse(jsmn_parser *parser, const char *js, size_t len,
c = js[parser->pos];
switch (c) {
case '{': case '[':
- count++;
+ token = jsmn_alloc_token(parser, tokens, num_tokens);
if (tokens == NULL) {
break;
}
- token = jsmn_alloc_token(parser, tokens, num_tokens);
if (token == NULL)
return JSMN_ERROR_NOMEM;
if (parser->toksuper != -1) {
@@ -235,7 +239,6 @@ int jsmn_parse(jsmn_parser *parser, const char *js, size_t len,
case '\"':
r = jsmn_parse_string(parser, js, len, tokens, num_tokens);
if (r < 0) return r;
- count++;
if (parser->toksuper != -1 && tokens != NULL)
tokens[parser->toksuper].size++;
break;
@@ -262,35 +265,39 @@ int jsmn_parse(jsmn_parser *parser, const char *js, size_t len,
#endif
}
break;
+
+ default:
+ /* In non-strict mode every unquoted value is a primitive */
#ifdef JSMN_STRICT
- /* In strict mode primitives are: numbers and booleans */
- case '-': case '0': case '1' : case '2': case '3' : case '4':
- case '5': case '6': case '7' : case '8': case '9':
- case 't': case 'f': case 'n' :
- /* And they must not be keys of the object */
- if (tokens != NULL && parser->toksuper != -1) {
- jsmntok_t *t = &tokens[parser->toksuper];
- if (t->type == JSMN_OBJECT ||
- (t->type == JSMN_STRING && t->size != 0)) {
+ switch (c) {
+ /* In strict mode primitives are: numbers and booleans */
+ case '-': case '0': case '1' : case '2': case '3' : case '4':
+ case '5': case '6': case '7' : case '8': case '9':
+ case 't': case 'f': case 'n' :
+#ifndef JSMN_FULLY_STRICT
+ /* Allow Inf and NaN in any mode other than fully strict */
+ case 'I': case 'N':
+#endif
+ /* And they must not be keys of the object */
+ if (tokens != NULL && parser->toksuper != -1) {
+ jsmntok_t *t = &tokens[parser->toksuper];
+ if (t->type == JSMN_OBJECT ||
+ (t->type == JSMN_STRING && t->size != 0)) {
+ return JSMN_ERROR_INVAL;
+ }
+ }
+ break;
+
+ default:
+ /* Unexpected char in strict mode */
return JSMN_ERROR_INVAL;
- }
}
-#else
- /* In non-strict mode every unquoted value is a primitive */
- default:
#endif
r = jsmn_parse_primitive(parser, js, len, tokens, num_tokens);
if (r < 0) return r;
- count++;
if (parser->toksuper != -1 && tokens != NULL)
tokens[parser->toksuper].size++;
break;
-
-#ifdef JSMN_STRICT
- /* Unexpected char in strict mode */
- default:
- return JSMN_ERROR_INVAL;
-#endif
}
}
@@ -303,7 +310,7 @@ int jsmn_parse(jsmn_parser *parser, const char *js, size_t len,
}
}
- return count;
+ return parser->count;
}
/**
@@ -314,5 +321,6 @@ void jsmn_init(jsmn_parser *parser) {
parser->pos = 0;
parser->toknext = 0;
parser->toksuper = -1;
+ parser->count = 0;
}
diff --git a/jsmn/jsmn.h b/jsmn/jsmn.h
index 01ca99c..9c20657 100644
--- a/jsmn/jsmn.h
+++ b/jsmn/jsmn.h
@@ -54,6 +54,7 @@ typedef struct {
typedef struct {
unsigned int pos; /* offset in the JSON string */
unsigned int toknext; /* next token to allocate */
+ unsigned int count; /* number of tokens parsed */
int toksuper; /* superior token node, e.g parent object or array */
} jsmn_parser;
diff --git a/regtest.tcl b/regtest.tcl
index a9ee5eb..5e66aa3 100644
--- a/regtest.tcl
+++ b/regtest.tcl
@@ -388,6 +388,17 @@ puts "TEST 54 PASSED"
apply {{} {info frame 0}}
puts "TEST 55 PASSED"
+# json decode should not core dump on invalid input
+set json {
+{
+ "fossil":"9c65b5432e4aeecf3556e5550c338ce93fd861cc",
+ "timestamp":1435827337,
+ "command":"timeline/checkin", /* this is line 3 */
+ "procTimeUs":3333,
+}}
+catch {json::decode $json}
+puts "TEST 56 PASSED"
+
# TAKE THE FOLLOWING puts AS LAST LINE
puts "--- ALL TESTS PASSED ---"
diff --git a/tests/json.test b/tests/json.test
index ed73401..78a19fa 100644
--- a/tests/json.test
+++ b/tests/json.test
@@ -60,6 +60,7 @@ test json-decode-012 {default null value} {
} {null}
test json-decode-1.1 {Number forms} {
+ # Note that this is not strictly correct JSON, but is usable in practice
json::decode {[ 1, 2, 3.0, 4, Infinity, NaN, -Infinity, -0.0, 1e5, -1e-5 ]}
} {1 2 3.0 4 Inf NaN -Inf -0.0 1e5 -1e-5}
@@ -80,15 +81,15 @@ test json-2.4 {schema tests} {
} {obj a num b num}
test json-2.5 {schema tests} {
- lindex [json::decode -schema {[1, 2, {a:"b", c:false}, "hello"]}] 1
+ lindex [json::decode -schema {[1, 2, {"a":"b", "c":false}, "hello"]}] 1
} {mixed num num {obj a str c bool} str}
test json-2.6 {schema tests} {
- lindex [json::decode -schema {[1, 2, {a:["b", 1, true, Infinity]}]}] 1
+ lindex [json::decode -schema {[1, 2, {"a":["b", 1, true, Infinity]}]}] 1
} {mixed num num {obj a {mixed str num bool num}}}
test json-2.7 {schema tests} {
- lindex [json::decode -schema {[1, 2, {a:["b", 1, true, ["d", "e", "f"]]}]}] 1
+ lindex [json::decode -schema {[1, 2, {"a":["b", 1, true, ["d", "e", "f"]]}]}] 1
} {mixed num num {obj a {mixed str num bool {list str}}}}
test json-2.8 {schema tests} {
@@ -96,10 +97,9 @@ test json-2.8 {schema tests} {
} {mixed num num bool bool}
test json-2.9 {schema tests} {
- lindex [json::decode -schema {[{a:1},{b:2}]}] 1
+ lindex [json::decode -schema {[{"a":1},{"b":2}]}] 1
} {mixed {obj a num} {obj b num}}
-
test json-3.1 {-index array} {
json::decode -index \
{[null, 1, 2, true, false, "hello"]}