diff --git a/LuaCppInterface/luacppinterface.h b/LuaCppInterface/luacppinterface.h index f70c39a..575d529 100644 --- a/LuaCppInterface/luacppinterface.h +++ b/LuaCppInterface/luacppinterface.h @@ -23,7 +23,10 @@ class Lua template LuaFunction internalCreateFunction( std::shared_ptr< std::function > func, lua_CFunction cfunc) { - LuaFunction** ptr = (LuaFunction**)lua_newuserdata(state.get(), sizeof(LuaFunction**)); + auto* ptr = (std::shared_ptr< std::function >*) + lua_newuserdata(state.get(), sizeof(std::shared_ptr< std::function >*)); + + ptr = new std::shared_ptr< std::function >(func); lua_newtable(state.get()); @@ -45,11 +48,8 @@ class Lua // set the metatable lua_setmetatable(state.get(), -2); - LuaFunction function = LuaFunction(state, -1, func); - // instantiate a luafunction that has a weak reference to the state - // that the lua garbage collector will collect. - *ptr = new LuaFunction(LuaFunction(LuaNoDestructor(state.get()), -1, func)); + LuaFunction function(LuaNoDestructor(state.get()), -1, func); lua_pop(state.get(), 1); return function; @@ -58,8 +58,8 @@ class Lua template static int lua_finalizer(lua_State* state) { - LuaFunction** func = (LuaFunction**)lua_touserdata(state, lua_upvalueindex(1)); - delete *func; + auto* func = (std::shared_ptr< std::function >*)lua_touserdata(state, lua_upvalueindex(1)); + delete func; return 0; }; diff --git a/tests/Makefile.am b/tests/Makefile.am index c28ae94..9fbfd39 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -3,7 +3,7 @@ if COND_GCOV MAYBE_COVERAGE=-fprofile-arcs endif -TESTS = demonstration1 demonstration2 demonstration3 demonstration4 luacpp testcallabletable testchartowideconvert testcoroutineexception testcoroutineexpectedbutnot testcreate testctoluafunction testexceptioninluafunction testextractingasfunctionbutistable testfunction testfunctionerror testfunctionexpectedbutnotcallable testfunctionparams testfunctionparamsreturn testfunctionreturn testgetmetatableonclosedstate testgetsetfunction testgetsetfunction2 testgetsetinsidetable testgetsetinteger testgetsetstring testgetsettable testgetstate testgettypeofvalueat testinvalidscript testpassingfunction testreadinglightuserdatafromuserdata testregistry testresumenoscript testreturnfromnative testreturnfromscript testreturnfromyieldingfunction testreturntablefromlua testreturntablefromnative testscriptexception testsetstring testsetwstring testtable testtableexpectedbutnotable testtableforeachintegerkey testtableforeachstringkey testtypeintstringmorph testtypemorphintwstring testtypestringintmorph testuserdata testuserdataconstructor testuserdatadispose testuserdatamethod testwidetocharconvert +TESTS = demonstration1 demonstration2 demonstration3 demonstration4 luacpp testcallabletable testchartowideconvert testcoroutineexception testcoroutineexpectedbutnot testcreate testctoluafunction testexceptioninluafunction testextractingasfunctionbutistable testfunction testfunctiondoesntleak testfunctionerror testfunctionexpectedbutnotcallable testfunctionparams testfunctionparamsreturn testfunctionreturn testgetmetatableonclosedstate testgetsetfunction testgetsetfunction2 testgetsetinsidetable testgetsetinteger testgetsetstring testgetsettable testgetstate testgettypeofvalueat testinvalidscript testpassingfunction testreadinglightuserdatafromuserdata testregistry testresumenoscript testreturnfromnative testreturnfromscript testreturnfromyieldingfunction testreturntablefromlua testreturntablefromnative testscriptexception testsetstring testsetwstring testtable testtableexpectedbutnotable testtableforeachintegerkey testtableforeachstringkey testtypeintstringmorph testtypemorphintwstring testtypestringintmorph testuserdata testuserdataconstructor testuserdatadispose testuserdatamethod testwidetocharconvert check_PROGRAMS = $(TESTS) @@ -53,6 +53,9 @@ testextractingasfunctionbutistable_LDADD = $(REQUIRED_LIBS) testfunction_SOURCES = testfunction.cpp lua testfunction_LDADD = $(REQUIRED_LIBS) +testfunctiondoesntleak_SOURCES = testfunctiondoesntleak.cpp lua +testfunctiondoesntleak_LDADD = $(REQUIRED_LIBS) + testfunctionerror_SOURCES = testfunctionerror.cpp lua testfunctionerror_LDADD = $(REQUIRED_LIBS) diff --git a/tests/testfunctiondoesntleak.cpp b/tests/testfunctiondoesntleak.cpp new file mode 100644 index 0000000..7e49530 --- /dev/null +++ b/tests/testfunctiondoesntleak.cpp @@ -0,0 +1,31 @@ +// Test for CreateFunction memory leak + +#include +#include + +struct Functor { + std::shared_ptr ptr; + + void operator()() const { + // no-op + } +}; + +int main() +{ + Lua lua; + + // Create a LuaFunction from a functor that holds a shared_ptr to + // a resource. If the function created via CreateFunction gets + // collected by the GC, the weak pointer will expire after that + std::weak_ptr weak; + { + auto ptr = std::make_shared(0); + weak = ptr; + auto function = lua.CreateFunction(Functor{ptr}); + } + + lua.CollectGarbage(); + + return !weak.expired(); +}