File V4-Always-set-the-tag-when-boxing-a-pointer.patch of Package libqt5-qtdeclarative.3900

From aa7c3b35ef9b737c574f436ea35452019a2ff29c Mon Sep 17 00:00:00 2001
From: Erik Verbruggen <erik.verbruggen@digia.com>
Date: Thu, 16 Jun 2016 13:39:57 +0200
Subject: [PATCH 1/1] V4: Always set the tag when boxing a pointer in
 QV4::Value.

All setters now store tags, so no-one can play loosy-goosy with the
boxed values (and accidentally forget to "tag" a value, resulting in
random garbage).

Change-Id: Ia0b78aa038d3ff46d5292b14bd593de310da16a0
Reviewed-by: Simon Hausmann <simon.hausmann@qt.io>
---
 .../qmldbg_debugger/qqmlnativedebugservice.cpp     |  2 +-
 src/qml/jsruntime/qv4arraydata.cpp                 | 10 +--
 src/qml/jsruntime/qv4objectiterator.cpp            |  5 --
 src/qml/jsruntime/qv4persistent.cpp                |  9 +--
 src/qml/jsruntime/qv4scopedvalue_p.h               | 16 +---
 src/qml/jsruntime/qv4value_p.h                     | 94 ++++++++++++----------
 6 files changed, 63 insertions(+), 73 deletions(-)

