diff options
| -rw-r--r-- | lua_cjson.c | 98 | ||||
| -rw-r--r-- | manual.txt | 26 |
2 files changed, 89 insertions, 35 deletions
diff --git a/lua_cjson.c b/lua_cjson.c index 344cb43..bdfa7d4 100644 --- a/lua_cjson.c +++ b/lua_cjson.c | |||
| @@ -39,6 +39,7 @@ | |||
| 39 | #include <assert.h> | 39 | #include <assert.h> |
| 40 | #include <string.h> | 40 | #include <string.h> |
| 41 | #include <math.h> | 41 | #include <math.h> |
| 42 | #include <limits.h> | ||
| 42 | #include <lua.h> | 43 | #include <lua.h> |
| 43 | #include <lauxlib.h> | 44 | #include <lauxlib.h> |
| 44 | 45 | ||
| @@ -61,7 +62,8 @@ | |||
| 61 | #define DEFAULT_SPARSE_CONVERT 0 | 62 | #define DEFAULT_SPARSE_CONVERT 0 |
| 62 | #define DEFAULT_SPARSE_RATIO 2 | 63 | #define DEFAULT_SPARSE_RATIO 2 |
| 63 | #define DEFAULT_SPARSE_SAFE 10 | 64 | #define DEFAULT_SPARSE_SAFE 10 |
| 64 | #define DEFAULT_MAX_DEPTH 20 | 65 | #define DEFAULT_ENCODE_MAX_DEPTH 20 |
| 66 | #define DEFAULT_DECODE_MAX_DEPTH 20 | ||
| 65 | #define DEFAULT_ENCODE_REFUSE_BADNUM 1 | 67 | #define DEFAULT_ENCODE_REFUSE_BADNUM 1 |
| 66 | #define DEFAULT_DECODE_REFUSE_BADNUM 0 | 68 | #define DEFAULT_DECODE_REFUSE_BADNUM 0 |
| 67 | #define DEFAULT_ENCODE_KEEP_BUFFER 1 | 69 | #define DEFAULT_ENCODE_KEEP_BUFFER 1 |
| @@ -120,9 +122,11 @@ typedef struct { | |||
| 120 | int encode_sparse_safe; | 122 | int encode_sparse_safe; |
| 121 | int encode_max_depth; | 123 | int encode_max_depth; |
| 122 | int encode_refuse_badnum; | 124 | int encode_refuse_badnum; |
| 123 | int decode_refuse_badnum; | ||
| 124 | int encode_keep_buffer; | ||
| 125 | int encode_number_precision; | 125 | int encode_number_precision; |
| 126 | int encode_keep_buffer; | ||
| 127 | |||
| 128 | int decode_refuse_badnum; | ||
| 129 | int decode_max_depth; | ||
| 126 | } json_config_t; | 130 | } json_config_t; |
| 127 | 131 | ||
| 128 | typedef struct { | 132 | typedef struct { |
| @@ -130,6 +134,7 @@ typedef struct { | |||
| 130 | const char *ptr; | 134 | const char *ptr; |
| 131 | strbuf_t *tmp; /* Temporary storage for strings */ | 135 | strbuf_t *tmp; /* Temporary storage for strings */ |
| 132 | json_config_t *cfg; | 136 | json_config_t *cfg; |
| 137 | int current_depth; | ||
| 133 | } json_parse_t; | 138 | } json_parse_t; |
| 134 | 139 | ||
| 135 | typedef struct { | 140 | typedef struct { |
| @@ -234,46 +239,50 @@ static int json_cfg_encode_sparse_array(lua_State *l) | |||
| 234 | return 3; | 239 | return 3; |
| 235 | } | 240 | } |
| 236 | 241 | ||
| 237 | /* Configures the maximum number of nested arrays/objects allowed when | 242 | /* Process integer options for configuration functions */ |
| 238 | * encoding */ | 243 | static int json_integer_option(lua_State *l, int *setting, int min, int max) |
| 239 | static int json_cfg_encode_max_depth(lua_State *l) | ||
| 240 | { | 244 | { |
| 241 | json_config_t *cfg; | 245 | char errmsg[64]; |
| 242 | int depth; | 246 | int value; |
| 243 | 247 | ||
| 244 | json_verify_arg_count(l, 1); | 248 | json_verify_arg_count(l, 1); |
| 245 | cfg = json_fetch_config(l); | ||
| 246 | 249 | ||
| 247 | if (lua_gettop(l)) { | 250 | if (lua_gettop(l)) { |
| 248 | depth = luaL_checkinteger(l, 1); | 251 | value = luaL_checkinteger(l, 1); |
| 249 | luaL_argcheck(l, depth > 0, 1, "expected positive integer"); | 252 | snprintf(errmsg, sizeof(errmsg), "expected integer between %d and %d", min, max); |
| 250 | cfg->encode_max_depth = depth; | 253 | luaL_argcheck(l, min <= value && value <= max, 1, errmsg); |
| 254 | *setting = value; | ||
| 251 | } | 255 | } |
| 252 | 256 | ||
| 253 | lua_pushinteger(l, cfg->encode_max_depth); | 257 | lua_pushinteger(l, *setting); |
| 254 | 258 | ||
| 255 | return 1; | 259 | return 1; |
| 256 | } | 260 | } |
| 257 | 261 | ||
| 258 | /* Configures number precision when converting doubles to text */ | 262 | /* Configures the maximum number of nested arrays/objects allowed when |
| 259 | static int json_cfg_encode_number_precision(lua_State *l) | 263 | * encoding */ |
| 264 | static int json_cfg_encode_max_depth(lua_State *l) | ||
| 260 | { | 265 | { |
| 261 | json_config_t *cfg; | 266 | json_config_t *cfg = json_fetch_config(l); |
| 262 | int precision; | ||
| 263 | 267 | ||
| 264 | json_verify_arg_count(l, 1); | 268 | return json_integer_option(l, &cfg->encode_max_depth, 1, INT_MAX); |
| 265 | cfg = json_fetch_config(l); | 269 | } |
| 266 | 270 | ||
| 267 | if (lua_gettop(l)) { | 271 | /* Configures the maximum number of nested arrays/objects allowed when |
| 268 | precision = luaL_checkinteger(l, 1); | 272 | * encoding */ |
| 269 | luaL_argcheck(l, 1 <= precision && precision <= 14, 1, | 273 | static int json_cfg_decode_max_depth(lua_State *l) |
| 270 | "expected integer between 1 and 14"); | 274 | { |
| 271 | cfg->encode_number_precision = precision; | 275 | json_config_t *cfg = json_fetch_config(l); |
| 272 | } | ||
| 273 | 276 | ||
| 274 | lua_pushinteger(l, cfg->encode_number_precision); | 277 | return json_integer_option(l, &cfg->decode_max_depth, 1, INT_MAX); |
| 278 | } | ||
| 275 | 279 | ||
| 276 | return 1; | 280 | /* Configures number precision when converting doubles to text */ |
| 281 | static int json_cfg_encode_number_precision(lua_State *l) | ||
| 282 | { | ||
| 283 | json_config_t *cfg = json_fetch_config(l); | ||
| 284 | |||
| 285 | return json_integer_option(l, &cfg->encode_number_precision, 1, 14); | ||
| 277 | } | 286 | } |
| 278 | 287 | ||
| 279 | /* Configures JSON encoding buffer persistence */ | 288 | /* Configures JSON encoding buffer persistence */ |
| @@ -387,7 +396,8 @@ static void json_create_config(lua_State *l) | |||
| 387 | cfg->encode_sparse_convert = DEFAULT_SPARSE_CONVERT; | 396 | cfg->encode_sparse_convert = DEFAULT_SPARSE_CONVERT; |
| 388 | cfg->encode_sparse_ratio = DEFAULT_SPARSE_RATIO; | 397 | cfg->encode_sparse_ratio = DEFAULT_SPARSE_RATIO; |
| 389 | cfg->encode_sparse_safe = DEFAULT_SPARSE_SAFE; | 398 | cfg->encode_sparse_safe = DEFAULT_SPARSE_SAFE; |
| 390 | cfg->encode_max_depth = DEFAULT_MAX_DEPTH; | 399 | cfg->encode_max_depth = DEFAULT_ENCODE_MAX_DEPTH; |
| 400 | cfg->decode_max_depth = DEFAULT_DECODE_MAX_DEPTH; | ||
| 391 | cfg->encode_refuse_badnum = DEFAULT_ENCODE_REFUSE_BADNUM; | 401 | cfg->encode_refuse_badnum = DEFAULT_ENCODE_REFUSE_BADNUM; |
| 392 | cfg->decode_refuse_badnum = DEFAULT_DECODE_REFUSE_BADNUM; | 402 | cfg->decode_refuse_badnum = DEFAULT_DECODE_REFUSE_BADNUM; |
| 393 | cfg->encode_keep_buffer = DEFAULT_ENCODE_KEEP_BUFFER; | 403 | cfg->encode_keep_buffer = DEFAULT_ENCODE_KEEP_BUFFER; |
| @@ -1094,10 +1104,19 @@ static void json_throw_parse_error(lua_State *l, json_parse_t *json, | |||
| 1094 | exp, found, token->index + 1); | 1104 | exp, found, token->index + 1); |
| 1095 | } | 1105 | } |
| 1096 | 1106 | ||
| 1097 | static void json_decode_checkstack(lua_State *l, json_parse_t *json, int n) | 1107 | static inline void json_decode_ascend(json_parse_t *json) |
| 1098 | { | 1108 | { |
| 1099 | if (lua_checkstack(l, n)) | 1109 | json->current_depth--; |
| 1110 | } | ||
| 1111 | |||
| 1112 | static void json_decode_descend(lua_State *l, json_parse_t *json, int slots) | ||
| 1113 | { | ||
| 1114 | json->current_depth++; | ||
| 1115 | |||
| 1116 | if (json->current_depth <= json->cfg->decode_max_depth && | ||
| 1117 | lua_checkstack(l, slots)) { | ||
| 1100 | return; | 1118 | return; |
| 1119 | } | ||
| 1101 | 1120 | ||
| 1102 | strbuf_free(json->tmp); | 1121 | strbuf_free(json->tmp); |
| 1103 | luaL_error(l, "Too many nested data structures"); | 1122 | luaL_error(l, "Too many nested data structures"); |
| @@ -1109,7 +1128,7 @@ static void json_parse_object_context(lua_State *l, json_parse_t *json) | |||
| 1109 | 1128 | ||
| 1110 | /* 3 slots required: | 1129 | /* 3 slots required: |
| 1111 | * .., table, key, value */ | 1130 | * .., table, key, value */ |
| 1112 | json_decode_checkstack(l, json, 3); | 1131 | json_decode_descend(l, json, 3); |
| 1113 | 1132 | ||
| 1114 | lua_newtable(l); | 1133 | lua_newtable(l); |
| 1115 | 1134 | ||
| @@ -1117,6 +1136,7 @@ static void json_parse_object_context(lua_State *l, json_parse_t *json) | |||
| 1117 | 1136 | ||
| 1118 | /* Handle empty objects */ | 1137 | /* Handle empty objects */ |
| 1119 | if (token.type == T_OBJ_END) { | 1138 | if (token.type == T_OBJ_END) { |
| 1139 | json_decode_ascend(json); | ||
| 1120 | return; | 1140 | return; |
| 1121 | } | 1141 | } |
| 1122 | 1142 | ||
| @@ -1140,8 +1160,10 @@ static void json_parse_object_context(lua_State *l, json_parse_t *json) | |||
| 1140 | 1160 | ||
| 1141 | json_next_token(json, &token); | 1161 | json_next_token(json, &token); |
| 1142 | 1162 | ||
| 1143 | if (token.type == T_OBJ_END) | 1163 | if (token.type == T_OBJ_END) { |
| 1164 | json_decode_ascend(json); | ||
| 1144 | return; | 1165 | return; |
| 1166 | } | ||
| 1145 | 1167 | ||
| 1146 | if (token.type != T_COMMA) | 1168 | if (token.type != T_COMMA) |
| 1147 | json_throw_parse_error(l, json, "comma or object end", &token); | 1169 | json_throw_parse_error(l, json, "comma or object end", &token); |
| @@ -1158,15 +1180,17 @@ static void json_parse_array_context(lua_State *l, json_parse_t *json) | |||
| 1158 | 1180 | ||
| 1159 | /* 2 slots required: | 1181 | /* 2 slots required: |
| 1160 | * .., table, value */ | 1182 | * .., table, value */ |
| 1161 | json_decode_checkstack(l, json, 2); | 1183 | json_decode_descend(l, json, 2); |
| 1162 | 1184 | ||
| 1163 | lua_newtable(l); | 1185 | lua_newtable(l); |
| 1164 | 1186 | ||
| 1165 | json_next_token(json, &token); | 1187 | json_next_token(json, &token); |
| 1166 | 1188 | ||
| 1167 | /* Handle empty arrays */ | 1189 | /* Handle empty arrays */ |
| 1168 | if (token.type == T_ARR_END) | 1190 | if (token.type == T_ARR_END) { |
| 1191 | json_decode_ascend(json); | ||
| 1169 | return; | 1192 | return; |
| 1193 | } | ||
| 1170 | 1194 | ||
| 1171 | for (i = 1; ; i++) { | 1195 | for (i = 1; ; i++) { |
| 1172 | json_process_value(l, json, &token); | 1196 | json_process_value(l, json, &token); |
| @@ -1174,8 +1198,10 @@ static void json_parse_array_context(lua_State *l, json_parse_t *json) | |||
| 1174 | 1198 | ||
| 1175 | json_next_token(json, &token); | 1199 | json_next_token(json, &token); |
| 1176 | 1200 | ||
| 1177 | if (token.type == T_ARR_END) | 1201 | if (token.type == T_ARR_END) { |
| 1202 | json_decode_ascend(json); | ||
| 1178 | return; | 1203 | return; |
| 1204 | } | ||
| 1179 | 1205 | ||
| 1180 | if (token.type != T_COMMA) | 1206 | if (token.type != T_COMMA) |
| 1181 | json_throw_parse_error(l, json, "comma or array end", &token); | 1207 | json_throw_parse_error(l, json, "comma or array end", &token); |
| @@ -1221,6 +1247,7 @@ static void lua_json_decode(lua_State *l, const char *json_text, int json_len) | |||
| 1221 | json_token_t token; | 1247 | json_token_t token; |
| 1222 | 1248 | ||
| 1223 | json.cfg = json_fetch_config(l); | 1249 | json.cfg = json_fetch_config(l); |
| 1250 | json.current_depth = 0; | ||
| 1224 | json.data = json_text; | 1251 | json.data = json_text; |
| 1225 | json.ptr = json.data; | 1252 | json.ptr = json.data; |
| 1226 | 1253 | ||
| @@ -1292,6 +1319,7 @@ static int lua_cjson_new(lua_State *l) | |||
| 1292 | { "decode", json_decode }, | 1319 | { "decode", json_decode }, |
| 1293 | { "encode_sparse_array", json_cfg_encode_sparse_array }, | 1320 | { "encode_sparse_array", json_cfg_encode_sparse_array }, |
| 1294 | { "encode_max_depth", json_cfg_encode_max_depth }, | 1321 | { "encode_max_depth", json_cfg_encode_max_depth }, |
| 1322 | { "decode_max_depth", json_cfg_decode_max_depth }, | ||
| 1295 | { "encode_number_precision", json_cfg_encode_number_precision }, | 1323 | { "encode_number_precision", json_cfg_encode_number_precision }, |
| 1296 | { "encode_keep_buffer", json_cfg_encode_keep_buffer }, | 1324 | { "encode_keep_buffer", json_cfg_encode_keep_buffer }, |
| 1297 | { "refuse_invalid_numbers", json_cfg_refuse_invalid_numbers }, | 1325 | { "refuse_invalid_numbers", json_cfg_refuse_invalid_numbers }, |
| @@ -158,6 +158,7 @@ setting = cjson.refuse_invalid_numbers([setting]) | |||
| 158 | depth = cjson.encode_max_depth([depth]) | 158 | depth = cjson.encode_max_depth([depth]) |
| 159 | convert, ratio, safe = cjson.encode_sparse_array([convert[, ratio[, safe]]]) | 159 | convert, ratio, safe = cjson.encode_sparse_array([convert[, ratio[, safe]]]) |
| 160 | keep = cjson.encode_keep_buffer([keep]) | 160 | keep = cjson.encode_keep_buffer([keep]) |
| 161 | depth = cjson.decode_max_depth([depth]) | ||
| 161 | ------------ | 162 | ------------ |
| 162 | 163 | ||
| 163 | 164 | ||
| @@ -239,6 +240,31 @@ numeric key will be stored as a Lua +string+. Any code assuming type | |||
| 239 | +number+ may break. | 240 | +number+ may break. |
| 240 | 241 | ||
| 241 | 242 | ||
| 243 | [[decode_max_depth]] | ||
| 244 | decode_max_depth | ||
| 245 | ~~~~~~~~~~~~~~~~ | ||
| 246 | |||
| 247 | [source,lua] | ||
| 248 | ------------ | ||
| 249 | depth = cjson.decode_max_depth([depth]) | ||
| 250 | -- "depth" must be a positive integer | ||
| 251 | ------------ | ||
| 252 | |||
| 253 | By default, Lua CJSON will reject JSON with arrays and/or objects | ||
| 254 | nested more than 20 deep. | ||
| 255 | |||
| 256 | This setting is only changed when an argument is provided. The current | ||
| 257 | setting is always returned. | ||
| 258 | |||
| 259 | When the maximum array/object depth is exceeded Lua CJSON will throw | ||
| 260 | an error. An error may be thrown before the depth limit is hit if Lua | ||
| 261 | is unable to allocate more objects on the Lua stack. | ||
| 262 | |||
| 263 | This check prevents unnecessarily complicated JSON from slowing down | ||
| 264 | the application, or crashing the application due to lack of process | ||
| 265 | stack space. | ||
| 266 | |||
| 267 | |||
| 242 | encode | 268 | encode |
| 243 | ~~~~~~ | 269 | ~~~~~~ |
| 244 | 270 | ||
