diff --git a/crates/js/src/interp.rs b/crates/js/src/interp.rs index 1740c5733..9d16046d0 100644 --- a/crates/js/src/interp.rs +++ b/crates/js/src/interp.rs @@ -1550,7 +1550,8 @@ impl Interp { let saved = self.temp_roots.len(); let mut out = Vec::with_capacity(n); for i in 0..n { - match self.get_from(*o, &index_key(u32::try_from(i).unwrap_or(u32::MAX)), list) { + // Each element read takes fuel, so a long array-like list stays within the run's limits. + match self.use_fuel().and_then(|()| self.get_from(*o, &index_key(u32::try_from(i).unwrap_or(u32::MAX)), list)) { Ok(v) => { self.temp_roots.push(v.clone()); out.push(v); diff --git a/crates/js/src/interp_tests.rs b/crates/js/src/interp_tests.rs index 8dff13050..03d9e6639 100644 --- a/crates/js/src/interp_tests.rs +++ b/crates/js/src/interp_tests.rs @@ -391,6 +391,13 @@ fn shrinking_an_array_takes_fuel_for_each_property() { assert_eq!(realm.run("a.length = 1; a.length + a[0] + (99999 in a ? 1 : 0)"), Ok(JsValue::Number(1.0))); } +#[test] +fn apply_takes_fuel_for_each_argument_it_reads() { + let mut realm = small(Limits { fuel: 1000, ..Limits::default() }); + assert_eq!(limit(&mut realm, "(function () {}).apply(null, {length: 65536});"), LimitKind::Fuel); + assert_eq!(realm.run("(function () { return arguments.length; }).apply(null, {length: 100})"), Ok(JsValue::Number(100.0))); +} + #[test] fn declarations_check_the_heap_before_they_are_bound() { // Each script declares more than fits in the heap. The run ends with the heap limit before