mirror of
https://github.com/storytold/vectorcraft.git
synced 2026-11-09 14:14:11 +00:00
JavaScript: JSON.parse releases its text before the reviver runs
The text is rooted and held only while the parse runs. A reviver can use the room the text took.
This commit is contained in:
@@ -162,15 +162,16 @@ fn parse(interp: &mut Interp, _: Value, args: &[Value], _: bool) -> JsResult<Val
|
||||
let mark = interp.temp_roots.len();
|
||||
// The text stays rooted for the whole parse, so a collection still counts it.
|
||||
interp.temp_roots.push(source.clone());
|
||||
let r = super::global::units_of(interp, std::slice::from_ref(&source)).and_then(|text| {
|
||||
let v = parse_text(interp, &text)?;
|
||||
let reviver = arg(args, 1);
|
||||
if !interp.is_callable(&reviver) {
|
||||
return Ok(v);
|
||||
}
|
||||
interp.temp_roots.push(v.clone());
|
||||
revive(interp, v, &reviver)
|
||||
});
|
||||
let parsed = super::global::units_of(interp, std::slice::from_ref(&source)).and_then(|text| parse_text(interp, &text));
|
||||
interp.temp_roots.truncate(mark);
|
||||
drop(source);
|
||||
let v = parsed?;
|
||||
let reviver = arg(args, 1);
|
||||
if !interp.is_callable(&reviver) {
|
||||
return Ok(v);
|
||||
}
|
||||
interp.temp_roots.push(v.clone());
|
||||
let r = revive(interp, v, &reviver);
|
||||
interp.temp_roots.truncate(mark);
|
||||
r
|
||||
}
|
||||
|
||||
@@ -722,6 +722,14 @@ fn json_parse_keeps_its_text_counted_for_the_whole_parse() {
|
||||
assert_eq!(realm.run(setup), Ok(JsValue::Number(0.0)));
|
||||
realm.interp().collect_garbage();
|
||||
assert_eq!(limit(&mut realm, parse), LimitKind::Heap);
|
||||
// The text is released before the reviver runs, so the reviver can use the room it took.
|
||||
let setup = "var ws = new Array(65537).join(' '); var o = {toString: function () { return ws + '1'; }}; 0";
|
||||
let mut measure = small(Limits::default());
|
||||
assert_eq!(measure.run(setup), Ok(JsValue::Number(0.0)));
|
||||
let heap_bytes = measure.collect_garbage() + 2 * 65537 + (16 << 10);
|
||||
let mut realm = small(Limits { heap_bytes, ..Limits::default() });
|
||||
assert_eq!(realm.run(setup), Ok(JsValue::Number(0.0)));
|
||||
assert_eq!(realm.run("JSON.parse(o, function () { return new Array(40001).join('x').length; })"), Ok(JsValue::Number(40000.0)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
Reference in New Issue
Block a user