diff --git a/src/xjson.c b/src/xjson.c index b663342..5d02ba7 100644 --- a/src/xjson.c +++ b/src/xjson.c @@ -7,6 +7,9 @@ #include #include "xjson.h" +#define XJ_MAX_DEPTH 128 +#define XJ_MAX_EXPNT 10 + typedef struct chunk_t chunk_t; /* Symbol: @@ -568,7 +571,7 @@ char *xj_strdup(const char *str, int len, xj_alloc *alloc, xj_error *error) typedef struct { const char *str; - int i, len; + int i, len, depth; xj_alloc *alloc; xj_error *error; } context_t; @@ -916,15 +919,17 @@ static void *parse_string(context_t *ctx, _Bool raw) return NULL; } - char c = ctx->str[ctx->i]; + uint32_t rune; + int rune_byte_count = xutf8_sequence_to_utf32_codepoint(ctx->str + ctx->i, ctx->len - ctx->i, &rune); - ctx->i += 1; // Skip the character after the '\'. - - if(c == 'u') + if(rune == 'u') { - int start = ctx->i-2; + int start = ctx->i-1; // Points to the '\'. assert(start >= 0); + assert(rune_byte_count == 1); + ctx->i += 1; // Skip the 'u'. + uint16_t first_half; if(!parse_XXXX_after_u(ctx, &first_half)) { @@ -1024,22 +1029,29 @@ static void *parse_string(context_t *ctx, _Bool raw) } else { - switch(c) + const char *s; int l; + switch(rune) { - case 'n': c = '\n'; break; - case 't': c = '\t'; break; - case 'b': c = '\b'; break; - case 'f': c = '\f'; break; - case 'r': c = '\r'; break; + case 'n': s = "\n"; l = 1; break; + case 't': s = "\t"; l = 1; break; + case 'b': s = "\b"; l = 1; break; + case 'f': s = "\f"; l = 1; break; + case 'r': s = "\r"; l = 1; break; + default: + s = ctx->str + ctx->i; + l = rune_byte_count; + break; } - if(!spc_append(&spc, &c, 1)) + ctx->i += rune_byte_count; + + if(!spc_append(&spc, s, l)) { xj_report(ctx->error, "Out of memory"); spc_free(&spc); return NULL; } - } + } } else { @@ -1182,7 +1194,7 @@ static xj_value *parse_number(context_t *ctx) ctx->i += 1; } - if(exponent > 6) + if(exponent > XJ_MAX_EXPNT) { xj_preport(ctx->error, ctx->str, exponent_start, "Exponent is too big"); return NULL; @@ -1416,6 +1428,13 @@ static xj_value *parse_value(context_t *ctx) xj_report(ctx->error, "String ended where a value was expected"); return NULL; } + + ctx->depth += 1; + if(ctx->depth == XJ_MAX_DEPTH) + { + xj_preport(ctx->error, ctx->str, ctx->i, "Maximum depth reached"); + return NULL; + } assert(!isspace(ctx->str[ctx->i])); @@ -1547,7 +1566,7 @@ xj_value *xj_decode(const char *str, int len, } context_t ctx = { - .str = str, .i = i, .len = len, + .str = str, .i = i, .len = len, .depth = 0, .alloc = alloc, .error = error }; return parse_value(&ctx); } diff --git a/src/xjson.h b/src/xjson.h index c8b55ae..85ae1e6 100644 --- a/src/xjson.h +++ b/src/xjson.h @@ -45,10 +45,10 @@ typedef struct xj_alloc xj_alloc; xj_alloc *xj_alloc_using(void *mem, int size, int ext, void (*free)(void*)); xj_alloc *xj_alloc_new(int size, int ext); void xj_alloc_del(xj_alloc *alloc); -void *xj_bpalloc(xj_alloc *alloc, int size); -void xj_preport(xj_error *error, const char *src, int off, const char *fmt, ...); -#define xj_report(error, fmt, ...) xj_preport(error, NULL, -1, fmt, ## __VA_ARGS__) +void *xj_bpalloc(xj_alloc *alloc, int size); +void xj_preport(xj_error *error, const char *src, int off, const char *fmt, ...); +#define xj_report(error, fmt, ...) xj_preport(error, NULL, -1, fmt, ## __VA_ARGS__) xj_value *xj_value_null(xj_alloc *alloc, xj_error *error); xj_value *xj_value_bool(xj_bool val, xj_alloc *alloc, xj_error *error);