Avoid stack overflow when destroying InternalClass
authorUlf Hermann <ulf.hermann@digia.com>
Thu, 6 Nov 2014 13:40:37 +0000 (14:40 +0100)
committerUlf Hermann <ulf.hermann@digia.com>
Thu, 6 Nov 2014 16:52:26 +0000 (17:52 +0100)
If there are deep object hierarchies connected to an InternalClass the
recursive nature of the destroy() method could lead to a stack
overflow. By changing the recursion into an iteration this is avoided.

Change-Id: I6667f268a366749c2dbc5f7147882388f192a9c5
Reviewed-by: Simon Hausmann <simon.hausmann@digia.com>
src/qml/jsruntime/qv4internalclass.cpp

index a59c389..bb22e30 100644 (file)
@@ -412,25 +412,24 @@ InternalClass *InternalClass::frozen()
 
 void InternalClass::destroy()
 {
-    if (!engine)
-        return;
-    engine = 0;
-
-    propertyTable.~PropertyHash();
-    nameMap.~SharedInternalClassData<String *>();
-    propertyData.~SharedInternalClassData<PropertyAttributes>();
+    QList<InternalClass *> destroyStack;
+    destroyStack.append(this);
 
-    if (m_sealed)
-        m_sealed->destroy();
-
-    if (m_frozen)
-        m_frozen->destroy();
-
-    for (QHash<Transition, InternalClass *>::ConstIterator it = transitions.begin(), end = transitions.end();
-         it != end; ++it)
-        it.value()->destroy();
-
-    transitions.clear();
+    while (!destroyStack.isEmpty()) {
+        InternalClass *next = destroyStack.takeLast();
+        if (!next->engine)
+            continue;
+        next->engine = 0;
+        next->propertyTable.~PropertyHash();
+        next->nameMap.~SharedInternalClassData<String *>();
+        next->propertyData.~SharedInternalClassData<PropertyAttributes>();
+        if (next->m_sealed)
+            destroyStack.append(next->m_sealed);
+        if (next->m_frozen)
+            destroyStack.append(next->m_frozen);
+        destroyStack.append(next->transitions.values());
+        next->transitions.clear();
+    }
 }
 
 struct InternalClassPoolVisitor