aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLars Knoll <lars.knoll@qt.io>2018-08-23 12:06:25 +0200
committerSimon Hausmann <simon.hausmann@qt.io>2018-08-23 10:15:51 +0000
commit98528ae780deecc831c115379d8aa90fa9450e44 (patch)
tree60f499fb448fc44daba42484b710989eabc5d15e
parentda9a715a52894501ae7d9292db9b33a237cce4e0 (diff)
Fix some remaining issues with detaching of array buffers
Make sure we check for detached buffers after all other calls that could execute code have happened. To do that convert the values to numbers before calling the write() methods of the specific typed array. Change-Id: I091e41400f740dfc1d0826657e285443c9336c40 Reviewed-by: Simon Hausmann <simon.hausmann@qt.io>
-rw-r--r--src/qml/jsruntime/qv4typedarray.cpp106
-rw-r--r--src/qml/jsruntime/qv4typedarray_p.h2
-rw-r--r--src/qml/jsruntime/qv4value_p.h10
-rw-r--r--tests/auto/qml/ecmascripttests/TestExpectations2
4 files changed, 75 insertions, 45 deletions
diff --git a/src/qml/jsruntime/qv4typedarray.cpp b/src/qml/jsruntime/qv4typedarray.cpp
index c52526d686..54c3b9cfc1 100644
--- a/src/qml/jsruntime/qv4typedarray.cpp
+++ b/src/qml/jsruntime/qv4typedarray.cpp
@@ -57,16 +57,31 @@ DEFINE_OBJECT_VTABLE(TypedArray);
Q_STATIC_ASSERT((int)ExecutionEngine::NTypedArrayTypes == (int)Heap::TypedArray::NTypes);
+static inline int toInt32(Value v)
+{
+ Q_ASSERT(v.isNumber());
+ if (v.isInteger())
+ return v.integerValue();
+ return Double::toInt32(v.doubleValue());
+}
+
+static inline double toDouble(Value v)
+{
+ Q_ASSERT(v.isNumber());
+ if (v.isInteger())
+ return v.integerValue();
+ return v.doubleValue();
+}
+
ReturnedValue Int8ArrayRead(const char *data, int index)
{
return Encode((int)(signed char)data[index]);
}
-void Int8ArrayWrite(ExecutionEngine *e, char *data, int index, const Value &value)
+void Int8ArrayWrite(char *data, int index, const Value &value)
{
- signed char v = (signed char)value.toUInt32();
- if (e->hasException)
- return;
+ int n = toInt32(value);
+ signed char v = static_cast<signed char>(n);
data[index] = v;
}
@@ -75,23 +90,22 @@ ReturnedValue UInt8ArrayRead(const char *data, int index)
return Encode((int)(unsigned char)data[index]);
}
-void UInt8ArrayWrite(ExecutionEngine *e, char *data, int index, const Value &value)
+void UInt8ArrayWrite(char *data, int index, const Value &value)
{
- unsigned char v = (unsigned char)value.toUInt32();
- if (e->hasException)
- return;
+ int n = toInt32(value);
+ unsigned char v = static_cast<unsigned char>(uint(n));
data[index] = v;
}
-void UInt8ClampedArrayWrite(ExecutionEngine *e, char *data, int index, const Value &value)
+void UInt8ClampedArrayWrite(char *data, int index, const Value &value)
{
+ Q_ASSERT(value.isNumber());
if (value.isInteger()) {
data[index] = (char)(unsigned char)qBound(0, value.integerValue(), 255);
return;
}
- double d = value.toNumber();
- if (e->hasException)
- return;
+ Q_ASSERT(value.isDouble());
+ double d = value.doubleValue();
// ### is there a way to optimise this?
if (d <= 0 || std::isnan(d)) {
data[index] = 0;
@@ -123,11 +137,10 @@ ReturnedValue Int16ArrayRead(const char *data, int index)
return Encode((int)*(const short *)(data + index));
}
-void Int16ArrayWrite(ExecutionEngine *e, char *data, int index, const Value &value)
+void Int16ArrayWrite(char *data, int index, const Value &value)
{
- short v = (short)value.toInt32();
- if (e->hasException)
- return;
+ int n = toInt32(value);
+ short v = static_cast<short>(n);
*(short *)(data + index) = v;
}
@@ -136,11 +149,10 @@ ReturnedValue UInt16ArrayRead(const char *data, int index)
return Encode((int)*(const unsigned short *)(data + index));
}
-void UInt16ArrayWrite(ExecutionEngine *e, char *data, int index, const Value &value)
+void UInt16ArrayWrite(char *data, int index, const Value &value)
{
- unsigned short v = (unsigned short)value.toInt32();
- if (e->hasException)
- return;
+ int n = toInt32(value);
+ unsigned short v = static_cast<unsigned short>(n);
*(unsigned short *)(data + index) = v;
}
@@ -149,11 +161,9 @@ ReturnedValue Int32ArrayRead(const char *data, int index)
return Encode(*(const int *)(data + index));
}
-void Int32ArrayWrite(ExecutionEngine *e, char *data, int index, const Value &value)
+void Int32ArrayWrite(char *data, int index, const Value &value)
{
- int v = (int)value.toInt32();
- if (e->hasException)
- return;
+ int v = toInt32(value);
*(int *)(data + index) = v;
}
@@ -162,11 +172,10 @@ ReturnedValue UInt32ArrayRead(const char *data, int index)
return Encode(*(const unsigned int *)(data + index));
}
-void UInt32ArrayWrite(ExecutionEngine *e, char *data, int index, const Value &value)
+void UInt32ArrayWrite(char *data, int index, const Value &value)
{
- unsigned int v = (unsigned int)value.toUInt32();
- if (e->hasException)
- return;
+ int n = toInt32(value);
+ unsigned v = static_cast<unsigned>(n);
*(unsigned int *)(data + index) = v;
}
@@ -175,11 +184,9 @@ ReturnedValue Float32ArrayRead(const char *data, int index)
return Encode(*(const float *)(data + index));
}
-void Float32ArrayWrite(ExecutionEngine *e, char *data, int index, const Value &value)
+void Float32ArrayWrite(char *data, int index, const Value &value)
{
- float v = value.toNumber();
- if (e->hasException)
- return;
+ float v = toDouble(value);
*(float *)(data + index) = v;
}
@@ -188,11 +195,9 @@ ReturnedValue Float64ArrayRead(const char *data, int index)
return Encode(*(const double *)(data + index));
}
-void Float64ArrayWrite(ExecutionEngine *e, char *data, int index, const Value &value)
+void Float64ArrayWrite(char *data, int index, const Value &value)
{
- double v = value.toNumber();
- if (e->hasException)
- return;
+ double v = toDouble(value);
*(double *)(data + index) = v;
}
@@ -277,7 +282,7 @@ ReturnedValue TypedArrayCtor::virtualCallAsConstructor(const FunctionObject *f,
for (uint i = 0; i < l; ++i) {
Primitive val;
val.setRawValue(read(src, i*srcElementSize));
- write(scope.engine, dest, i*destElementSize, val);
+ write(dest, i*destElementSize, val);
}
}
@@ -346,7 +351,10 @@ ReturnedValue TypedArrayCtor::virtualCallAsConstructor(const FunctionObject *f,
ScopedValue val(scope);
while (idx < l) {
val = o->get(idx);
- array->d()->type->write(scope.engine, b, 0, val);
+ val = val->convertedToNumber();
+ if (scope.engine->hasException)
+ return Encode::undefined();
+ array->d()->type->write(b, 0, val);
if (scope.engine->hasException)
return Encode::undefined();
++idx;
@@ -384,6 +392,8 @@ ReturnedValue TypedArray::virtualGet(const Managed *m, PropertyKey id, const Val
uint index = id.asArrayIndex();
Scope scope(static_cast<const Object *>(m)->engine());
Scoped<TypedArray> a(scope, static_cast<const TypedArray *>(m));
+ if (a->d()->buffer->isDetachedBuffer())
+ return scope.engine->throwTypeError();
uint bytesPerElement = a->d()->type->bytesPerElement;
uint byteOffset = a->d()->byteOffset + index * bytesPerElement;
@@ -409,13 +419,18 @@ bool TypedArray::virtualPut(Managed *m, PropertyKey id, const Value &value, Valu
Scope scope(v4);
Scoped<TypedArray> a(scope, static_cast<TypedArray *>(m));
+ if (a->d()->buffer->isDetachedBuffer())
+ return scope.engine->throwTypeError();
uint bytesPerElement = a->d()->type->bytesPerElement;
uint byteOffset = a->d()->byteOffset + index * bytesPerElement;
if (byteOffset + bytesPerElement > (uint)a->d()->buffer->byteLength())
return false;
- a->d()->type->write(scope.engine, a->d()->buffer->data->data(), byteOffset, value);
+ Value v = Primitive::fromReturnedValue(value.convertedToNumber());
+ if (scope.hasException() || a->d()->buffer->isDetachedBuffer())
+ return scope.engine->throwTypeError();
+ a->d()->type->write(a->d()->buffer->data->data(), byteOffset, v);
return true;
}
@@ -612,13 +627,15 @@ ReturnedValue IntrinsicTypedArrayPrototype::method_fill(const FunctionObject *b,
double val = argc ? argv[0].toNumber() : std::numeric_limits<double>::quiet_NaN();
Value value = Primitive::fromDouble(val);
+ if (scope.hasException() || v->d()->buffer->isDetachedBuffer())
+ return scope.engine->throwTypeError();
char *data = v->d()->buffer->data->data();
uint bytesPerElement = v->d()->type->bytesPerElement;
uint byteOffset = v->d()->byteOffset;
while (k < fin) {
- v->d()->type->write(scope.engine, data, byteOffset + k * bytesPerElement, value);
+ v->d()->type->write(data, byteOffset + k * bytesPerElement, value);
k++;
}
@@ -1237,7 +1254,12 @@ ReturnedValue IntrinsicTypedArrayPrototype::method_set(const FunctionObject *b,
ScopedValue val(scope);
while (idx < l) {
val = o->get(idx);
- a->d()->type->write(scope.engine, b, 0, val);
+ if (scope.hasException())
+ return Encode::undefined();
+ val = val->convertedToNumber();
+ if (scope.hasException() || buffer->isDetachedBuffer())
+ return scope.engine->throwTypeError();
+ a->d()->type->write(b, 0, val);
if (scope.engine->hasException)
RETURN_UNDEFINED();
++idx;
@@ -1278,7 +1300,7 @@ ReturnedValue IntrinsicTypedArrayPrototype::method_set(const FunctionObject *b,
for (uint i = 0; i < l; ++i) {
Primitive val;
val.setRawValue(read(src, i*srcElementSize));
- write(scope.engine, dest, i*elementSize, val);
+ write(dest, i*elementSize, val);
}
if (srcCopy)
diff --git a/src/qml/jsruntime/qv4typedarray_p.h b/src/qml/jsruntime/qv4typedarray_p.h
index 31698fa6d0..775ba61ddc 100644
--- a/src/qml/jsruntime/qv4typedarray_p.h
+++ b/src/qml/jsruntime/qv4typedarray_p.h
@@ -61,7 +61,7 @@ namespace QV4 {
struct ArrayBuffer;
typedef ReturnedValue (*TypedArrayRead)(const char *data, int index);
-typedef void (*TypedArrayWrite)(ExecutionEngine *engine, char *data, int index, const Value &value);
+typedef void (*TypedArrayWrite)(char *data, int index, const Value &value);
struct TypedArrayOperations {
int bytesPerElement;
diff --git a/src/qml/jsruntime/qv4value_p.h b/src/qml/jsruntime/qv4value_p.h
index 6a6df3eb6d..e4be6b99dd 100644
--- a/src/qml/jsruntime/qv4value_p.h
+++ b/src/qml/jsruntime/qv4value_p.h
@@ -408,6 +408,7 @@ public:
}
static bool toBooleanImpl(Value val);
double toInteger() const;
+ inline ReturnedValue convertedToNumber() const;
inline double toNumber() const;
static double toNumberImpl(Value v);
double toNumberImpl() const { return toNumberImpl(*this); }
@@ -554,6 +555,15 @@ inline double Value::toNumber() const
return toNumberImpl();
}
+inline ReturnedValue Value::convertedToNumber() const
+{
+ if (isInteger() || isDouble())
+ return asReturnedValue();
+ Value v;
+ v.setDouble(toNumberImpl());
+ return v.asReturnedValue();
+}
+
inline
ReturnedValue Heap::Base::asReturnedValue() const
{
diff --git a/tests/auto/qml/ecmascripttests/TestExpectations b/tests/auto/qml/ecmascripttests/TestExpectations
index de21ad7fad..3d79b87652 100644
--- a/tests/auto/qml/ecmascripttests/TestExpectations
+++ b/tests/auto/qml/ecmascripttests/TestExpectations
@@ -683,7 +683,6 @@ built-ins/TypedArray/from/name.js fails
built-ins/TypedArray/from/prop-desc.js fails
built-ins/TypedArray/prototype/constructor.js fails
built-ins/TypedArray/prototype/fill/fill-values-conversion-operations-consistent-nan.js fails
-built-ins/TypedArray/prototype/set/array-arg-targetbuffer-detached-on-get-src-value-throws.js fails
built-ins/TypedArray/prototype/slice/bit-precision.js fails
built-ins/TypedArray/prototype/sort/arraylength-internal.js fails
built-ins/TypedArray/prototype/sort/comparefn-call-throws.js fails
@@ -790,7 +789,6 @@ built-ins/TypedArrays/internals/Set/detached-buffer.js fails
built-ins/TypedArrays/internals/Set/key-is-minus-zero.js fails
built-ins/TypedArrays/internals/Set/key-is-not-integer.js fails
built-ins/TypedArrays/internals/Set/key-is-out-of-bounds.js fails
-built-ins/TypedArrays/internals/Set/tonumber-value-detached-buffer.js fails
built-ins/TypedArrays/internals/Set/tonumber-value-throws.js strictFails
built-ins/WeakMap/constructor.js fails
built-ins/WeakMap/empty-iterable.js fails