Browse Source

Fix memory leak with ReferenceCountable objects

Gambini 11 years ago
parent
commit
f495847af5

+ 22 - 8
Include/Rocket/Core/Lua/LuaType.inl

@@ -109,9 +109,19 @@ int LuaType<T>::push(lua_State *L, T* obj, bool gc)
         }
         else
         {
-            if(IsReferenceCounted<T>())
-                ((Rocket::Core::ReferenceCountable*)obj)->AddReference();
+            //In case this is an address that has been pushed
+            //to lua before, we need to set it to nil
+            lua_pushnil(L); // ->[4] = nil
+            lua_setfield(L,-2,name); //represents t[k] = v, [-2 = 3] = t -> v = [4], k = <ClassName>; pop [4]
+        }
+
+        if(IsReferenceCounted<T>())
+        {
+            //If you look at the gc_T function, reference countables do not
+            //care about the "DO NOT TRASH" table
+            ((Rocket::Core::ReferenceCountable*)obj)->AddReference();
         }
+
         lua_pop(L,1); // -> pop [3]
     }
     lua_settop(L,ud); //[ud = 2] -> remove everything that is above 2, top = [2]
@@ -167,19 +177,23 @@ int LuaType<T>::gc_T(lua_State* L)
     T * obj = check(L,1); //[1] = this userdata
     if(obj == NULL)
         return 0;
+    if(IsReferenceCounted<T>())
+    {
+        // ReferenceCountables do not care about the "DO NOT TRASH" table.
+        // Because userdata is pushed which contains a pointer to the pointer
+        // of 'obj', 'obj' will be garbage collected for every time 'obj' was pushed.
+        ((Rocket::Core::ReferenceCountable*)obj)->RemoveReference();
+        return 0;
+    }
     lua_getfield(L,LUA_REGISTRYINDEX,"DO NOT TRASH"); //->[2] = return value from this
     if(lua_istable(L,-1) ) //[-1 = 2], if it is a table
     {
         char name[32];
         tostring(name,obj);
         lua_getfield(L,-1, std::string(name).c_str()); //[-1 = 2] -> [3] = the value returned from if <ClassName> exists in the table to not gc
-        if(lua_isnil(L,-1) ) //[-1 = 3] if it doesn't exist, then we are free to garbage collect c++ side
+        if(lua_isnoneornil(L,-1) ) //[-1 = 3] if it doesn't exist, then we are free to garbage collect c++ side
         {
-            if(IsReferenceCounted<T>())
-            {
-                ((Rocket::Core::ReferenceCountable*)obj)->RemoveReference();
-            }
-            else
+            if(!IsReferenceCounted<T>())
             {
                 delete obj;
                 obj = NULL;

+ 4 - 2
Source/Core/Lua/Document.cpp

@@ -102,7 +102,8 @@ int DocumentCreateElement(lua_State* L, Document* obj)
 {
     const char* tag = luaL_checkstring(L,1);
     Element* ele = obj->CreateElement(tag);
-    LuaType<Element>::push(L,ele,false);
+    LuaType<Element>::push(L,ele,true);
+    ele->RemoveReference();
     return 1;
 }
 
@@ -111,7 +112,8 @@ int DocumentCreateTextNode(lua_State* L, Document* obj)
     //need ElementText object first
     const char* text = luaL_checkstring(L,1);
     ElementText* et = obj->CreateTextNode(text);
-    LuaType<ElementText>::push(L, et, false);
+    LuaType<ElementText>::push(L, et, true);
+    et->RemoveReference();
 	return 1;
 }
 

+ 1 - 0
Source/Core/Lua/LuaElementInstancer.cpp

@@ -27,6 +27,7 @@
 
 #include "precompiled.h"
 #include "LuaElementInstancer.h"
+#include <Rocket/Core/Platform.h>
 #include <Rocket/Core/Lua/LuaType.h>
 #include <Rocket/Core/Lua/Interpreter.h>
 #include <Rocket/Core/Log.h>