mirror of
https://github.com/pjh456/OxideJS.git
synced 2026-10-23 18:21:13 +08:00
fix: JSON 解析器嵌套深度上限 128 防深嵌套栈溢出
This commit is contained in:
@@ -168,9 +168,15 @@ struct JsonNode {
|
||||
///
|
||||
/// # 边界与前提
|
||||
/// - 前导零数字、尾随逗号、溢出(1e400)、孤立 surrogate 均报 SyntaxError。
|
||||
/// - 嵌套 object/array 深度上限 `MAX_JSON_DEPTH` 层,超限报 SyntaxError
|
||||
/// (进入时先计入再判定,防深嵌套在递归展开前耗尽栈)。
|
||||
/// - 重复对象键:末写胜(键序由 build_js_value 统一)。
|
||||
fn parse_json(text: &str) -> Result<JsonNode, String> {
|
||||
let mut p = JsonParser { text, pos: 0 };
|
||||
let mut p = JsonParser {
|
||||
text,
|
||||
pos: 0,
|
||||
depth: 0,
|
||||
};
|
||||
p.skip_ws();
|
||||
let node = p.parse_value()?;
|
||||
p.skip_ws();
|
||||
@@ -180,9 +186,13 @@ fn parse_json(text: &str) -> Result<JsonNode, String> {
|
||||
Ok(node)
|
||||
}
|
||||
|
||||
/// 嵌套容器深度上限:object/array 进入时计入,超限报 SyntaxError。
|
||||
const MAX_JSON_DEPTH: usize = 128;
|
||||
|
||||
struct JsonParser<'a> {
|
||||
text: &'a str,
|
||||
pos: usize,
|
||||
depth: usize,
|
||||
}
|
||||
|
||||
impl<'a> JsonParser<'a> {
|
||||
@@ -243,14 +253,27 @@ impl<'a> JsonParser<'a> {
|
||||
Ok(self.prim(JsonKind::String(s), start))
|
||||
}
|
||||
b'[' => {
|
||||
// 深度计数:进入时先 +1 再判上限,超限在递归展开前拒绝。
|
||||
self.depth += 1;
|
||||
if self.depth > MAX_JSON_DEPTH {
|
||||
self.depth -= 1;
|
||||
return Err("recursion limit exceeded".into());
|
||||
}
|
||||
let items = self.parse_array()?;
|
||||
self.depth -= 1;
|
||||
Ok(JsonNode {
|
||||
kind: JsonKind::Array(items),
|
||||
source: None,
|
||||
})
|
||||
}
|
||||
b'{' => {
|
||||
self.depth += 1;
|
||||
if self.depth > MAX_JSON_DEPTH {
|
||||
self.depth -= 1;
|
||||
return Err("recursion limit exceeded".into());
|
||||
}
|
||||
let entries = self.parse_object()?;
|
||||
self.depth -= 1;
|
||||
Ok(JsonNode {
|
||||
kind: JsonKind::Object(entries),
|
||||
source: None,
|
||||
|
||||
@@ -740,6 +740,42 @@ fn replacer_whitelist_undefined_value_skipped() {
|
||||
assert_eq!(out, r#"{"a":1}"#);
|
||||
}
|
||||
|
||||
// --- 嵌套深度上限(递归限制)---
|
||||
|
||||
// 深度 128 层恰好过:128 层嵌套数组正常解析。
|
||||
#[test]
|
||||
fn parse_depth_128_ok() {
|
||||
let out = eval_str(
|
||||
"(() => { const v = JSON.parse('['.repeat(128) + ']'.repeat(128)); \
|
||||
return String(Array.isArray(v) && v.length === 1); })()",
|
||||
)
|
||||
.unwrap();
|
||||
assert_eq!(out, "true");
|
||||
}
|
||||
|
||||
// 深度 129 层超限:抛 SyntaxError(递归限制),而非进程 abort。
|
||||
#[test]
|
||||
fn parse_depth_129_throws() {
|
||||
let out = eval_str(
|
||||
"(() => { try { JSON.parse('['.repeat(129) + ']'.repeat(129)); return 'no-throw'; } \
|
||||
catch (e) { return e.constructor.name + '|' + e.message; } })()",
|
||||
)
|
||||
.unwrap();
|
||||
assert_eq!(out, "SyntaxError|recursion limit exceeded");
|
||||
}
|
||||
|
||||
// 深度计数复位:深嵌套解析超限失败后,随后普通嵌套解析不受残留计数影响。
|
||||
#[test]
|
||||
fn parse_depth_count_resets() {
|
||||
let out = eval_str(
|
||||
"(() => { try { JSON.parse('['.repeat(129) + ']'.repeat(129)); } catch (e) {} \
|
||||
const v = JSON.parse('{\"a\":{\"b\":[1]}}'); \
|
||||
return String(v.a.b[0]); })()",
|
||||
)
|
||||
.unwrap();
|
||||
assert_eq!(out, "1");
|
||||
}
|
||||
|
||||
fn eval_str(source: &str) -> Result<String, String> {
|
||||
let (vm, result) = eval(source)?;
|
||||
vm.lookup_str(result)
|
||||
|
||||
Reference in New Issue
Block a user