Scripts: loose equality and the JSON space string keep a converted string rooted while it is flattened

This commit is contained in:
dotCooCoo
2026-11-11 22:49:15 -08:00
parent 1f991536d6
commit 40283f4a38
3 changed files with 17 additions and 9 deletions
+2 -1
View File
@@ -474,7 +474,8 @@ fn settings(interp: &mut Interp, replacer: &Value, space: &Value) -> JsResult<Se
let n = to_integer(interp, &space)?.clamp(0.0, 10.0) as usize;
s.gap = vec![u16::from(b' '); n];
}
Value::String(t) => s.gap = flat_charged(interp, &t)?.iter().take(10).copied().collect(),
// Rooted, so what the string holds is still counted while its copy is reserved.
Value::String(t) => s.gap = interp.rooted(&[Value::String(t.clone())], |i| flat_charged(i, &t))?.iter().take(10).copied().collect(),
_ => {}
}
Ok(s)
+3 -1
View File
@@ -2816,7 +2816,9 @@ impl Interp {
| (Value::Bool(_), Value::Bool(_))
| (Value::Object(_), Value::Object(_)) => return Ok(strict_eq(&x, &y)),
(Value::Number(n), Value::String(s)) | (Value::String(s), Value::Number(n)) => {
return Ok(*n == string_to_number(&flat_charged(self, s)?));
// Rooted, so what the string holds is still counted while its copy is reserved.
let units = self.rooted(&[x.clone(), y.clone()], |i| flat_charged(i, s))?;
return Ok(*n == string_to_number(&units));
}
(Value::Bool(v), _) => x = Value::Number(f64::from(u8::from(*v))),
(_, Value::Bool(v)) => y = Value::Number(f64::from(u8::from(*v))),
+12 -7
View File
@@ -361,13 +361,18 @@ fn a_converted_rope_counts_what_it_holds_while_its_copy_is_made() {
let build = "var s = 'x'; for (var i = 0; i < 18; i++) s = s + s; function f(c) { return s + c; } \
function mk() { var a = f('a'); a[0]; return a + 'b'; }";
let limits = Limits { heap_bytes: 4 * 262_146, ..Limits::default() };
let not_stopped: Vec<_> = ["+({ valueOf: mk })", "({})[{ toString: mk }]"]
.into_iter()
.filter(|read| {
let result = Realm::with_options(Options::default(), limits.clone()).run(&format!("{build} {read}; 0"));
!matches!(result, Err(ref e) if e.kind == RunErrorKind::Limit(LimitKind::Heap))
})
.collect();
let not_stopped: Vec<_> = [
"+({ valueOf: mk })",
"({})[{ toString: mk }]",
"({ valueOf: mk }) == 1",
"JSON.stringify(0, null, (function () { var o = new String(''); o.toString = mk; return o; })())",
]
.into_iter()
.filter(|read| {
let result = Realm::with_options(Options::default(), limits.clone()).run(&format!("{build} {read}; 0"));
!matches!(result, Err(ref e) if e.kind == RunErrorKind::Limit(LimitKind::Heap))
})
.collect();
assert!(not_stopped.is_empty(), "not stopped by the heap limit: {not_stopped:?}");
}