diff options
author | Mark Pulford <mark@kyne.com.au> | 2011-04-25 19:15:56 +0930 |
---|---|---|
committer | Mark Pulford <mark@kyne.com.au> | 2011-04-25 19:15:56 +0930 |
commit | 2a12b3fa4b8cdef53288aa2667df0dad2d7f2fc2 (patch) | |
tree | 553107e5ad0d580326cea4801b73846e8c0abfe9 | |
parent | 06b42604a44f49e94bad277f87c9024b40a7e491 (diff) | |
download | lua-cjson-2a12b3fa4b8cdef53288aa2667df0dad2d7f2fc2.tar.gz lua-cjson-2a12b3fa4b8cdef53288aa2667df0dad2d7f2fc2.tar.bz2 lua-cjson-2a12b3fa4b8cdef53288aa2667df0dad2d7f2fc2.zip |
Grow decode stack, prealloc strings during encode
- Check stack usage during decode to prevent crashing in excessively
nested data structures.
- Preallocate the required memory for json_append_string().
-rw-r--r-- | lua_json.c | 34 | ||||
-rw-r--r-- | strbuf.c | 4 | ||||
-rw-r--r-- | strbuf.h | 14 |
3 files changed, 34 insertions, 18 deletions
@@ -7,24 +7,18 @@ | |||
7 | * json.null. | 7 | * json.null. |
8 | * - Parsing comments is not support. According to json.org, this isn't | 8 | * - Parsing comments is not support. According to json.org, this isn't |
9 | * part of the spec. | 9 | * part of the spec. |
10 | * | ||
11 | * Note: lua_json_decode() probably spends significant time rehashing | ||
12 | * tables since it is difficult to know their size ahead of time. | ||
13 | * Earlier JSON libaries didn't have this problem but the intermediate | ||
14 | * storage (and their implementations) were much slower anyway.. | ||
10 | */ | 15 | */ |
11 | 16 | ||
12 | /* FIXME: | 17 | /* FIXME: |
13 | * - Ensure JSON data is UTF-8. Fail otherwise. | 18 | * - Ensure JSON data is UTF-8. Fail otherwise. |
14 | * - Alternatively, dynamically support Unicode in JSON string. Return current locale. | 19 | * - Alternatively, dynamically support Unicode in JSON string. Return current locale. |
15 | * - Use lua_checkstack() to ensure there is enough stack space left to | 20 | * - Consider implementing other Unicode standards. |
16 | * fulfill an operation. What happens if we don't, is that acceptible too? | ||
17 | * Does lua_checkstack grow the stack, or merely check if it is possible? | ||
18 | */ | ||
19 | |||
20 | /* FIXME: | ||
21 | * - Option to encode non-printable characters? Only \" \\ are required | 21 | * - Option to encode non-printable characters? Only \" \\ are required |
22 | * - Unicode? | ||
23 | */ | ||
24 | |||
25 | /* FIXME: | ||
26 | * - Review memory allocation handling and error returns. | ||
27 | * Ensure all memory is free. Including after exceptions. | ||
28 | */ | 22 | */ |
29 | 23 | ||
30 | #include <assert.h> | 24 | #include <assert.h> |
@@ -94,13 +88,19 @@ static void json_append_string(lua_State *l, strbuf_t *json, int lindex) | |||
94 | 88 | ||
95 | str = lua_tolstring(l, lindex, &len); | 89 | str = lua_tolstring(l, lindex, &len); |
96 | 90 | ||
91 | /* Worst case is len * 6 (all unicode escapes). | ||
92 | * This buffer is reused constantly for small strings | ||
93 | * If there are any excess pages, they won't be hit anyway. | ||
94 | * This gains ~5% speedup. */ | ||
95 | strbuf_ensure_empty_length(json, len * 6); | ||
96 | |||
97 | strbuf_append_char(json, '\"'); | 97 | strbuf_append_char(json, '\"'); |
98 | for (i = 0; i < len; i++) { | 98 | for (i = 0; i < len; i++) { |
99 | p = json_escape_char(str[i]); | 99 | p = json_escape_char(str[i]); |
100 | if (p) | 100 | if (p) |
101 | strbuf_append_string(json, p); | 101 | strbuf_append_string(json, p); |
102 | else | 102 | else |
103 | strbuf_append_char(json, str[i]); | 103 | strbuf_append_char_unsafe(json, str[i]); |
104 | } | 104 | } |
105 | strbuf_append_char(json, '\"'); | 105 | strbuf_append_char(json, '\"'); |
106 | } | 106 | } |
@@ -536,6 +536,10 @@ static void json_parse_object_context(lua_State *l, json_parse_t *json) | |||
536 | { | 536 | { |
537 | json_token_t token; | 537 | json_token_t token; |
538 | 538 | ||
539 | /* 3 slots required: | ||
540 | * .., table, key, value */ | ||
541 | luaL_checkstack(l, 3, "too many nested data structures"); | ||
542 | |||
539 | lua_newtable(l); | 543 | lua_newtable(l); |
540 | 544 | ||
541 | json_next_token(json, &token); | 545 | json_next_token(json, &token); |
@@ -576,6 +580,10 @@ static void json_parse_array_context(lua_State *l, json_parse_t *json) | |||
576 | json_token_t token; | 580 | json_token_t token; |
577 | int i; | 581 | int i; |
578 | 582 | ||
583 | /* 2 slots required: | ||
584 | * .., table, value */ | ||
585 | luaL_checkstack(l, 2, "too many nested data structures"); | ||
586 | |||
579 | lua_newtable(l); | 587 | lua_newtable(l); |
580 | 588 | ||
581 | json_next_token(json, &token); | 589 | json_next_token(json, &token); |
@@ -152,9 +152,7 @@ void strbuf_resize(strbuf_t *s, int len) | |||
152 | 152 | ||
153 | void strbuf_append_mem(strbuf_t *s, const char *c, int len) | 153 | void strbuf_append_mem(strbuf_t *s, const char *c, int len) |
154 | { | 154 | { |
155 | if (len > strbuf_empty_length(s)) | 155 | strbuf_ensure_empty_length(s, len); |
156 | strbuf_resize(s, s->length + len); | ||
157 | |||
158 | memcpy(s->buf + s->length, c, len); | 156 | memcpy(s->buf + s->length, c, len); |
159 | s->length += len; | 157 | s->length += len; |
160 | } | 158 | } |
@@ -38,6 +38,7 @@ extern void strbuf_resize(strbuf_t *s, int len); | |||
38 | static int strbuf_empty_length(strbuf_t *s); | 38 | static int strbuf_empty_length(strbuf_t *s); |
39 | static int strbuf_length(strbuf_t *s); | 39 | static int strbuf_length(strbuf_t *s); |
40 | static char *strbuf_string(strbuf_t *s, int *len); | 40 | static char *strbuf_string(strbuf_t *s, int *len); |
41 | static void strbuf_ensure_empty_length(strbuf_t *s, int len); | ||
41 | 42 | ||
42 | /* Update */ | 43 | /* Update */ |
43 | extern void strbuf_append_fmt(strbuf_t *s, const char *format, ...); | 44 | extern void strbuf_append_fmt(strbuf_t *s, const char *format, ...); |
@@ -53,6 +54,12 @@ static inline int strbuf_empty_length(strbuf_t *s) | |||
53 | return s->size - s->length - 1; | 54 | return s->size - s->length - 1; |
54 | } | 55 | } |
55 | 56 | ||
57 | static inline void strbuf_ensure_empty_length(strbuf_t *s, int len) | ||
58 | { | ||
59 | if (len > strbuf_empty_length(s)) | ||
60 | strbuf_resize(s, s->length + len); | ||
61 | } | ||
62 | |||
56 | static inline int strbuf_length(strbuf_t *s) | 63 | static inline int strbuf_length(strbuf_t *s) |
57 | { | 64 | { |
58 | return s->length; | 65 | return s->length; |
@@ -60,9 +67,12 @@ static inline int strbuf_length(strbuf_t *s) | |||
60 | 67 | ||
61 | static inline void strbuf_append_char(strbuf_t *s, const char c) | 68 | static inline void strbuf_append_char(strbuf_t *s, const char c) |
62 | { | 69 | { |
63 | if (strbuf_empty_length(s) < 1) | 70 | strbuf_ensure_empty_length(s, 1); |
64 | strbuf_resize(s, s->length + 1); | 71 | s->buf[s->length++] = c; |
72 | } | ||
65 | 73 | ||
74 | static inline void strbuf_append_char_unsafe(strbuf_t *s, const char c) | ||
75 | { | ||
66 | s->buf[s->length++] = c; | 76 | s->buf[s->length++] = c; |
67 | } | 77 | } |
68 | 78 | ||