From a4877338826381d454dfdae74242a007b3aac9e0 Mon Sep 17 00:00:00 2001
From: Ulf Hermann <ulf.hermann@digia.com>
Date: Thu, 6 Nov 2014 14:40:37 +0100
Subject: [PATCH] Avoid stack overflow when destroying InternalClass

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 | 35 +++++++++++++-------------
 1 file changed, 17 insertions(+), 18 deletions(-)

diff --git a/src/qml/jsruntime/qv4internalclass.cpp b/src/qml/jsruntime/qv4internalclass.cpp
index a59c3892a1..bb22e30ac1 100644
--- a/src/qml/jsruntime/qv4internalclass.cpp
+++ b/src/qml/jsruntime/qv4internalclass.cpp
@@ -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
-- 
GitLab