Skip to content

Commit b0e4d2c

Browse files
committed
yyjson 0eca326, recursion limit
1 parent 5067ead commit b0e4d2c

File tree

6 files changed

+639
-100
lines changed

6 files changed

+639
-100
lines changed

README.md

+3
Original file line numberDiff line numberDiff line change
@@ -625,6 +625,9 @@ It raises `JSONDecodeError` if given an invalid type or invalid
625625
JSON. This includes if the input contains `NaN`, `Infinity`, or `-Infinity`,
626626
which the standard library allows, but is not valid JSON.
627627

628+
It raises `JSONDecodeError` if a combination of array or object recurses
629+
1024 levels deep.
630+
628631
`JSONDecodeError` is a subclass of `json.JSONDecodeError` and `ValueError`.
629632
This is for compatibility with the standard library.
630633

include/yyjson-recursion-limit.patch

+161
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,161 @@
1+
diff --git a/include/yyjson/yyjson.c b/include/yyjson/yyjson.c
2+
index e76f538..4bac033 100644
3+
--- a/include/yyjson/yyjson.c
4+
+++ b/include/yyjson/yyjson.c
5+
@@ -329,8 +329,9 @@ uint32_t yyjson_version(void) {
6+
#ifndef YYJSON_DISABLE_UTF8_VALIDATION
7+
#define YYJSON_DISABLE_UTF8_VALIDATION 0
8+
#endif
9+
-
10+
-
11+
+#ifndef YYJSON_READER_CONTAINER_RECURSION_LIMIT
12+
+#define YYJSON_READER_CONTAINER_RECURSION_LIMIT 1024
13+
+#endif
14+
15+
/*==============================================================================
16+
* Macros
17+
@@ -5798,6 +5799,8 @@ fail_character:
18+
return_err(cur, UNEXPECTED_CHARACTER, "unexpected character");
19+
fail_garbage:
20+
return_err(cur, UNEXPECTED_CONTENT, "unexpected content after document");
21+
+fail_recursion:
22+
+ return_err(cur, RECURSION_DEPTH, "array and object recursion depth exceeded");
23+
24+
#undef return_err
25+
}
26+
@@ -5854,7 +5857,8 @@ static_inline yyjson_doc *read_root_minify(u8 *hdr,
27+
yyjson_val *ctn_parent; /* parent of current container */
28+
yyjson_doc *doc; /* the JSON document, equals to val_hdr */
29+
const char *msg; /* error message */
30+
-
31+
+
32+
+ u32 container_depth = 0; /* limit on number of open array and map */
33+
bool raw; /* read number as raw */
34+
bool inv; /* allow invalid unicode */
35+
u8 *raw_end; /* raw end for null-terminator */
36+
@@ -5889,6 +5893,11 @@ static_inline yyjson_doc *read_root_minify(u8 *hdr,
37+
}
38+
39+
arr_begin:
40+
+ container_depth++;
41+
+ if (unlikely(container_depth >= YYJSON_READER_CONTAINER_RECURSION_LIMIT)) {
42+
+ goto fail_recursion;
43+
+ }
44+
+
45+
/* save current container */
46+
ctn->tag = (((u64)ctn_len + 1) << YYJSON_TAG_BIT) |
47+
(ctn->tag & YYJSON_TAG_MASK);
48+
@@ -5988,6 +5997,8 @@ arr_val_end:
49+
goto fail_character;
50+
51+
arr_end:
52+
+ container_depth--;
53+
+
54+
/* get parent container */
55+
ctn_parent = (yyjson_val *)(void *)((u8 *)ctn - ctn->uni.ofs);
56+
57+
@@ -6006,6 +6017,11 @@ arr_end:
58+
}
59+
60+
obj_begin:
61+
+ container_depth++;
62+
+ if (unlikely(container_depth >= YYJSON_READER_CONTAINER_RECURSION_LIMIT)) {
63+
+ goto fail_recursion;
64+
+ }
65+
+
66+
/* push container */
67+
ctn->tag = (((u64)ctn_len + 1) << YYJSON_TAG_BIT) |
68+
(ctn->tag & YYJSON_TAG_MASK);
69+
@@ -6134,6 +6150,8 @@ obj_val_end:
70+
goto fail_character;
71+
72+
obj_end:
73+
+ container_depth--;
74+
+
75+
/* pop container */
76+
ctn_parent = (yyjson_val *)(void *)((u8 *)ctn - ctn->uni.ofs);
77+
/* point to the next value */
78+
@@ -6185,6 +6203,8 @@ fail_character:
79+
return_err(cur, UNEXPECTED_CHARACTER, "unexpected character");
80+
fail_garbage:
81+
return_err(cur, UNEXPECTED_CONTENT, "unexpected content after document");
82+
+fail_recursion:
83+
+ return_err(cur, RECURSION_DEPTH, "array and object recursion depth exceeded");
84+
85+
#undef val_incr
86+
#undef return_err
87+
@@ -6242,7 +6262,8 @@ static_inline yyjson_doc *read_root_pretty(u8 *hdr,
88+
yyjson_val *ctn_parent; /* parent of current container */
89+
yyjson_doc *doc; /* the JSON document, equals to val_hdr */
90+
const char *msg; /* error message */
91+
-
92+
+
93+
+ u32 container_depth = 0; /* limit on number of open array and map */
94+
bool raw; /* read number as raw */
95+
bool inv; /* allow invalid unicode */
96+
u8 *raw_end; /* raw end for null-terminator */
97+
@@ -6279,6 +6300,11 @@ static_inline yyjson_doc *read_root_pretty(u8 *hdr,
98+
}
99+
100+
arr_begin:
101+
+ container_depth++;
102+
+ if (unlikely(container_depth >= YYJSON_READER_CONTAINER_RECURSION_LIMIT)) {
103+
+ goto fail_recursion;
104+
+ }
105+
+
106+
/* save current container */
107+
ctn->tag = (((u64)ctn_len + 1) << YYJSON_TAG_BIT) |
108+
(ctn->tag & YYJSON_TAG_MASK);
109+
@@ -6395,6 +6421,8 @@ arr_val_end:
110+
goto fail_character;
111+
112+
arr_end:
113+
+ container_depth--;
114+
+
115+
/* get parent container */
116+
ctn_parent = (yyjson_val *)(void *)((u8 *)ctn - ctn->uni.ofs);
117+
118+
@@ -6414,6 +6442,11 @@ arr_end:
119+
}
120+
121+
obj_begin:
122+
+ container_depth++;
123+
+ if (unlikely(container_depth >= YYJSON_READER_CONTAINER_RECURSION_LIMIT)) {
124+
+ goto fail_recursion;
125+
+ }
126+
+
127+
/* push container */
128+
ctn->tag = (((u64)ctn_len + 1) << YYJSON_TAG_BIT) |
129+
(ctn->tag & YYJSON_TAG_MASK);
130+
@@ -6562,6 +6595,8 @@ obj_val_end:
131+
goto fail_character;
132+
133+
obj_end:
134+
+ container_depth--;
135+
+
136+
/* pop container */
137+
ctn_parent = (yyjson_val *)(void *)((u8 *)ctn - ctn->uni.ofs);
138+
/* point to the next value */
139+
@@ -6614,6 +6649,8 @@ fail_character:
140+
return_err(cur, UNEXPECTED_CHARACTER, "unexpected character");
141+
fail_garbage:
142+
return_err(cur, UNEXPECTED_CONTENT, "unexpected content after document");
143+
+fail_recursion:
144+
+ return_err(cur, RECURSION_DEPTH, "array and object recursion depth exceeded");
145+
146+
#undef val_incr
147+
#undef return_err
148+
diff --git a/include/yyjson/yyjson.h b/include/yyjson/yyjson.h
149+
index c393408..bc688e0 100644
150+
--- a/include/yyjson/yyjson.h
151+
+++ b/include/yyjson/yyjson.h
152+
@@ -831,6 +831,9 @@ static const yyjson_read_code YYJSON_READ_ERROR_FILE_OPEN = 12;
153+
/** Failed to read a file. */
154+
static const yyjson_read_code YYJSON_READ_ERROR_FILE_READ = 13;
155+
156+
+/** Document exceeded YYJSON_READER_CONTAINER_RECURSION_LIMIT. */
157+
+static const yyjson_read_code YYJSON_READ_ERROR_RECURSION_DEPTH = 14;
158+
+
159+
/** Error information for JSON reader. */
160+
typedef struct yyjson_read_err {
161+
/** Error code, see `yyjson_read_code` for all possible values. */

0 commit comments

Comments
 (0)