Index: qtdeclarative-opensource-src-5.6.1/src/plugins/qmltooling/qmldbg_debugger/qqmlnativedebugservice.cpp
===================================================================
--- qtdeclarative-opensource-src-5.6.1.orig/src/plugins/qmltooling/qmldbg_debugger/qqmlnativedebugservice.cpp
+++ qtdeclarative-opensource-src-5.6.1/src/plugins/qmltooling/qmldbg_debugger/qqmlnativedebugservice.cpp
@@ -549,7 +549,7 @@ void NativeDebugger::handleExpressions(Q
             dict[QStringLiteral("name")] = name;
             dict[QStringLiteral("valueencoded")] = QStringLiteral("undefined");
             output.append(dict);
-        } else if (result.ptr && result.ptr->_val) {
+        } else if (result.ptr && result.ptr->rawValue()) {
             collector.collect(&output, QString(), name, *result);
         } else {
             QJsonObject dict;
Index: qtdeclarative-opensource-src-5.6.1/src/qml/jsruntime/qv4arraydata.cpp
===================================================================
--- qtdeclarative-opensource-src-5.6.1.orig/src/qml/jsruntime/qv4arraydata.cpp
+++ qtdeclarative-opensource-src-5.6.1/src/qml/jsruntime/qv4arraydata.cpp
@@ -93,8 +93,8 @@ Q_STATIC_ASSERT(sizeof(Heap::ArrayData)
 
 static Q_ALWAYS_INLINE void storeValue(ReturnedValue *target, uint value)
 {
-    Value v = Value::fromReturnedValue(*target);
-    v.setValue(value);
+    Value v;
+    v.setTagValue(Value::fromReturnedValue(*target).tag(), value);
     *target = v.asReturnedValue();
 }
 
@@ -189,7 +189,7 @@ void ArrayData::realloc(Object *o, Type
                 n->value = i;
             } else {
                 storeValue(lastFree, i);
-                sparse->arrayData[i].setTag(Value::Empty_Type);
+                sparse->arrayData[i].setEmpty();
                 lastFree = &sparse->arrayData[i].rawValueRef();
             }
         }
@@ -198,7 +198,7 @@ void ArrayData::realloc(Object *o, Type
     if (toCopy < sparse->alloc) {
         for (uint i = toCopy; i < sparse->alloc; ++i) {
             storeValue(lastFree, i);
-            sparse->arrayData[i].setTag(Value::Empty_Type);
+            sparse->arrayData[i].setEmpty();
             lastFree = &sparse->arrayData[i].rawValueRef();
         }
         storeValue(lastFree, UINT_MAX);
@@ -396,7 +396,7 @@ uint SparseArrayData::allocate(Object *o
                 // found two slots in a row
                 uint idx = Value::fromReturnedValue(*last).uint_32();
                 Value lastV = Value::fromReturnedValue(*last);
-                lastV.setValue(dd->arrayData[lastV.value() + 1].value());
+                lastV.setTagValue(lastV.tag(), dd->arrayData[lastV.value() + 1].value());
                 *last = lastV.rawValue();
                 dd->attrs[idx] = Attr_Accessor;
                 return idx;
Index: qtdeclarative-opensource-src-5.6.1/src/qml/jsruntime/qv4objectiterator.cpp
===================================================================
--- qtdeclarative-opensource-src-5.6.1.orig/src/qml/jsruntime/qv4objectiterator.cpp
+++ qtdeclarative-opensource-src-5.6.1/src/qml/jsruntime/qv4objectiterator.cpp
@@ -68,11 +68,6 @@ void ObjectIterator::init(const Object *
     object->setM(o ? o->m() : 0);
     current->setM(o ? o->m() : 0);
 
-#ifndef QV4_USE_64_BIT_VALUE_ENCODING
-    object->setTag(QV4::Value::Managed_Type);
-    current->setTag(QV4::Value::Managed_Type);
-#endif
-
     if (object->as<ArgumentsObject>()) {
         Scope scope(engine);
         Scoped<ArgumentsObject> (scope, object->asReturnedValue())->fullyCreate();
Index: qtdeclarative-opensource-src-5.6.1/src/qml/jsruntime/qv4persistent.cpp
===================================================================
--- qtdeclarative-opensource-src-5.6.1.orig/src/qml/jsruntime/qv4persistent.cpp
+++ qtdeclarative-opensource-src-5.6.1/src/qml/jsruntime/qv4persistent.cpp
@@ -79,11 +79,9 @@ Page *allocatePage(PersistentValueStorag
     if (p->header.next)
         p->header.next->header.prev = &p->header.next;
     for (int i = 0; i < kEntriesPerPage - 1; ++i) {
-        p->values[i].setTag(QV4::Value::Empty_Type);
-        p->values[i].setInt_32(i + 1);
+        p->values[i].setEmpty(i + 1);
     }
-    p->values[kEntriesPerPage - 1].setTag(QV4::Value::Empty_Type);
-    p->values[kEntriesPerPage - 1].setInt_32(-1);
+    p->values[kEntriesPerPage - 1].setEmpty(-1);
 
     storage->firstPage = p;
 
@@ -205,8 +203,7 @@ void PersistentValueStorage::free(Value
 
     Page *p = getPage(v);
 
-    v->setTag(QV4::Value::Empty_Type);
-    v->setInt_32(p->header.freeList);
+    v->setEmpty(p->header.freeList);
     p->header.freeList = v - p->values;
     if (!--p->header.refCount)
         freePage(p);
Index: qtdeclarative-opensource-src-5.6.1/src/qml/jsruntime/qv4scopedvalue_p.h
===================================================================
--- qtdeclarative-opensource-src-5.6.1.orig/src/qml/jsruntime/qv4scopedvalue_p.h
+++ qtdeclarative-opensource-src-5.6.1/src/qml/jsruntime/qv4scopedvalue_p.h
@@ -120,9 +120,6 @@ struct ScopedValue
     {
         ptr = scope.engine->jsStackTop++;
         ptr->setM(o);
-#ifndef QV4_USE_64_BIT_VALUE_ENCODING
-        ptr->setTag(QV4::Value::Managed_Type);
-#endif
     }
 
     ScopedValue(const Scope &scope, Managed *m)
@@ -144,9 +141,6 @@ struct ScopedValue
 
     ScopedValue &operator=(Heap::Base *o) {
         ptr->setM(o);
-#ifndef QV4_USE_64_BIT_VALUE_ENCODING
-        ptr->setTag(QV4::Value::Managed_Type);
-#endif
         return *this;
     }
 
@@ -186,18 +180,12 @@ struct Scoped
 
     inline void setPointer(const Managed *p) {
         ptr->setM(p ? p->m() : 0);
-#ifndef QV4_USE_64_BIT_VALUE_ENCODING
-        ptr->setTag(QV4::Value::Managed_Type);
-#endif
     }
 
     Scoped(const Scope &scope)
     {
         ptr = scope.engine->jsStackTop++;
         ptr->setM(0);
-#ifndef QV4_USE_64_BIT_VALUE_ENCODING
-        ptr->setTag(QV4::Value::Managed_Type);
-#endif
     }
 
     Scoped(const Scope &scope, const Value &v)
@@ -339,14 +327,14 @@ struct ScopedCallData {
 
 inline Value &Value::operator =(const ScopedValue &v)
 {
-    _val = v.ptr->val();
+    _val = v.ptr->rawValue();
     return *this;
 }
 
 template<typename T>
 inline Value &Value::operator=(const Scoped<T> &t)
 {
-    _val = t.ptr->val();
+    _val = t.ptr->rawValue();
     return *this;
 }
 
Index: qtdeclarative-opensource-src-5.6.1/src/qml/jsruntime/qv4value_p.h
===================================================================
--- qtdeclarative-opensource-src-5.6.1.orig/src/qml/jsruntime/qv4value_p.h
+++ qtdeclarative-opensource-src-5.6.1/src/qml/jsruntime/qv4value_p.h
@@ -66,6 +66,7 @@ typedef uint Bool;
 
 struct Q_QML_PRIVATE_EXPORT Value
 {
+private:
     /*
         We use two different ways of encoding JS values. One for 32bit and one for 64bit systems.
 
@@ -90,10 +91,10 @@ struct Q_QML_PRIVATE_EXPORT Value
 
     quint64 _val;
 
-    Q_ALWAYS_INLINE quint64 val() const { return _val; }
-    Q_ALWAYS_INLINE void setVal(quint64 v) { _val = v; }
-    Q_ALWAYS_INLINE void setValue(quint32 v) { memcpy(&_val, &v, 4); }
-    Q_ALWAYS_INLINE void setTag(quint32 t) { memcpy(4 + (quint8 *)&_val, &t, 4); }
+public:
+    Q_ALWAYS_INLINE quint64 &rawValueRef() { return _val; }
+    Q_ALWAYS_INLINE quint64 rawValue() const { return _val; }
+    Q_ALWAYS_INLINE void setRawValue(quint64 raw) { _val = raw; }
 
 #if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
     static inline int valueOffset() { return 0; }
@@ -113,17 +114,52 @@ struct Q_QML_PRIVATE_EXPORT Value
     Q_ALWAYS_INLINE Heap::Base *m() const { Q_UNREACHABLE(); return Q_NULLPTR; }
     Q_ALWAYS_INLINE void setM(Heap::Base *b) { Q_UNUSED(b); Q_UNREACHABLE(); }
 #elif defined(QV4_USE_64_BIT_VALUE_ENCODING)
-    Q_ALWAYS_INLINE Heap::Base *m() const { Heap::Base *b; memcpy(&b, &_val, QT_POINTER_SIZE); return b; }
-    Q_ALWAYS_INLINE void setM(Heap::Base *b) { memcpy(&_val, &b, QT_POINTER_SIZE); }
+    Q_ALWAYS_INLINE Heap::Base *m() const
+    {
+        Heap::Base *b;
+        memcpy(&b, &_val, 8);
+        return b;
+    }
+    Q_ALWAYS_INLINE void setM(Heap::Base *b)
+    {
+        memcpy(&_val, &b, 8);
+    }
 #else // !QV4_USE_64_BIT_VALUE_ENCODING
-    Q_ALWAYS_INLINE Heap::Base *m() const { Q_STATIC_ASSERT(sizeof(Heap::Base*) == sizeof(quint32)); Heap::Base *b; quint32 v = value(); memcpy(&b, &v, 4); return b; }
-    Q_ALWAYS_INLINE void setM(Heap::Base *b) { quint32 v; memcpy(&v, &b, 4); setValue(v); }
+    Q_ALWAYS_INLINE Heap::Base *m() const
+    {
+        Q_STATIC_ASSERT(sizeof(Heap::Base*) == sizeof(quint32));
+        Heap::Base *b;
+        quint32 v = value();
+        memcpy(&b, &v, 4);
+        return b;
+    }
+    Q_ALWAYS_INLINE void setM(Heap::Base *b)
+    {
+        quint32 v;
+        memcpy(&v, &b, 4);
+        setTagValue(Managed_Type, v);
+    }
 #endif
 
-    Q_ALWAYS_INLINE int int_32() const { int i; quint32 v = value(); memcpy(&i, &v, 4); return i; }
-    Q_ALWAYS_INLINE void setInt_32(int i) { quint32 u; memcpy(&u, &i, 4); setValue(u); }
+    Q_ALWAYS_INLINE int int_32() const
+    {
+        return int(value());
+    }
+    Q_ALWAYS_INLINE void setInt_32(int i)
+    {
+        setTagValue(Integer_Type_Internal, quint32(i));
+    }
     Q_ALWAYS_INLINE uint uint_32() const { return value(); }
 
+    Q_ALWAYS_INLINE void setEmpty()
+    {
+        setTagValue(Empty_Type, value());
+    }
+
+    Q_ALWAYS_INLINE void setEmpty(int i)
+    {
+        setTagValue(Empty_Type, quint32(i));
+    }
 #ifndef QV4_USE_64_BIT_VALUE_ENCODING
     enum Masks {
         SilentNaNBit           =                  0x00040000,
@@ -260,7 +296,6 @@ struct Q_QML_PRIVATE_EXPORT Value
             int i = (int)d;
             if (i == d) {
                 setInt_32(i);
-                setTag(Integer_Type_Internal);
                 return true;
             }
         }
@@ -292,22 +327,10 @@ struct Q_QML_PRIVATE_EXPORT Value
         return m();
     }
 
-    Q_ALWAYS_INLINE quint64 &rawValueRef() {
-        return _val;
-    }
-    Q_ALWAYS_INLINE quint64 rawValue() const {
-        return _val;
-    }
-    Q_ALWAYS_INLINE void setRawValue(quint64 raw) { _val = raw; }
-
     static inline Value fromHeapObject(Heap::Base *m)
     {
         Value v;
-        v.setRawValue(0);
         v.setM(m);
-#ifndef QV4_USE_64_BIT_VALUE_ENCODING
-        v.setTag(Managed_Type);
-#endif
         return v;
     }
 
@@ -328,7 +351,7 @@ struct Q_QML_PRIVATE_EXPORT Value
     inline bool tryIntegerConversion() {
         bool b = integerCompatible();
         if (b)
-            setTag(Integer_Type_Internal);
+            setTagValue(Integer_Type_Internal, value());
         return b;
     }
 
@@ -378,7 +401,7 @@ struct Q_QML_PRIVATE_EXPORT Value
     Value &operator=(ReturnedValue v) { _val = v; return *this; }
     Value &operator=(Managed *m) {
         if (!m) {
-            setTagValue(Undefined_Type, 0);
+            setM(0);
         } else {
             _val = reinterpret_cast<Value *>(m)->_val;
         }
@@ -386,9 +409,6 @@ struct Q_QML_PRIVATE_EXPORT Value
     }
     Value &operator=(Heap::Base *o) {
         setM(o);
-#ifndef QV4_USE_64_BIT_VALUE_ENCODING
-        setTag(Managed_Type);
-#endif
         return *this;
     }
 
@@ -479,13 +499,7 @@ struct Q_QML_PRIVATE_EXPORT Primitive :
 inline Primitive Primitive::undefinedValue()
 {
     Primitive v;
-#ifdef QV4_USE_64_BIT_VALUE_ENCODING
-    v.setRawValue(quint64(Undefined_Type) << Tag_Shift);
-#else
-    v.setRawValue(0);
-    v.setTag(Undefined_Type);
-    v.setValue(0);
-#endif
+    v.setTagValue(Undefined_Type, 0);
     return v;
 }
 
@@ -499,11 +513,7 @@ inline Primitive Primitive::emptyValue()
 inline Primitive Primitive::nullValue()
 {
     Primitive v;
-#ifndef QV4_USE_64_BIT_VALUE_ENCODING
-    v.setRawValue(quint64(Null_Type_Internal) << Tag_Shift);
-#else
     v.setTagValue(Null_Type_Internal, 0);
-#endif
     return v;
 }
 
@@ -524,7 +534,7 @@ inline Primitive Primitive::fromDouble(d
 inline Primitive Primitive::fromInt32(int i)
 {
     Primitive v;
-    v.setTagValue(Integer_Type_Internal, 0); // For mingw482, because it complains, and for VS9, because of internal compiler errors.
+    v.setTagValue(Integer_Type_Internal, 0);
     v.setInt_32(i);
     return v;
 }
@@ -533,8 +543,7 @@ inline Primitive Primitive::fromUInt32(u
 {
     Primitive v;
     if (i < INT_MAX) {
-        v.setTagValue(Integer_Type_Internal, 0); // For mingw482, because it complains, and for VS9, because of internal compiler errors.
-        v.setInt_32((int)i);
+        v.setTagValue(Integer_Type_Internal, i);
     } else {
         v.setDouble(i);
     }
openSUSE Build Service is sponsored by