Warning, /graphics/krita/3rdparty/ext_qt/0122-Don-t-use-UINT_MAX-as-invalid-array-index-in-PropertyKey.patch is written in an unsupported language. File is not indexed.
0001 From 68b7a66a6e4d673d11aab44cb87b3f005cdff8ea Mon Sep 17 00:00:00 2001 0002 From: Ulf Hermann <ulf.hermann@qt.io> 0003 Date: Fri, 29 Mar 2019 09:24:27 +0100 0004 Subject: [PATCH] Don't use UINT_MAX as invalid array index in PropertyKey 0005 0006 Technically UINT_MAX is actually a valid array index, although that is 0007 an academic problem right now. However, we do have a method 0008 isArrayIndex() and should just use that to determine if a PropertyKey is 0009 an array index. 0010 0011 Fixes: QTBUG-73893 0012 Change-Id: I302e7894331ed2ab4717f7d8d6cc7d8974dabb4e 0013 Reviewed-by: Erik Verbruggen <erik.verbruggen@qt.io> 0014 --- 0015 src/qml/jsruntime/qv4argumentsobject.cpp | 58 ++++++++++++++---------- 0016 src/qml/jsruntime/qv4engine.cpp | 5 +- 0017 src/qml/jsruntime/qv4identifiertable.cpp | 5 +- 0018 src/qml/jsruntime/qv4object.cpp | 18 +++----- 0019 src/qml/jsruntime/qv4propertykey_p.h | 4 +- 0020 src/qml/jsruntime/qv4stringobject.cpp | 15 +++--- 0021 src/qml/jsruntime/qv4typedarray.cpp | 40 ++++++++-------- 0022 7 files changed, 75 insertions(+), 70 deletions(-) 0023 0024 diff --git a/src/qml/jsruntime/qv4argumentsobject.cpp b/src/qml/jsruntime/qv4argumentsobject.cpp 0025 index 4a21f62cf2..98e0ef9e70 100644 0026 --- a/src/qml/jsruntime/qv4argumentsobject.cpp 0027 +++ b/src/qml/jsruntime/qv4argumentsobject.cpp 0028 @@ -116,6 +116,9 @@ bool ArgumentsObject::virtualDefineOwnProperty(Managed *m, PropertyKey id, const 0029 { 0030 ArgumentsObject *args = static_cast<ArgumentsObject *>(m); 0031 args->fullyCreate(); 0032 + if (!id.isArrayIndex()) 0033 + return Object::virtualDefineOwnProperty(m, id, desc, attrs); 0034 + 0035 uint index = id.asArrayIndex(); 0036 0037 if (!args->isMapped(index)) 0038 @@ -148,36 +151,42 @@ bool ArgumentsObject::virtualDefineOwnProperty(Managed *m, PropertyKey id, const 0039 0040 ReturnedValue ArgumentsObject::virtualGet(const Managed *m, PropertyKey id, const Value *receiver, bool *hasProperty) 0041 { 0042 - const ArgumentsObject *args = static_cast<const ArgumentsObject *>(m); 0043 - uint index = id.asArrayIndex(); 0044 - if (index < args->d()->argCount && !args->d()->fullyCreated) { 0045 - if (hasProperty) 0046 - *hasProperty = true; 0047 - return args->context()->args()[index].asReturnedValue(); 0048 + if (id.isArrayIndex()) { 0049 + const ArgumentsObject *args = static_cast<const ArgumentsObject *>(m); 0050 + uint index = id.asArrayIndex(); 0051 + if (index < args->d()->argCount && !args->d()->fullyCreated) { 0052 + if (hasProperty) 0053 + *hasProperty = true; 0054 + return args->context()->args()[index].asReturnedValue(); 0055 + } 0056 + 0057 + if (args->isMapped(index)) { 0058 + Q_ASSERT(index < static_cast<uint>(args->context()->function->formalParameterCount())); 0059 + if (hasProperty) 0060 + *hasProperty = true; 0061 + return args->context()->args()[index].asReturnedValue(); 0062 + } 0063 } 0064 0065 - if (!args->isMapped(index)) 0066 - return Object::virtualGet(m, id, receiver, hasProperty); 0067 - Q_ASSERT(index < static_cast<uint>(args->context()->function->formalParameterCount())); 0068 - if (hasProperty) 0069 - *hasProperty = true; 0070 - return args->context()->args()[index].asReturnedValue(); 0071 + return Object::virtualGet(m, id, receiver, hasProperty); 0072 } 0073 0074 bool ArgumentsObject::virtualPut(Managed *m, PropertyKey id, const Value &value, Value *receiver) 0075 { 0076 - ArgumentsObject *args = static_cast<ArgumentsObject *>(m); 0077 - uint index = id.asArrayIndex(); 0078 - 0079 - if (args == receiver && index < args->d()->argCount && !args->d()->fullyCreated) { 0080 - args->context()->setArg(index, value); 0081 - return true; 0082 + if (id.isArrayIndex()) { 0083 + ArgumentsObject *args = static_cast<ArgumentsObject *>(m); 0084 + uint index = id.asArrayIndex(); 0085 + 0086 + if (args == receiver && index < args->d()->argCount && !args->d()->fullyCreated) { 0087 + args->context()->setArg(index, value); 0088 + return true; 0089 + } 0090 + 0091 + bool isMapped = (args == receiver && args->isMapped(index)); 0092 + if (isMapped) 0093 + args->context()->setArg(index, value); 0094 } 0095 0096 - bool isMapped = (args == receiver && args->isMapped(index)); 0097 - if (isMapped) 0098 - args->context()->setArg(index, value); 0099 - 0100 return Object::virtualPut(m, id, value, receiver); 0101 } 0102 0103 @@ -186,13 +195,16 @@ bool ArgumentsObject::virtualDeleteProperty(Managed *m, PropertyKey id) 0104 ArgumentsObject *args = static_cast<ArgumentsObject *>(m); 0105 args->fullyCreate(); 0106 bool result = Object::virtualDeleteProperty(m, id); 0107 - if (result) 0108 + if (result && id.isArrayIndex()) 0109 args->removeMapping(id.asArrayIndex()); 0110 return result; 0111 } 0112 0113 PropertyAttributes ArgumentsObject::virtualGetOwnProperty(const Managed *m, PropertyKey id, Property *p) 0114 { 0115 + if (!id.isArrayIndex()) 0116 + return Object::virtualGetOwnProperty(m, id, p); 0117 + 0118 const ArgumentsObject *args = static_cast<const ArgumentsObject *>(m); 0119 uint index = id.asArrayIndex(); 0120 if (index < args->d()->argCount && !args->d()->fullyCreated) { 0121 diff --git a/src/qml/jsruntime/qv4engine.cpp b/src/qml/jsruntime/qv4engine.cpp 0122 index ab980e99df..5bc81de472 100644 0123 --- a/src/qml/jsruntime/qv4engine.cpp 0124 +++ b/src/qml/jsruntime/qv4engine.cpp 0125 @@ -1659,9 +1659,8 @@ static QV4::ReturnedValue variantMapToJS(QV4::ExecutionEngine *v4, const QVarian 0126 s = v4->newIdentifier(it.key()); 0127 key = s->propertyKey(); 0128 v = variantToJS(v4, it.value()); 0129 - uint idx = key->asArrayIndex(); 0130 - if (idx < UINT_MAX) 0131 - o->arraySet(idx, v); 0132 + if (key->isArrayIndex()) 0133 + o->arraySet(key->asArrayIndex(), v); 0134 else 0135 o->insertMember(s, v); 0136 } 0137 diff --git a/src/qml/jsruntime/qv4identifiertable.cpp b/src/qml/jsruntime/qv4identifiertable.cpp 0138 index e476baa886..102c06d9b0 100644 0139 --- a/src/qml/jsruntime/qv4identifiertable.cpp 0140 +++ b/src/qml/jsruntime/qv4identifiertable.cpp 0141 @@ -216,9 +216,8 @@ PropertyKey IdentifierTable::asPropertyKeyImpl(const Heap::String *str) 0142 0143 Heap::StringOrSymbol *IdentifierTable::resolveId(PropertyKey i) const 0144 { 0145 - uint arrayIdx = i.asArrayIndex(); 0146 - if (arrayIdx < UINT_MAX) 0147 - return engine->newString(QString::number(arrayIdx)); 0148 + if (i.isArrayIndex()) 0149 + return engine->newString(QString::number(i.asArrayIndex())); 0150 if (!i.isValid()) 0151 return nullptr; 0152 0153 diff --git a/src/qml/jsruntime/qv4object.cpp b/src/qml/jsruntime/qv4object.cpp 0154 index efab9a6454..206b410cf4 100644 0155 --- a/src/qml/jsruntime/qv4object.cpp 0156 +++ b/src/qml/jsruntime/qv4object.cpp 0157 @@ -406,8 +406,8 @@ ReturnedValue Object::internalGet(PropertyKey id, const Value *receiver, bool *h 0158 { 0159 Heap::Object *o = d(); 0160 0161 - uint index = id.asArrayIndex(); 0162 - if (index != UINT_MAX) { 0163 + if (id.isArrayIndex()) { 0164 + const uint index = id.asArrayIndex(); 0165 Scope scope(this); 0166 PropertyAttributes attrs; 0167 ScopedProperty pd(scope); 0168 @@ -431,8 +431,6 @@ ReturnedValue Object::internalGet(PropertyKey id, const Value *receiver, bool *h 0169 break; 0170 } 0171 } else { 0172 - Q_ASSERT(!id.isArrayIndex()); 0173 - 0174 while (1) { 0175 auto idx = o->internalClass->findValueOrGetter(id); 0176 if (idx.isValid()) { 0177 @@ -470,14 +468,13 @@ bool Object::internalPut(PropertyKey id, const Value &value, Value *receiver) 0178 if (d()->internalClass->vtable->getOwnProperty == Object::virtualGetOwnProperty) { 0179 // This object standard methods in the vtable, so we can take a shortcut 0180 // and avoid the calls to getOwnProperty and defineOwnProperty 0181 - uint index = id.asArrayIndex(); 0182 0183 PropertyAttributes attrs; 0184 PropertyIndex propertyIndex{nullptr, nullptr}; 0185 0186 - if (index != UINT_MAX) { 0187 + if (id.isArrayIndex()) { 0188 if (arrayData()) 0189 - propertyIndex = arrayData()->getValueOrSetter(index, &attrs); 0190 + propertyIndex = arrayData()->getValueOrSetter(id.asArrayIndex(), &attrs); 0191 } else { 0192 auto member = internalClass()->findValueOrSetter(id); 0193 if (member.isValid()) { 0194 @@ -546,12 +543,11 @@ bool Object::internalPut(PropertyKey id, const Value &value, Value *receiver) 0195 0196 if (r->internalClass()->vtable->defineOwnProperty == virtualDefineOwnProperty) { 0197 // standard object, we can avoid some more checks 0198 - uint index = id.asArrayIndex(); 0199 - if (index == UINT_MAX) { 0200 + if (id.isArrayIndex()) { 0201 + r->arraySet(id.asArrayIndex(), value); 0202 + } else { 0203 ScopedStringOrSymbol s(scope, id.asStringOrSymbol()); 0204 r->insertMember(s, value); 0205 - } else { 0206 - r->arraySet(index, value); 0207 } 0208 return true; 0209 } 0210 diff --git a/src/qml/jsruntime/qv4propertykey_p.h b/src/qml/jsruntime/qv4propertykey_p.h 0211 index 47867765db..523afd4ccf 100644 0212 --- a/src/qml/jsruntime/qv4propertykey_p.h 0213 +++ b/src/qml/jsruntime/qv4propertykey_p.h 0214 @@ -113,8 +113,8 @@ public: 0215 static PropertyKey invalid() { PropertyKey key; key.val = 0; return key; } 0216 static PropertyKey fromArrayIndex(uint idx) { PropertyKey key; key.val = ArrayIndexMask | static_cast<quint64>(idx); return key; } 0217 bool isStringOrSymbol() const { return isManaged() && val != 0; } 0218 - uint asArrayIndex() const { return (isManaged() || val == 0) ? std::numeric_limits<uint>::max() : static_cast<uint>(val & 0xffffffff); } 0219 - uint isArrayIndex() const { return !isManaged() && val != 0 && static_cast<uint>(val & 0xffffffff) != std::numeric_limits<uint>::max(); } 0220 + uint asArrayIndex() const { Q_ASSERT(isArrayIndex()); return static_cast<uint>(val & 0xffffffff); } 0221 + uint isArrayIndex() const { return !isManaged() && val != 0; } 0222 bool isValid() const { return val != 0; } 0223 static PropertyKey fromStringOrSymbol(Heap::StringOrSymbol *b) 0224 { PropertyKey key; key.setM(b); return key; } 0225 diff --git a/src/qml/jsruntime/qv4stringobject.cpp b/src/qml/jsruntime/qv4stringobject.cpp 0226 index dee6a67792..1c6dfe0fdb 100644 0227 --- a/src/qml/jsruntime/qv4stringobject.cpp 0228 +++ b/src/qml/jsruntime/qv4stringobject.cpp 0229 @@ -152,13 +152,14 @@ PropertyAttributes StringObject::virtualGetOwnProperty(const Managed *m, Propert 0230 if (attributes != Attr_Invalid) 0231 return attributes; 0232 0233 - const StringObject *s = static_cast<const StringObject *>(m); 0234 - uint slen = s->d()->string->toQString().length(); 0235 - uint index = id.asArrayIndex(); 0236 - if (index < slen) { 0237 - if (p) 0238 - p->value = s->getIndex(index); 0239 - return Attr_NotConfigurable|Attr_NotWritable; 0240 + if (id.isArrayIndex()) { 0241 + const uint index = id.asArrayIndex(); 0242 + const auto s = static_cast<const StringObject *>(m); 0243 + if (index < uint(s->d()->string->toQString().length())) { 0244 + if (p) 0245 + p->value = s->getIndex(index); 0246 + return Attr_NotConfigurable|Attr_NotWritable; 0247 + } 0248 } 0249 return Object::virtualGetOwnProperty(m, id, p); 0250 } 0251 diff --git a/src/qml/jsruntime/qv4typedarray.cpp b/src/qml/jsruntime/qv4typedarray.cpp 0252 index d83f021450..43e1dabb6d 100644 0253 --- a/src/qml/jsruntime/qv4typedarray.cpp 0254 +++ b/src/qml/jsruntime/qv4typedarray.cpp 0255 @@ -459,24 +459,23 @@ Heap::TypedArray *TypedArray::create(ExecutionEngine *e, Heap::TypedArray::Type 0256 0257 ReturnedValue TypedArray::virtualGet(const Managed *m, PropertyKey id, const Value *receiver, bool *hasProperty) 0258 { 0259 - uint index = id.asArrayIndex(); 0260 - if (index == UINT_MAX && !id.isCanonicalNumericIndexString()) 0261 + const bool isArrayIndex = id.isArrayIndex(); 0262 + if (!isArrayIndex && !id.isCanonicalNumericIndexString()) 0263 return Object::virtualGet(m, id, receiver, hasProperty); 0264 - // fall through, with index == UINT_MAX it'll do the right thing. 0265 0266 Scope scope(static_cast<const Object *>(m)->engine()); 0267 Scoped<TypedArray> a(scope, static_cast<const TypedArray *>(m)); 0268 if (a->d()->buffer->isDetachedBuffer()) 0269 return scope.engine->throwTypeError(); 0270 0271 - if (index >= a->length()) { 0272 + if (!isArrayIndex || id.asArrayIndex() >= a->length()) { 0273 if (hasProperty) 0274 *hasProperty = false; 0275 return Encode::undefined(); 0276 } 0277 0278 uint bytesPerElement = a->d()->type->bytesPerElement; 0279 - uint byteOffset = a->d()->byteOffset + index * bytesPerElement; 0280 + uint byteOffset = a->d()->byteOffset + id.asArrayIndex() * bytesPerElement; 0281 Q_ASSERT(byteOffset + bytesPerElement <= (uint)a->d()->buffer->byteLength()); 0282 0283 if (hasProperty) 0284 @@ -486,27 +485,22 @@ ReturnedValue TypedArray::virtualGet(const Managed *m, PropertyKey id, const Val 0285 0286 bool TypedArray::virtualHasProperty(const Managed *m, PropertyKey id) 0287 { 0288 - uint index = id.asArrayIndex(); 0289 - if (index == UINT_MAX && !id.isCanonicalNumericIndexString()) 0290 + const bool isArrayIndex = id.isArrayIndex(); 0291 + if (!isArrayIndex && !id.isCanonicalNumericIndexString()) 0292 return Object::virtualHasProperty(m, id); 0293 - // fall through, with index == UINT_MAX it'll do the right thing. 0294 0295 const TypedArray *a = static_cast<const TypedArray *>(m); 0296 if (a->d()->buffer->isDetachedBuffer()) { 0297 a->engine()->throwTypeError(); 0298 return false; 0299 } 0300 - if (index >= a->length()) 0301 - return false; 0302 - return true; 0303 + return isArrayIndex && id.asArrayIndex() < a->length(); 0304 } 0305 0306 PropertyAttributes TypedArray::virtualGetOwnProperty(const Managed *m, PropertyKey id, Property *p) 0307 { 0308 - uint index = id.asArrayIndex(); 0309 - if (index == UINT_MAX && !id.isCanonicalNumericIndexString()) 0310 + if (!id.isArrayIndex() && !id.isCanonicalNumericIndexString()) 0311 return Object::virtualGetOwnProperty(m, id, p); 0312 - // fall through, with index == UINT_MAX it'll do the right thing. 0313 0314 bool hasProperty = false; 0315 ReturnedValue v = virtualGet(m, id, m, &hasProperty); 0316 @@ -517,10 +511,9 @@ PropertyAttributes TypedArray::virtualGetOwnProperty(const Managed *m, PropertyK 0317 0318 bool TypedArray::virtualPut(Managed *m, PropertyKey id, const Value &value, Value *receiver) 0319 { 0320 - uint index = id.asArrayIndex(); 0321 - if (index == UINT_MAX && !id.isCanonicalNumericIndexString()) 0322 + const bool isArrayIndex = id.isArrayIndex(); 0323 + if (!isArrayIndex && !id.isCanonicalNumericIndexString()) 0324 return Object::virtualPut(m, id, value, receiver); 0325 - // fall through, with index == UINT_MAX it'll do the right thing. 0326 0327 ExecutionEngine *v4 = static_cast<Object *>(m)->engine(); 0328 if (v4->hasException) 0329 @@ -531,6 +524,10 @@ bool TypedArray::virtualPut(Managed *m, PropertyKey id, const Value &value, Valu 0330 if (a->d()->buffer->isDetachedBuffer()) 0331 return scope.engine->throwTypeError(); 0332 0333 + if (!isArrayIndex) 0334 + return false; 0335 + 0336 + const uint index = id.asArrayIndex(); 0337 if (index >= a->length()) 0338 return false; 0339 0340 @@ -547,11 +544,12 @@ bool TypedArray::virtualPut(Managed *m, PropertyKey id, const Value &value, Valu 0341 0342 bool TypedArray::virtualDefineOwnProperty(Managed *m, PropertyKey id, const Property *p, PropertyAttributes attrs) 0343 { 0344 - uint index = id.asArrayIndex(); 0345 - if (index == UINT_MAX && !id.isCanonicalNumericIndexString()) 0346 - return Object::virtualDefineOwnProperty(m, id, p, attrs); 0347 - // fall through, with index == UINT_MAX it'll do the right thing. 0348 + if (!id.isArrayIndex()) { 0349 + return !id.isCanonicalNumericIndexString() 0350 + && Object::virtualDefineOwnProperty(m, id, p, attrs); 0351 + } 0352 0353 + const uint index = id.asArrayIndex(); 0354 TypedArray *a = static_cast<TypedArray *>(m); 0355 if (index >= a->length() || attrs.isAccessor()) 0356 return false; 0357 -- 0358 GitLab 0359