diff --git a/core/engine/src/builtins/array/mod.rs b/core/engine/src/builtins/array/mod.rs index acd695878ea..ff79728832f 100644 --- a/core/engine/src/builtins/array/mod.rs +++ b/core/engine/src/builtins/array/mod.rs @@ -1291,6 +1291,7 @@ impl Array { .with_message("length + number of arguments exceeds the max safe integer limit") .into()); } + // b. Let k be len. let mut k = len; // c. Repeat, while k > 0, diff --git a/core/engine/src/builtins/array/tests.rs b/core/engine/src/builtins/array/tests.rs index 7f8d2d98f72..12255e848e0 100644 --- a/core/engine/src/builtins/array/tests.rs +++ b/core/engine/src/builtins/array/tests.rs @@ -249,6 +249,24 @@ fn unshift() { TestAction::assert_eq("arr.unshift(1, 2)", 4), TestAction::assert("arrayEquals(arr, [1, 2, 3, 4])"), ]); + + // Test case from PR 5076 ensuring unshift doesn't bypass setters + run_test_actions([ + TestAction::run_harness(), + TestAction::run(indoc! {r#" + var array = [1]; + Object.defineProperty(Array.prototype, "1", { + set(_val) { + Object.freeze(array); + }, + }); + "#}), + TestAction::assert_native_error( + "array.unshift(0)", + JsNativeErrorKind::Type, + "cannot set non-writable property: 0", + ), + ]); } #[test] diff --git a/core/engine/src/vm/mod.rs b/core/engine/src/vm/mod.rs index f01c9bb47dd..ad21c3981f4 100644 --- a/core/engine/src/vm/mod.rs +++ b/core/engine/src/vm/mod.rs @@ -279,13 +279,21 @@ impl Stack { #[cfg(feature = "trace")] /// Display the stack trace of the current frame. fn display_trace(&self, frame: &CallFrame, frame_count: usize) -> String { + const MAX_VALUE_LENGTH: usize = 20; + const MAX_STACK_DISPLAY_WIDTH: usize = 60; + let mut string = String::from("[ "); for (i, (j, value)) in self.stack.iter().enumerate().rev().enumerate() { - match value { - value if value.is_callable() => string.push_str("[function]"), - value if value.is_object() => string.push_str("[object]"), - value => string.push_str(&value.display().to_string()), + let mut value_str = match value { + value if value.is_callable() => "[function]".to_string(), + value if value.is_object() => "[object]".to_string(), + value => value.display().to_string(), + }; + if value_str.len() > MAX_VALUE_LENGTH { + value_str.truncate(MAX_VALUE_LENGTH - 3); + value_str.push_str("..."); } + string.push_str(&value_str); if frame.frame_pointer() == j { let _ = write!(string, " |{frame_count}|"); @@ -296,6 +304,11 @@ impl Stack { string.push(' '); } + if string.len() > MAX_STACK_DISPLAY_WIDTH { + string.truncate(MAX_STACK_DISPLAY_WIDTH - 4); + string.push_str("... "); + } + string.push(']'); string } @@ -663,12 +676,17 @@ impl Context { .code_block .bytecode .next_instruction(frame.pc as usize); - let operands = self + let mut operands = self .vm .frame() .code_block() .instruction_operands(&instruction); + if operands.len() > Self::OPERAND_COLUMN_WIDTH { + operands.truncate(Self::OPERAND_COLUMN_WIDTH - 3); + operands.push_str("..."); + } + let instant = Instant::now(); let result = self.execute_instruction(f, opcode); let duration = instant.elapsed();