summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMark Pulford <mark@kyne.com.au>2011-04-25 19:15:56 +0930
committerMark Pulford <mark@kyne.com.au>2011-04-25 19:15:56 +0930
commit2a12b3fa4b8cdef53288aa2667df0dad2d7f2fc2 (patch)
tree553107e5ad0d580326cea4801b73846e8c0abfe9
parent06b42604a44f49e94bad277f87c9024b40a7e491 (diff)
downloadlua-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.c34
-rw-r--r--strbuf.c4
-rw-r--r--strbuf.h14
3 files changed, 34 insertions, 18 deletions
diff --git a/lua_json.c b/lua_json.c
index 1753e49..1d334ea 100644
--- a/lua_json.c
+++ b/lua_json.c
@@ -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);
diff --git a/strbuf.c b/strbuf.c
index 227cb47..44145dd 100644
--- a/strbuf.c
+++ b/strbuf.c
@@ -152,9 +152,7 @@ void strbuf_resize(strbuf_t *s, int len)
152 152
153void strbuf_append_mem(strbuf_t *s, const char *c, int len) 153void 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}
diff --git a/strbuf.h b/strbuf.h
index 914274c..d6e2d90 100644
--- a/strbuf.h
+++ b/strbuf.h
@@ -38,6 +38,7 @@ extern void strbuf_resize(strbuf_t *s, int len);
38static int strbuf_empty_length(strbuf_t *s); 38static int strbuf_empty_length(strbuf_t *s);
39static int strbuf_length(strbuf_t *s); 39static int strbuf_length(strbuf_t *s);
40static char *strbuf_string(strbuf_t *s, int *len); 40static char *strbuf_string(strbuf_t *s, int *len);
41static void strbuf_ensure_empty_length(strbuf_t *s, int len);
41 42
42/* Update */ 43/* Update */
43extern void strbuf_append_fmt(strbuf_t *s, const char *format, ...); 44extern 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
57static 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
56static inline int strbuf_length(strbuf_t *s) 63static 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
61static inline void strbuf_append_char(strbuf_t *s, const char c) 68static 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
74static 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