Browse Source

Fix a memory leak when pushing love objects to threads which never load that object’s module (resolves issue #1267).

Also fix Variant assignment operator to call release() on the correct object.

--HG--
branch : minor
Alex Szpakowski 8 years ago
parent
commit
43fea45f9f
2 changed files with 18 additions and 5 deletions
  1. 5 5
      src/common/Variant.cpp
  2. 13 0
      src/common/runtime.cpp

+ 5 - 5
src/common/Variant.cpp

@@ -106,7 +106,7 @@ Variant::Variant(const Variant &v)
 {
 	if (type == STRING)
 		data.string->retain();
-	else if (type == FUSERDATA && data.userdata != nullptr)
+	else if (type == FUSERDATA && udatatype != nullptr && data.userdata != nullptr)
 		((love::Object *) data.userdata)->retain();
 	else if (type == TABLE)
 		data.table->retain();
@@ -128,7 +128,7 @@ Variant::~Variant()
 		data.string->release();
 		break;
 	case FUSERDATA:
-		if (data.userdata != nullptr)
+		if (udatatype != nullptr && data.userdata != nullptr)
 			((love::Object *) data.userdata)->release();
 		break;
 	case TABLE:
@@ -143,15 +143,15 @@ Variant &Variant::operator = (const Variant &v)
 {
 	if (v.type == STRING)
 		v.data.string->retain();
-	else if (v.type == FUSERDATA && v.data.userdata != nullptr)
+	else if (v.type == FUSERDATA && v.udatatype != nullptr && v.data.userdata != nullptr)
 		((love::Object *) v.data.userdata)->retain();
 	else if (v.type == TABLE)
 		v.data.table->retain();
 
 	if (type == STRING)
 		data.string->release();
-	else if (type == FUSERDATA && v.data.userdata != nullptr)
-		((love::Object *) v.data.userdata)->release();
+	else if (type == FUSERDATA && udatatype != nullptr && data.userdata != nullptr)
+		((love::Object *) data.userdata)->release();
 	else if (type == TABLE)
 		data.table->release();
 

+ 13 - 0
src/common/runtime.cpp

@@ -490,6 +490,19 @@ void luax_rawnewtype(lua_State *L, love::Type &type, love::Object *object)
 
 	const char *name = type.getName();
 	luaL_newmetatable(L, name);
+
+	lua_getfield(L, -1, "__gc");
+	bool has_gc = !lua_isnoneornil(L, -1);
+	lua_pop(L, 1);
+
+	// Make sure mt.__gc exists, so Lua states which don't have the object's
+	// module loaded will still clean the object up when it's collected.
+	if (!has_gc)
+	{
+		lua_pushcfunction(L, w__gc);
+		lua_setfield(L, -2, "__gc");
+	}
+
 	lua_setmetatable(L, -2);
 }