lua-users home
lua-l archive

[Date Prev][Date Next][Thread Prev][Thread Next] [Date Index] [Thread Index]


Forgive me if this has been discussed already, but I can’t find it after spending some time searching the archives.  If it has and you have a link, please just send me there!  :D

 

The short version is that it looks like the garbage collector decides to collect and free a block of strings while my script is executing… the problem is, those strings include one that has the next token to be processed.  BUT – only if the script has a bunch of free instructions and this processing is occurring during the initial lua_pcall() after the luaL_loadfile  .  EG:

 

fails.lua:

 

--do thing 1

--do thing 2

-- do thing 3

-- do thing 4

 

while:

 

works.lua:

 

function doThings()

--do thing 1

-- do thing 2

-- do thing 3

-- do thing 4

end

 

 

I found this thread:

 

http://lua-list.2524044.n2.nabble.com/closure-runs-with-garbage-collected-upvalue-tt6798377.html#none

 

but it seems to be a different problem, and the suggested fix didn’t resolve my issue.

 

 

 

 

 

Longer version:

 

Lua 5.1.4 compiled into a library that is linked into my main C/C++ exe, running on Windows 7, built with VisDev 2008.

 

I’m using a modified version of the Game Programming Gems 7 automatic Lua binding system (originally written by Julien Hamaide against Lua 5.1.2) to bind classes and their methods and member variables into Lua.

On startup, I have a couple of scripts that run to set some initial values.  Currently the scripts are just tests, to confirm that all functionality is working (I’m still confirming my modifications are correct).

 

The first script runs fine – it’s relatively short and contains a single function which is called.

 

The second script is a bit longer and exhibits the problem when the code is not contained in a function, but rather is just a bunch of loose instructions.

 

The script looks like so when things are outside the function – just some basic stuff, a few variables created and set to various test values

 

    local light1 = CLight:CreateCLight(LightType.light_ambient)

    local light2 = CLight:CreateCLight(LightType.light_directional)

    local color1 = F32_Color4:new(0.5, 0.5, 0.5, 1)

    light1:SetColorDiffuse(color1)

    light1:SetColorSpecular(color1)

    CViewerManager:AddLight(light1)   -- This is where the problem occurs.

 

… (there’s more to the script, but it seems irrelevant)

 

 

CViewerManager is a bound class – I’m using Julien’s method of using the Global table’s __index metamethod to do the lookup with a GlobalIndexEventHandler() function:

 

// ----------------------------------------------------------------------------------------------------

int MetaScriptableLuaRegister::GlobalIndexEventHandler(lua_State* lua_state)

{

   MetaScriptableBindingData *  binding;

   const char *                 class_name;

   int                          class_index;

 

   lua_getfield(lua_state, LUA_GLOBALSINDEX, "_binding_data");

   binding     = reinterpret_cast<MetaScriptableBindingData *>(lua_touserdata(lua_state, -1));

   lua_pop(lua_state, 1);

   class_name = lua_tostring(lua_state, 2);

 

   if (!class_name || !binding->FindClassIndex(class_index, class_name))

   {

      lua_pushnil(lua_state);

   }

   else

   {

      MetaScriptableBindingHelper * binding_data = static_cast<MetaScriptableBindingHelper *>(lua_newuserdata(lua_state, sizeof(MetaScriptableBindingHelper)));

 

      lua_newtable(lua_state); // Create Metatable

      lua_pushcfunction(lua_state, &MetaScriptableLuaRegister::IndexEventHandler);

      lua_setfield(lua_state, -2, "__index");

      lua_pushcfunction(lua_state, &MetaScriptableLuaRegister::NewIndexEventHandler);

      lua_setfield(lua_state, -2, "__newindex");

 

      lua_setmetatable(lua_state, -2);

 

      binding_data->Object = NULL;

      binding_data->ClassIndex = class_index;

 

      // put a copy in the global table

      lua_pushvalue(lua_state, 2);

      lua_pushvalue(lua_state, -2);

      lua_rawset(lua_state, LUA_GLOBALSINDEX);

   }

 

   return 1;

}

 

 

As you can see, that creates a new userdata for the helper table that has the class index in my lookup list and binds a metatable with __index and __newindex metamethods defined, to catch calls to methods and variables respectively.  The two callback functions are very similar to  GlobalIndexEventHandler() and everything seems to execute fine, until that last line of lua I copied above is reached:

 

CViewerManager:AddLight(light1)

 

