diff options
author | Lars Knoll <lars.knoll@qt.io> | 2018-04-04 12:09:12 +0200 |
---|---|---|
committer | Lars Knoll <lars.knoll@qt.io> | 2018-05-02 14:17:33 +0000 |
commit | 0496475831972387fe74733fec6de68c4fcb2c45 (patch) | |
tree | 21b75afbe7b0c1f7259e6e145170cc349f680c2c /src/qml/jsruntime/qv4arrayobject.cpp | |
parent | d5f5f86824437bff8946c83d4369536a6de6f0e7 (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.cpp | 32 |
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); |