aboutsummaryrefslogtreecommitdiffstats
path: root/src/qml/jsruntime/qv4dataview.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/qml/jsruntime/qv4dataview.cpp')
-rw-r--r--src/qml/jsruntime/qv4dataview.cpp168
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