CViewManager triggers the call to GlobalIndexEventHandler () correctly.  But as that runs, the call to lua_pushcfunction (which seems to be a #define wrapping lua_pushcclosure() ) executes a call to luaC_checkGC(), which triggers a sweep of the strings list.  That sweep gets these strings (I added my own realloc function that prints out the parameters passed in and adjusted the code to pass in a useful string for labeling):

 

B116300        0    23     0 freeobj:LUA_TSTRING

B11AB28        0    27     0 freeobj:LUA_TSTRING

B11AE18        0    28     0 freeobj:LUA_TSTRING

B11A6B8        0    29     0 freeobj:LUA_TSTRING

B119210        0    45     0 freeobj:LUA_TSTRING

B11A9F0        0    34     0 freeobj:LUA_TSTRING

B1191C0        0    18     0 freeobj:LUA_TSTRING

B11AAD0        0    23     0 freeobj:LUA_TSTRING

B11A850        0    30     0 freeobj:LUA_TSTRING

B116248        0    31     0 freeobj:LUA_TSTRING

B11A590        0    23     0 freeobj:LUA_TSTRING

B11A7F8        0    26     0 freeobj:LUA_TSTRING

B11A4D8        0    23     0 freeobj:LUA_TSTRING

B11AA50        0    32     0 freeobj:LUA_TSTRING

B1162A8        0    25     0 freeobj:LUA_TSTRING

B11A530        0    29     0 freeobj:LUA_TSTRING

 

 

And those strings are these, most of which were allocated during the parse and seem to have the names of tokens for the running script:

 

       0  B116300     0    23 luaS_newlstr called for luaX_newstring: color2

       0  B11AB28     0    27 luaS_newlstr called for luaX_newstring: F32_Color4

       0  B11AE18     0    28 luaS_newlstr called for luaX_newstring: F32_Vector3

       0  B11A6B8     0    29 luaS_newlstr called for luaX_newstring: SetDirection

       0  B119210     0    45 luaS_new called for pushstr: config/ViewerMode-Assets.lua

       0  B11A9F0     0    34 luaS_newlstr called for luaX_newstring: light_directional

       0  B1191C0     0    18 luaS_newlstr called for luaO_pushvfstring: @

       0  B11AAD0     0    23 luaS_newlstr called for luaX_newstring: color1

       0  B11A850     0    30 luaS_newlstr called for luaX_newstring: light_ambient

       0  B116248     0    31 luaS_newlstr called for luaX_newstring: CViewerManager

       0  B11A590     0    23 luaS_newlstr called for luaX_newstring: light2

       0  B11A7F8     0    26 luaS_newlstr called for luaX_newstring: LightType

       0  B11A4D8     0    23 luaS_newlstr called for luaX_newstring: light1

       0  B11AA50     0    32 luaS_newlstr called for luaX_newstring: SetColorDiffuse

       0  B1162A8     0    25 luaS_newlstr called for luaX_newstring: AddLight             -- VERY BAD!  Next token to be executed!

       0  B11A530     0    29 luaS_newlstr called for luaX_newstring: CreateCLight

 

Which causes the problem when Lua calls into the IndexEventHandler() for the CViewerManager:AddLight portion of the script:

 

 

int MetaScriptableLuaRegister::IndexEventHandler(lua_State * lua_state)

{

   MetaScriptableBindingData *                 binding;

   MetaScriptableBindingData::BINDING_FUNCTION function;

   const char *                                method_name;

   MetaScriptableBindingHelper *               binding_data;

 

   lua_getfield(lua_state, LUA_GLOBALSINDEX, "_binding_data");

   binding        = reinterpret_cast<MetaScriptableBindingData *>(lua_touserdata(lua_state, -1));

   lua_pop(lua_state, 1);

   binding_data   = static_cast<MetaScriptableBindingHelper *>(lua_touserdata(lua_state, 1));

   method_name    = lua_tostring(lua_state, 2);

 

 

At this point, method_name comes back with the free’d pointer at 0x0B1162A8, which has garbage in it (per my debugger):

 

+                             method_name 0x0b1162b8 " <… garbage elided …>"      const char *

 

 

 

So…

 

Any thoughts?  Is it something obvious that I’ve done, or do we need more info to figure out what’s up?  For now, putting all my code into functions and calling them after the initial parse is fine.  But I’m worried this only postpones the issue and that it will come back when my functions become more complex or I have multiple functions in the file.

 

Thanks!

 

-Greg



IMPORTANT: This email message is intended only for the use of the individual to whom, or entity to which, it is addressed and may contain information that is privileged, confidential and exempt from disclosure under applicable law. If you are NOT the intended recipient, you are hereby notified that any use, dissemination, distribution or copying of this communication is strictly prohibited. If you have received this communication in error, please reply to the sender immediately and permanently delete this email. Thank you.