From 7554270e9b70a06fe6ab42e5ba965b3752597a41 Mon Sep 17 00:00:00 2001 From: HyukWoo Park Date: Tue, 10 Dec 2024 14:03:28 +0900 Subject: [PATCH] Handle out-of-bound access in TypedArray Signed-off-by: HyukWoo Park --- src/builtins/BuiltinTypedArray.cpp | 12 +- src/runtime/TypedArrayObject.cpp | 216 ++++++++++++++--------------- 2 files changed, 114 insertions(+), 114 deletions(-) diff --git a/src/builtins/BuiltinTypedArray.cpp b/src/builtins/BuiltinTypedArray.cpp index 670542de0..f9366e059 100644 --- a/src/builtins/BuiltinTypedArray.cpp +++ b/src/builtins/BuiltinTypedArray.cpp @@ -763,20 +763,20 @@ static Value builtinTypedArraySet(ExecutionState& state, Value thisValue, size_t ErrorObject::throwBuiltinError(state, ErrorCode::RangeError, strings->TypedArray.string(), true, strings->set.string(), ErrorObject::Messages::GlobalObject_InvalidArrayLength); } - size_t targetByteIndex = targetOffset * targetElementSize + targetByteOffset; size_t k = 0; - size_t limit = targetByteIndex + targetElementSize * srcLength; - while (targetByteIndex < limit) { + size_t targetByteIndex = targetOffset * targetElementSize + targetByteOffset; + while (k < srcLength) { Value value = src->get(state, ObjectPropertyName(state, Value(k))).value(state, src); + if (UNLIKELY(isBigIntArray)) { value = value.toBigInt(state); } else { value = Value(Value::DoubleToIntConvertibleTestNeeds, value.toNumber(state)); } - targetBuffer->throwTypeErrorIfDetached(state); - // Perform SetValueInBuffer(targetBuffer, targetByteIndex, targetType, value, true, "Unordered"). - targetBuffer->setValueInBuffer(state, targetByteIndex, target->typedArrayType(), value); + if (LIKELY(!targetBuffer->isDetachedBuffer() && targetByteIndex + targetElementSize <= targetBuffer->byteLength())) { + targetBuffer->setValueInBuffer(state, targetByteIndex, target->typedArrayType(), value); + } k++; targetByteIndex += targetElementSize; diff --git a/src/runtime/TypedArrayObject.cpp b/src/runtime/TypedArrayObject.cpp index 0778bca32..db7ff633c 100644 --- a/src/runtime/TypedArrayObject.cpp +++ b/src/runtime/TypedArrayObject.cpp @@ -216,114 +216,114 @@ bool TypedArrayObject::integerIndexedElementSet(ExecutionState& state, double in return true; } -#define DECLARE_TYPEDARRAY(TYPE, type, siz, nativeType) \ - TypedArrayObject* TYPE##ArrayObject::allocateTypedArray(ExecutionState& state, Object* newTarget, size_t length) \ - { \ - ASSERT(!!newTarget); \ - Object* proto = Object::getPrototypeFromConstructor(state, newTarget, [](ExecutionState& state, Context* constructorRealm) -> Object* { \ - return constructorRealm->globalObject()->type##ArrayPrototype(); \ - }); \ - TypedArrayObject* obj = new TYPE##ArrayObject(state, proto); \ - if (length == std::numeric_limits::max()) { \ - obj->setBuffer(nullptr, 0, 0, 0); \ - } else { \ - auto buffer = ArrayBufferObject::allocateArrayBuffer(state, state.context()->globalObject()->arrayBuffer(), length * siz); \ - obj->setBuffer(buffer, 0, length* siz, length); \ - } \ - return obj; \ - } \ - \ - template \ - Value TYPE##ArrayObject::getDirectValueFromBuffer(ExecutionState& state, size_t byteindex) \ - { \ - typedef typename TYPE##Adaptor::Type Type; \ - ASSERT(byteLength()); \ - size_t elementSize = sizeof(Type); \ - ASSERT(byteindex + elementSize <= byteLength()); \ - auto bufferAddress = rawBuffer(); \ - if (UNLIKELY(bufferAddress == nullptr)) { \ - return Value(); \ - } \ - uint8_t* rawStart = bufferAddress + byteindex; \ - Type res; \ - if (isLittleEndian) { \ - res = *((Type*)rawStart); \ - } else { \ - for (size_t i = 0; i < elementSize; i++) { \ - ((uint8_t*)&res)[elementSize - i - 1] = rawStart[i]; \ - } \ - } \ - if (std::is_same::value) { \ - return Value(new BigInt((int64_t)res)); \ - } else if (std::is_same::value) { \ - return Value(new BigInt((uint64_t)res)); \ - } else if (std::is_same::value) { \ - return Value((uint8_t)res); \ - } else if (std::is_same::value) { \ - return Value((uint16_t)res); \ - } else if (std::is_same::value) { \ - return Value((uint32_t)res); \ - } else if (std::is_same::value) { \ - return Value((int8_t)res); \ - } else if (std::is_same::value) { \ - return Value((int16_t)res); \ - } else if (std::is_same::value) { \ - return Value((int32_t)res); \ - } \ - return Value(Value::DoubleToIntConvertibleTestNeeds, res); \ - } \ - template \ - void TYPE##ArrayObject::setDirectValueInBuffer(ExecutionState& state, size_t byteindex, const Value& val) \ - { \ - typedef typename TYPE##Adaptor::Type Type; \ - Type littleEndianVal = TYPE##Adaptor::toNative(state, val); \ - ASSERT(byteLength()); \ - size_t elementSize = siz; \ - ASSERT(byteindex + elementSize <= byteLength()); \ - auto bufferAddress = rawBuffer(); \ - uint8_t* rawStart = bufferAddress + byteindex; \ - \ - if (isLittleEndian) { \ - *((Type*)rawStart) = littleEndianVal; \ - } else { \ - for (size_t i = 0; i < elementSize; i++) { \ - rawStart[i] = ((uint8_t*)&littleEndianVal)[elementSize - i - 1]; \ - } \ - } \ - } \ - \ - ObjectGetResult TYPE##ArrayObject::getIndexedProperty(ExecutionState& state, const Value& property, const Value& receiver) \ - { \ - if (LIKELY(property.isUInt32() && (size_t)property.asUInt32() < arrayLength())) { \ - if (UNLIKELY(buffer()->isDetachedBuffer())) { \ - return ObjectGetResult(); \ - } \ - size_t indexedPosition = property.asUInt32() * siz; \ - return ObjectGetResult(getDirectValueFromBuffer(state, indexedPosition), true, true, false); \ - } \ - return get(state, ObjectPropertyName(state, property), receiver); \ - } \ - \ - Value TYPE##ArrayObject::getIndexedPropertyValue(ExecutionState& state, const Value& property, const Value& receiver) \ - { \ - if (LIKELY(property.isUInt32() && (size_t)property.asUInt32() < arrayLength())) { \ - if (UNLIKELY(buffer()->isDetachedBuffer())) { \ - return Value(); \ - } \ - size_t indexedPosition = property.asUInt32() * siz; \ - return getDirectValueFromBuffer(state, indexedPosition); \ - } \ - return get(state, ObjectPropertyName(state, property), receiver).value(state, receiver); \ - } \ - \ - bool TYPE##ArrayObject::setIndexedProperty(ExecutionState& state, const Value& property, const Value& value, const Value& receiver) \ - { \ - if (LIKELY(property.isUInt32() && (size_t)property.asUInt32() < arrayLength() && !buffer()->isDetachedBuffer())) { \ - size_t indexedPosition = property.asUInt32() * siz; \ - setDirectValueInBuffer(state, indexedPosition, value); \ - return true; \ - } \ - return set(state, ObjectPropertyName(state, property), value, receiver); \ +#define DECLARE_TYPEDARRAY(TYPE, type, siz, nativeType) \ + TypedArrayObject* TYPE##ArrayObject::allocateTypedArray(ExecutionState& state, Object* newTarget, size_t length) \ + { \ + ASSERT(!!newTarget); \ + Object* proto = Object::getPrototypeFromConstructor(state, newTarget, [](ExecutionState& state, Context* constructorRealm) -> Object* { \ + return constructorRealm->globalObject()->type##ArrayPrototype(); \ + }); \ + TypedArrayObject* obj = new TYPE##ArrayObject(state, proto); \ + if (length == std::numeric_limits::max()) { \ + obj->setBuffer(nullptr, 0, 0, 0); \ + } else { \ + auto buffer = ArrayBufferObject::allocateArrayBuffer(state, state.context()->globalObject()->arrayBuffer(), length * siz); \ + obj->setBuffer(buffer, 0, length* siz, length); \ + } \ + return obj; \ + } \ + \ + template \ + Value TYPE##ArrayObject::getDirectValueFromBuffer(ExecutionState& state, size_t byteindex) \ + { \ + typedef typename TYPE##Adaptor::Type Type; \ + ASSERT(byteLength()); \ + size_t elementSize = sizeof(Type); \ + ASSERT(byteindex + elementSize <= byteLength()); \ + auto bufferAddress = rawBuffer(); \ + if (UNLIKELY(bufferAddress == nullptr)) { \ + return Value(); \ + } \ + uint8_t* rawStart = bufferAddress + byteindex; \ + Type res; \ + if (isLittleEndian) { \ + res = *((Type*)rawStart); \ + } else { \ + for (size_t i = 0; i < elementSize; i++) { \ + ((uint8_t*)&res)[elementSize - i - 1] = rawStart[i]; \ + } \ + } \ + if (std::is_same::value) { \ + return Value(new BigInt((int64_t)res)); \ + } else if (std::is_same::value) { \ + return Value(new BigInt((uint64_t)res)); \ + } else if (std::is_same::value) { \ + return Value((uint8_t)res); \ + } else if (std::is_same::value) { \ + return Value((uint16_t)res); \ + } else if (std::is_same::value) { \ + return Value((uint32_t)res); \ + } else if (std::is_same::value) { \ + return Value((int8_t)res); \ + } else if (std::is_same::value) { \ + return Value((int16_t)res); \ + } else if (std::is_same::value) { \ + return Value((int32_t)res); \ + } \ + return Value(Value::DoubleToIntConvertibleTestNeeds, res); \ + } \ + template \ + void TYPE##ArrayObject::setDirectValueInBuffer(ExecutionState& state, size_t byteindex, const Value& val) \ + { \ + typedef typename TYPE##Adaptor::Type Type; \ + Type littleEndianVal = TYPE##Adaptor::toNative(state, val); \ + ASSERT(byteLength()); \ + size_t elementSize = siz; \ + ASSERT(byteindex + elementSize <= byteLength()); \ + auto bufferAddress = rawBuffer(); \ + uint8_t* rawStart = bufferAddress + byteindex; \ + \ + if (isLittleEndian) { \ + *((Type*)rawStart) = littleEndianVal; \ + } else { \ + for (size_t i = 0; i < elementSize; i++) { \ + rawStart[i] = ((uint8_t*)&littleEndianVal)[elementSize - i - 1]; \ + } \ + } \ + } \ + \ + ObjectGetResult TYPE##ArrayObject::getIndexedProperty(ExecutionState& state, const Value& property, const Value& receiver) \ + { \ + if (LIKELY(property.isUInt32() && (size_t)property.asUInt32() < arrayLength())) { \ + if (UNLIKELY(buffer()->isDetachedBuffer())) { \ + return ObjectGetResult(); \ + } \ + size_t indexedPosition = property.asUInt32() * siz; \ + return ObjectGetResult(getDirectValueFromBuffer(state, indexedPosition), true, true, false); \ + } \ + return get(state, ObjectPropertyName(state, property), receiver); \ + } \ + \ + Value TYPE##ArrayObject::getIndexedPropertyValue(ExecutionState& state, const Value& property, const Value& receiver) \ + { \ + if (LIKELY(property.isUInt32() && (size_t)property.asUInt32() < arrayLength())) { \ + if (UNLIKELY(buffer()->isDetachedBuffer())) { \ + return Value(); \ + } \ + size_t indexedPosition = property.asUInt32() * siz; \ + return getDirectValueFromBuffer(state, indexedPosition); \ + } \ + return get(state, ObjectPropertyName(state, property), receiver).value(state, receiver); \ + } \ + \ + bool TYPE##ArrayObject::setIndexedProperty(ExecutionState& state, const Value& property, const Value& value, const Value& receiver) \ + { \ + if (LIKELY(property.isUInt32() && (size_t)property.asUInt32() < arrayLength() && !buffer()->isDetachedBuffer() && value.isPrimitive())) { \ + size_t indexedPosition = property.asUInt32() * siz; \ + setDirectValueInBuffer(state, indexedPosition, value); \ + return true; \ + } \ + return set(state, ObjectPropertyName(state, property), value, receiver); \ } FOR_EACH_TYPEDARRAY_TYPES(DECLARE_TYPEDARRAY)