Skip to content

Commit

Permalink
[JSC] DataView constructor should check if byteOffset exceeds source …
Browse files Browse the repository at this point in the history
…ArrayBuffer length before creating an instance

https://bugs.webkit.org/show_bug.cgi?id=273689

Reviewed by Yusuke Suzuki.

According to the spec[1], should check if byteOffset exceeds source ArrayBuffer length before
creating an instance. This patch fixes the test case that is failing in test262[2].

[1]: https://tc39.es/ecma262/#sec-dataview-buffer-byteoffset-bytelength
[2]: https://github.com/tc39/test262/blob/main/test/built-ins/DataView/byteOffset-validated-against-initial-buffer-length.js

* JSTests/stress/dataview-construct.js:
(shouldThrow):
* JSTests/test262/expectations.yaml:
* Source/JavaScriptCore/runtime/JSGenericTypedArrayViewConstructorInlines.h:
(JSC::constructGenericTypedArrayViewImpl):

Canonical link: https://commits.webkit.org/278385@main
  • Loading branch information
sosukesuzuki authored and Constellation committed May 5, 2024
1 parent f941ea9 commit b56ff58
Show file tree
Hide file tree
Showing 3 changed files with 20 additions and 15 deletions.
2 changes: 1 addition & 1 deletion JSTests/stress/dataview-construct.js
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ shouldThrow(() => {

shouldThrow(() => {
new DataView(buffer, 256);
}, "RangeError: Length out of range of buffer");
}, "RangeError: byteOffset exceeds source ArrayBuffer byteLength");

shouldThrow(() => {
new DataView(buffer, -1);
Expand Down
3 changes: 0 additions & 3 deletions JSTests/test262/expectations.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -54,9 +54,6 @@ test/built-ins/AsyncFromSyncIteratorPrototype/throw/throw-undefined-return-objec
test/built-ins/AsyncFromSyncIteratorPrototype/throw/throw-undefined.js:
default: 'Test262:AsyncTestFailure:Test262Error: Test262Error: Promise should be rejected Thrown value was not an object!'
strict mode: 'Test262:AsyncTestFailure:Test262Error: Test262Error: Promise should be rejected Thrown value was not an object!'
test/built-ins/DataView/byteOffset-validated-against-initial-buffer-length.js:
default: 'Test262Error: Expected a RangeError but got a Test262Error'
strict mode: 'Test262Error: Expected a RangeError but got a Test262Error'
test/built-ins/Function/internals/Construct/derived-return-val-realm.js:
default: 'Test262Error: Expected a TypeError but got a different error constructor with the same name'
strict mode: 'Test262Error: Expected a TypeError but got a different error constructor with the same name'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -260,6 +260,19 @@ ALWAYS_INLINE EncodedJSValue constructGenericTypedArrayViewImpl(JSGlobalObject*
size_t offset = 0;
std::optional<size_t> length;
if (auto* arrayBuffer = jsDynamicCast<JSArrayBuffer*>(firstValue)) {
if (argCount > 1) {
offset = callFrame->uncheckedArgument(1).toTypedArrayIndex(globalObject, "byteOffset"_s);
RETURN_IF_EXCEPTION(scope, { });

if constexpr (ViewClass::TypedArrayStorageType == TypeDataView) {
RefPtr<ArrayBuffer> buffer = arrayBuffer->impl();
if (UNLIKELY(offset > buffer->byteLength())) {
throwRangeError(globalObject, scope, "byteOffset exceeds source ArrayBuffer byteLength"_s);
RETURN_IF_EXCEPTION(scope, { });
}
}
}

if (arrayBuffer->isResizableOrGrowableShared()) {
structure = JSC_GET_DERIVED_STRUCTURE(vm, resizableOrGrowableSharedTypedArrayStructureWithTypedArrayType<ViewClass::TypedArrayStorageType>, newTarget, callFrame->jsCallee());
RETURN_IF_EXCEPTION(scope, { });
Expand All @@ -268,17 +281,12 @@ ALWAYS_INLINE EncodedJSValue constructGenericTypedArrayViewImpl(JSGlobalObject*
RETURN_IF_EXCEPTION(scope, { });
}

if (argCount > 1) {
offset = callFrame->uncheckedArgument(1).toTypedArrayIndex(globalObject, "byteOffset"_s);
RETURN_IF_EXCEPTION(scope, encodedJSValue());

if (argCount > 2) {
// If the length value is present but undefined, treat it as missing.
JSValue lengthValue = callFrame->uncheckedArgument(2);
if (!lengthValue.isUndefined()) {
length = lengthValue.toTypedArrayIndex(globalObject, ViewClass::TypedArrayStorageType == TypeDataView ? "byteLength"_s : "length"_s);
RETURN_IF_EXCEPTION(scope, encodedJSValue());
}
if (argCount > 2) {
// If the length value is present but undefined, treat it as missing.
JSValue lengthValue = callFrame->uncheckedArgument(2);
if (!lengthValue.isUndefined()) {
length = lengthValue.toTypedArrayIndex(globalObject, ViewClass::TypedArrayStorageType == TypeDataView ? "byteLength"_s : "length"_s);
RETURN_IF_EXCEPTION(scope, encodedJSValue());
}
}
} else {
Expand Down

0 comments on commit b56ff58

Please sign in to comment.