diff options
Diffstat (limited to 'src/qml/jsruntime/qv4dataview.cpp')
-rw-r--r-- | src/qml/jsruntime/qv4dataview.cpp | 168 |
1 files changed, 107 insertions, 61 deletions
diff --git a/src/qml/jsruntime/qv4dataview.cpp b/src/qml/jsruntime/qv4dataview.cpp index d959b1667b..3f0e2fd1a7 100644 --- a/src/qml/jsruntime/qv4dataview.cpp +++ b/src/qml/jsruntime/qv4dataview.cpp @@ -55,38 +55,63 @@ void Heap::DataViewCtor::init(QV4::ExecutionContext *scope) Heap::FunctionObject::init(scope, QStringLiteral("DataView")); } -ReturnedValue DataViewCtor::virtualCallAsConstructor(const FunctionObject *f, const Value *argv, int argc, const Value *) +static uint toIndex(ExecutionEngine *e, const Value &v) +{ + if (v.isUndefined()) + return 0; + double index = v.toInteger(); + if (index < 0) { + e->throwRangeError(QStringLiteral("index out of range")); + return 0; + } + uint idx = static_cast<uint>(index); + if (idx != index) { + e->throwRangeError(QStringLiteral("index out of range")); + return 0; + } + return idx; +} + +ReturnedValue DataViewCtor::virtualCallAsConstructor(const FunctionObject *f, const Value *argv, int argc, const Value *newTarget) { Scope scope(f->engine()); Scoped<ArrayBuffer> buffer(scope, argc ? argv[0] : Primitive::undefinedValue()); - if (!buffer || buffer->isDetachedBuffer()) + if (!newTarget || !buffer) + return scope.engine->throwTypeError(); + + uint offset = ::toIndex(scope.engine, argc > 1 ? argv[1]: Primitive::undefinedValue()); + if (scope.hasException()) + return Encode::undefined(); + if (buffer->isDetachedBuffer()) return scope.engine->throwTypeError(); - double bo = argc > 1 ? argv[1].toNumber() : 0; - uint byteOffset = (uint)bo; uint bufferLength = buffer->d()->data->size; - double bl = argc < 3 || argv[2].isUndefined() ? (bufferLength - bo) : argv[2].toNumber(); - uint byteLength = (uint)bl; - if (bo != byteOffset || bl != byteLength || byteOffset + byteLength > bufferLength) + if (offset > bufferLength) + return scope.engine->throwRangeError(QStringLiteral("DataView: constructor arguments out of range")); + + uint byteLength = (argc < 3 || argv[2].isUndefined()) ? (bufferLength - offset) : ::toIndex(scope.engine, argv[2]); + if (scope.hasException()) + return Encode::undefined(); + if (offset + byteLength > bufferLength) return scope.engine->throwRangeError(QStringLiteral("DataView: constructor arguments out of range")); Scoped<DataView> a(scope, scope.engine->memoryManager->allocate<DataView>()); a->d()->buffer.set(scope.engine, buffer->d()); a->d()->byteLength = byteLength; - a->d()->byteOffset = byteOffset; + a->d()->byteOffset = offset; return a.asReturnedValue(); } -ReturnedValue DataViewCtor::virtualCall(const FunctionObject *f, const Value *, const Value *argv, int argc) +ReturnedValue DataViewCtor::virtualCall(const FunctionObject *f, const Value *, const Value *, int) { - return virtualCallAsConstructor(f, argv, argc, f); + return f->engine()->throwTypeError(); } void DataViewPrototype::init(ExecutionEngine *engine, Object *ctor) { Scope scope(engine); ScopedObject o(scope); - ctor->defineReadonlyConfigurableProperty(engine->id_length(), Primitive::fromInt32(3)); + ctor->defineReadonlyConfigurableProperty(engine->id_length(), Primitive::fromInt32(1)); ctor->defineReadonlyProperty(engine->id_prototype(), (o = this)); defineDefaultProperty(engine->id_constructor(), (o = ctor)); defineAccessorProperty(QStringLiteral("buffer"), method_get_buffer, nullptr); @@ -138,6 +163,9 @@ ReturnedValue DataViewPrototype::method_get_byteLength(const FunctionObject *b, if (!v) return b->engine()->throwTypeError(); + if (v->d()->buffer->isDetachedBuffer()) + return b->engine()->throwTypeError(); + return Encode(v->d()->byteLength); } @@ -147,23 +175,28 @@ ReturnedValue DataViewPrototype::method_get_byteOffset(const FunctionObject *b, if (!v) return b->engine()->throwTypeError(); + if (v->d()->buffer->isDetachedBuffer()) + return b->engine()->throwTypeError(); + return Encode(v->d()->byteOffset); } template <typename T> ReturnedValue DataViewPrototype::method_getChar(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc) { + ExecutionEngine *e = b->engine(); const DataView *v = thisObject->as<DataView>(); - if (!v || argc < 1) - return b->engine()->throwTypeError(); - double l = argv[0].toNumber(); - uint idx = (uint)l; - if (l != idx || idx + sizeof(T) > v->d()->byteLength) - return b->engine()->throwTypeError(); + if (!v) + return e->throwTypeError(); + uint idx = ::toIndex(e, argc ? argv[0] : Primitive::undefinedValue()); + if (e->hasException) + return Encode::undefined(); + if (v->d()->buffer->isDetachedBuffer()) + return e->throwTypeError(); + if (idx + sizeof(T) > v->d()->byteLength) + return e->throwRangeError(QStringLiteral("index out of range")); idx += v->d()->byteOffset; - if (v->d()->buffer->isDetachedBuffer()) - return b->engine()->throwTypeError(); T t = T(v->d()->buffer->data->data()[idx]); return Encode((int)t); @@ -172,19 +205,21 @@ ReturnedValue DataViewPrototype::method_getChar(const FunctionObject *b, const V template <typename T> ReturnedValue DataViewPrototype::method_get(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc) { + ExecutionEngine *e = b->engine(); const DataView *v = thisObject->as<DataView>(); - if (!v || argc < 1) - return b->engine()->throwTypeError(); - double l = argv[0].toNumber(); - uint idx = (uint)l; - if (l != idx || idx + sizeof(T) > v->d()->byteLength) - return b->engine()->throwTypeError(); + if (!v) + return e->throwTypeError(); + uint idx = ::toIndex(e, argc ? argv[0] : Primitive::undefinedValue()); + if (e->hasException) + return Encode::undefined(); + if (v->d()->buffer->isDetachedBuffer()) + return e->throwTypeError(); + if (idx + sizeof(T) > v->d()->byteLength) + return e->throwRangeError(QStringLiteral("index out of range")); idx += v->d()->byteOffset; bool littleEndian = argc < 2 ? false : argv[1].toBoolean(); - if (v->d()->buffer->isDetachedBuffer()) - return b->engine()->throwTypeError(); T t = littleEndian ? qFromLittleEndian<T>((uchar *)v->d()->buffer->data->data() + idx) : qFromBigEndian<T>((uchar *)v->d()->buffer->data->data() + idx); @@ -195,20 +230,21 @@ ReturnedValue DataViewPrototype::method_get(const FunctionObject *b, const Value template <typename T> ReturnedValue DataViewPrototype::method_getFloat(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc) { + ExecutionEngine *e = b->engine(); const DataView *v = thisObject->as<DataView>(); - if (!v || argc < 1) - return b->engine()->throwTypeError(); - double l = argv[0].toNumber(); - uint idx = (uint)l; - if (l != idx || idx + sizeof(T) > v->d()->byteLength) - return b->engine()->throwTypeError(); + if (!v) + return e->throwTypeError(); + uint idx = ::toIndex(e, argc ? argv[0] : Primitive::undefinedValue()); + if (e->hasException) + return Encode::undefined(); + if (v->d()->buffer->isDetachedBuffer()) + return e->throwTypeError(); + if (idx + sizeof(T) > v->d()->byteLength) + return e->throwRangeError(QStringLiteral("index out of range")); idx += v->d()->byteOffset; bool littleEndian = argc < 2 ? false : argv[1].toBoolean(); - if (v->d()->buffer->isDetachedBuffer()) - return b->engine()->throwTypeError(); - if (sizeof(T) == 4) { // float union { @@ -235,19 +271,22 @@ ReturnedValue DataViewPrototype::method_getFloat(const FunctionObject *b, const template <typename T> ReturnedValue DataViewPrototype::method_setChar(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc) { + ExecutionEngine *e = b->engine(); const DataView *v = thisObject->as<DataView>(); - if (!v || argc < 1) - return b->engine()->throwTypeError(); - double l = argv[0].toNumber(); - uint idx = (uint)l; - if (l != idx || idx + sizeof(T) > v->d()->byteLength) - return b->engine()->throwTypeError(); - idx += v->d()->byteOffset; + if (!v) + return e->throwTypeError(); + uint idx = ::toIndex(e, argc ? argv[0] : Primitive::undefinedValue()); + if (e->hasException) + return Encode::undefined(); int val = argc >= 2 ? argv[1].toInt32() : 0; if (v->d()->buffer->isDetachedBuffer()) - return b->engine()->throwTypeError(); + return e->throwTypeError(); + + if (idx + sizeof(T) > v->d()->byteLength) + return e->throwRangeError(QStringLiteral("index out of range")); + idx += v->d()->byteOffset; v->d()->buffer->data->data()[idx] = (char)val; @@ -257,21 +296,24 @@ ReturnedValue DataViewPrototype::method_setChar(const FunctionObject *b, const V template <typename T> ReturnedValue DataViewPrototype::method_set(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc) { + ExecutionEngine *e = b->engine(); const DataView *v = thisObject->as<DataView>(); - if (!v || argc < 1) - return b->engine()->throwTypeError(); - double l = argv[0].toNumber(); - uint idx = (uint)l; - if (l != idx || idx + sizeof(T) > v->d()->byteLength) - return b->engine()->throwTypeError(); - idx += v->d()->byteOffset; + if (!v) + return e->throwTypeError(); + uint idx = ::toIndex(e, argc ? argv[0] : Primitive::undefinedValue()); + if (e->hasException) + return Encode::undefined(); int val = argc >= 2 ? argv[1].toInt32() : 0; - bool littleEndian = argc < 3 ? false : argv[2].toBoolean(); if (v->d()->buffer->isDetachedBuffer()) - return b->engine()->throwTypeError(); + return e->throwTypeError(); + + if (idx + sizeof(T) > v->d()->byteLength) + return e->throwRangeError(QStringLiteral("index out of range")); + idx += v->d()->byteOffset; + if (littleEndian) qToLittleEndian<T>(val, (uchar *)v->d()->buffer->data->data() + idx); @@ -284,19 +326,23 @@ ReturnedValue DataViewPrototype::method_set(const FunctionObject *b, const Value template <typename T> ReturnedValue DataViewPrototype::method_setFloat(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc) { + ExecutionEngine *e = b->engine(); const DataView *v = thisObject->as<DataView>(); - if (!v || argc < 1) - return b->engine()->throwTypeError(); - double l = argv[0].toNumber(); - uint idx = (uint)l; - if (l != idx || idx + sizeof(T) > v->d()->byteLength) - return b->engine()->throwTypeError(); - idx += v->d()->byteOffset; + if (!v) + return e->throwTypeError(); + uint idx = ::toIndex(e, argc ? argv[0] : Primitive::undefinedValue()); + if (e->hasException) + return Encode::undefined(); double val = argc >= 2 ? argv[1].toNumber() : qt_qnan(); bool littleEndian = argc < 3 ? false : argv[2].toBoolean(); + if (v->d()->buffer->isDetachedBuffer()) - return b->engine()->throwTypeError(); + return e->throwTypeError(); + + if (idx + sizeof(T) > v->d()->byteLength) + return e->throwRangeError(QStringLiteral("index out of range")); + idx += v->d()->byteOffset; if (sizeof(T) == 4) { // float |