Skip to content

Commit f5e88de

Browse files
fix(built-ins): modify IsTypedArrayFixedLength implementation to match spec (#5262)
<!--- Thank you for contributing to Boa! Please fill out the template below, and remove or add any information as you feel necessary. ---> This Pull Request fixes/closes #5256. As required by ecma262, `Object.preventExtensions` may be applied to typed arrays without error if the `IsTypedArrayFixedLength` is not false. Prior to this commit, this check was incorrectly implemented via `ArrayBuffer::is_fixed_len` which does not/can not include an AUTO length check. This discrepancy lies in that the requirements of a fixed-length `TypedArray` slightly differ from a fixed-length arraybuffer. It adds and replaces the checks as specified by [`sec-istypedarrayfixedlength`](https://tc39.es/ecma262/#sec-istypedarrayfixedlength). Now, [typed_array_exotic_prevent_extensions](https://github.com/boa-dev/boa/blob/main/core/engine/src/builtins/typed_array/object.rs#L289) should - return `Ok(false)` when the `TypedArray` is auto length or when the backing `ArrayBuffer` is resizable. - failing the above, call `ordinary_prevent_extensions` if the backing array is a `SharedArrayBuffer`. This PR also adds a test to ensure what the title of this issue says. In addition, test262's `test/staging/built-ins/preventExtensions` should now pass completely.
1 parent cd1a386 commit f5e88de

2 files changed

Lines changed: 45 additions & 3 deletions

File tree

core/engine/src/builtins/typed_array/object.rs

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use std::sync::atomic::Ordering;
44

55
use crate::{
66
Context, JsExpect, JsNativeError, JsResult, JsString, JsValue,
7-
builtins::array_buffer::BufferObject,
7+
builtins::array_buffer::{BufferObject, BufferRef},
88
object::{
99
JsData, JsObject,
1010
internal_methods::{
@@ -279,6 +279,26 @@ impl TypedArray {
279279
// 4. Return true.
280280
Some(index)
281281
}
282+
283+
/// Abstract operation `IsTypedArrayFixedLength ( O )`.
284+
///
285+
/// More information:
286+
/// - [ECMAScript reference][spec]
287+
///
288+
/// [spec]: https://tc39.es/ecma262/#sec-istypedarrayfixedlength
289+
fn is_fixed_length(&self) -> bool {
290+
// 1. If O.[[ArrayLength]] is auto, return false.
291+
if self.is_auto_length() {
292+
return false;
293+
}
294+
295+
// 2. Let buffer be O.[[ViewedArrayBuffer]].
296+
match self.viewed_array_buffer().as_buffer() {
297+
// 3. If IsFixedLengthArrayBuffer(buffer) is false and IsSharedArrayBuffer(buffer) is false, return false.
298+
BufferRef::Buffer(buf) => buf.is_fixed_len(),
299+
BufferRef::SharedBuffer(_) => true,
300+
}
301+
}
282302
}
283303

284304
// Integer-Indexed Exotic Objects [[PreventExtensions]] ( O )
@@ -295,8 +315,9 @@ pub(crate) fn typed_array_exotic_prevent_extensions(
295315
.downcast_ref::<TypedArray>()
296316
.js_expect("must be a TypedArray")?;
297317

298-
ta.viewed_array_buffer().as_buffer().is_fixed_len()
299-
};
318+
ta.is_fixed_length()
319+
}; // Note: this block ensures that the borrow of obj is dropped
320+
// so it may be re-borrowed in step 3
300321

301322
// 1. If IsTypedArrayFixedLength(O) is false, return false.
302323
if !is_fixed_length {

core/engine/src/builtins/typed_array/tests.rs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -161,3 +161,24 @@ fn typedarray_conversion_mismatch_throws() {
161161
),
162162
]);
163163
}
164+
165+
#[test]
166+
fn typedarray_exotic_prevent_extensions() {
167+
// ref: https://github.com/tc39/test262/blob/main/test/staging/built-ins/Object/preventExtensions/preventExtensions-variable-length-typed-arrays.js
168+
run_test_actions([
169+
TestAction::run("const gsab = new SharedArrayBuffer(4, { maxByteLength: 8 });"),
170+
TestAction::run("const fixedLength = new Uint8Array(gsab, 0, 4);"),
171+
TestAction::run("const fixedLengthWithOffset = new Uint8Array(gsab, 2, 2);"),
172+
TestAction::run("Object.preventExtensions(fixedLength);"),
173+
TestAction::run("Object.preventExtensions(fixedLengthWithOffset);"),
174+
TestAction::assert("!Object.isExtensible(fixedLength)"),
175+
TestAction::assert("!Object.isExtensible(fixedLengthWithOffset)"),
176+
TestAction::run("const rab = new ArrayBuffer(4);"),
177+
TestAction::run("const fixedLength1 = new Uint8Array(rab, 0, 4);"),
178+
TestAction::run("const fixedLengthWithOffset1 = new Uint8Array(rab, 2, 2);"),
179+
TestAction::run("Object.preventExtensions(fixedLength1);"),
180+
TestAction::run("Object.preventExtensions(fixedLengthWithOffset1);"),
181+
TestAction::assert("!Object.isExtensible(fixedLength1)"),
182+
TestAction::assert("!Object.isExtensible(fixedLengthWithOffset1)"),
183+
]);
184+
}

0 commit comments

Comments
 (0)