aboutsummaryrefslogtreecommitdiffstats
path: root/src/qml/jsruntime/qv4arrayobject.cpp
diff options
context:
space:
mode:
authorLars Knoll <lars.knoll@qt.io>2018-04-04 12:09:12 +0200
committerLars Knoll <lars.knoll@qt.io>2018-05-02 14:17:33 +0000
commit0496475831972387fe74733fec6de68c4fcb2c45 (patch)
tree21b75afbe7b0c1f7259e6e145170cc349f680c2c /src/qml/jsruntime/qv4arrayobject.cpp
parentd5f5f86824437bff8946c83d4369536a6de6f0e7 (diff)
The length of array like objects can in some cases be 2^53 -1 in ES7
Add a Value::getLength(), that converts a Value to a length bound between 0 and 2^53-1 as per ES7 spec. Use the extended range in Array.prototype.splice and map to fix hanging test cases. Change-Id: If9280d501423cfc10a60abd4e8aa30521d2a7bca Reviewed-by: Simon Hausmann <simon.hausmann@qt.io>
Diffstat (limited to 'src/qml/jsruntime/qv4arrayobject.cpp')
-rw-r--r--src/qml/jsruntime/qv4arrayobject.cpp32
1 files changed, 23 insertions, 9 deletions
diff --git a/src/qml/jsruntime/qv4arrayobject.cpp b/src/qml/jsruntime/qv4arrayobject.cpp
index bd019d3bcb..37c386d781 100644
--- a/src/qml/jsruntime/qv4arrayobject.cpp
+++ b/src/qml/jsruntime/qv4arrayobject.cpp
@@ -548,19 +548,31 @@ ReturnedValue ArrayPrototype::method_splice(const FunctionObject *b, const Value
if (!instance)
RETURN_UNDEFINED();
- uint len = instance->getLength();
-
- ScopedArrayObject newArray(scope, scope.engine->newArrayObject());
+ qint64 len = instance->getLength();
double rs = (argc ? argv[0] : Primitive::undefinedValue()).toInteger();
- uint start;
+ qint64 start;
if (rs < 0)
- start = (uint) qMax(0., len + rs);
+ start = static_cast<qint64>(qMax(0., len + rs));
else
- start = (uint) qMin(rs, (double)len);
+ start = static_cast<qint64>(qMin(rs, static_cast<double>(len)));
+
+ qint64 deleteCount = 0;
+ qint64 itemCount = 0;
+ if (argc == 1) {
+ deleteCount = len - start;
+ } else if (argc > 1){
+ itemCount = argc - 2;
+ double dc = argv[1].toInteger();
+ deleteCount = static_cast<qint64>(qMin(qMax(dc, 0.), double(len - start)));
+ }
- uint deleteCount = (uint)qMin(qMax((argc > 1 ? argv[1] : Primitive::undefinedValue()).toInteger(), 0.), (double)(len - start));
+ if (len + itemCount - deleteCount > /*(static_cast<qint64>(1) << 53) - 1*/ UINT_MAX - 1)
+ return scope.engine->throwTypeError();
+ if (deleteCount > /*(static_cast<qint64>(1) << 53) - 1*/ UINT_MAX - 1)
+ return scope.engine->throwRangeError(QString::fromLatin1("Array length out of range."));
+ ScopedArrayObject newArray(scope, scope.engine->newArrayObject());
newArray->arrayReserve(deleteCount);
ScopedValue v(scope);
for (uint i = 0; i < deleteCount; ++i) {
@@ -572,7 +584,6 @@ ReturnedValue ArrayPrototype::method_splice(const FunctionObject *b, const Value
}
newArray->setArrayLengthUnchecked(deleteCount);
- uint itemCount = argc < 2 ? 0 : argc - 2;
if (itemCount < deleteCount) {
for (uint k = start; k < len - deleteCount; ++k) {
@@ -873,12 +884,15 @@ ReturnedValue ArrayPrototype::method_map(const FunctionObject *b, const Value *t
if (!instance)
RETURN_UNDEFINED();
- uint len = instance->getLength();
+ qint64 len = instance->getLength();
if (!argc || !argv->isFunctionObject())
THROW_TYPE_ERROR();
const FunctionObject *callback = static_cast<const FunctionObject *>(argv);
+ if (len > UINT_MAX - 1)
+ return scope.engine->throwRangeError(QString::fromLatin1("Array length out of range."));
+
ScopedArrayObject a(scope, scope.engine->newArrayObject());
a->arrayReserve(len);
a->setArrayLengthUnchecked(len);