Re: Crash in wrapper_base.cpp

classic Classic list List threaded Threaded
14 messages Options
Reply | Threaded
Open this post in threaded view
|

Re: Crash in wrapper_base.cpp

Drew McLean
Hey all,

It doesn't seem like my posting was sent out since it's not showing up in the mail archives on sourceforge.  Here it is again below.  If anyone can shed some light on this it would be really appreciated.  Thanks.

    Drew


On Sun, Jul 3, 2011 at 6:25 PM, Drew McLean <[hidden email]> wrote:
Hello,

I am using Lua 0.9.1 in a custom game engine and am using the feature of extending C++ objects using Lua via luabind::wrap_base.  My C++ base class is called Agent and contains a virtual function called Update().  I have created a class called ScriptableAgent which extends Agent and luabind::wrap_base.  Lua instances of derived classes are stored in a global table in Lua to avoid garbage collection occurring before the object should be destroyed.  Once created in Lua they are passed to a C++ container which updates the instances each frame.  Whenever I am done with an instance it is removed from the container in C++ and is then removed from the global Lua table so that it can be garbage collected.

I have come across a problem when continuously creating many instances with a short lifetime (this exposes the problem quickly and consistently anyway).  After a while, garbage collection occurs and cleans a bunch of them up.  Immediately after the collection, a crash occurs in the container update loop when updating an instance that *wasn't* garbage collected.  I can tell that it wasn't collected because each Agent has a unique ID and I print it when adding/removing it from the global Lua table, when adding/removing from the C++ container, when in the Lua __finalize() method and inside the destructor in C++. 

The crash occurs in wrapper_base.cpp on line 39 because obj is NULL.  The code around the crash:

    LUABIND_API void do_call_member_selection(lua_State* L, char const* name)
    {
        object_rep* obj = static_cast<object_rep*>(lua_touserdata(L, -1));
        lua_pop(L, 1); // pop self
       
        obj->crep()->get_table(L); // push the crep table    <<<<< Crash here because obj is NULL
        lua_pushstring(L, name);
        lua_gettable(L, -2);
        lua_remove(L, -2); // remove the crep table

        if (!is_luabind_function(L, -1))
            return;

        // this (usually) means the function has not been
        // overridden by lua, call the default implementation
        lua_pop(L, 1);
        obj->crep()->get_default_table(L); // push the crep table
        lua_pushstring(L, name);
        lua_gettable(L, -2);
        lua_remove(L, -2); // remove the crep table
    }



Here is the relevant callstack:

game.exe!luabind::detail::object_rep::crep()  Line 48 + 0x26 bytes    C++
game.exe!luabind::detail::do_call_member_selection(lua_State * L=0x0dc68f78, const char * name=0x0239750c)  Line 39 + 0xc bytes    C++
game.exe!luabind::wrap_base::call<void>(const char * name=0x0239750c, luabind::detail::type_<void> * __formal=0x00000000)  Line 125 + 0xd bytes    C++
game.exe!ScriptableAgent_luabind::Update()  Line 57 + 0x16 bytes    C++
...


Here is an example of the execution order which may help in demonstrating the problem.  The Agent instance on the callstack when the crash occurs has an ID of 110.  According to the log output, this Agent is still in the global table.

...
Registering lua agent: 108
AgentContainer::AddAgent(0xdd19918) [108]
TubeTravelSequenceAgent:__finalize() [28]
ScriptableAgent_luabind::~ScriptableAgent_luabind(): [28]
AgentContainer::RemoveAgent(0xdd590b0) [105]
TubeTravelSequenceAgent:__finalize() [27]
ScriptableAgent_luabind::~ScriptableAgent_luabind(): [27]
Unregistering lua agent: 105
Registering lua agent: 109
AgentContainer::AddAgent(0xc32a6b0) [109]
TubeTravelSequenceAgent:__finalize() [26]
ScriptableAgent_luabind::~ScriptableAgent_luabind(): [26]
AgentContainer::RemoveAgent(0xc2a3570) [106]
Unregistering lua agent: 106
Registering lua agent: 110      <<<<<<<<<<< Agent 110 added
AgentContainer::AddAgent(0xdd55be0) [110]    <<<<<<<<<<<<<< Agent 110 added
TubeTravelSequenceAgent:__finalize() [25]
ScriptableAgent_luabind::~ScriptableAgent_luabind(): [25]
TubeTravelSequenceAgent:__finalize() [24]
ScriptableAgent_luabind::~ScriptableAgent_luabind(): [24]
AgentContainer::RemoveAgent(0xdd71e18) [107]
Unregistering lua agent: 107
Registering lua agent: 111
AgentContainer::AddAgent(0xdd902d0) [111]
TubeTravelSequenceAgent:__finalize() [23]
ScriptableAgent_luabind::~ScriptableAgent_luabind(): [23]
TubeTravelSequenceAgent:__finalize() [22]
ScriptableAgent_luabind::~ScriptableAgent_luabind(): [22]
AgentContainer::RemoveAgent(0xdd19918) [108]
Unregistering lua agent: 108
ScriptableAgent:__finalize() [21]
ScriptableAgent_luabind::~ScriptableAgent_luabind(): [21]
Registering lua agent: 112
AgentContainer::AddAgent(0xc268a60) [112]
TubeTravelSequenceAgent:__finalize() [108]
ScriptableAgent_luabind::~ScriptableAgent_luabind(): [108]
TubeTravelSequenceAgent:__finalize() [107]
ScriptableAgent_luabind::~ScriptableAgent_luabind(): [107]
TubeTravelSequenceAgent:__finalize() [106]
ScriptableAgent_luabind::~ScriptableAgent_luabind(): [106]
TubeTravelSequenceAgent:__finalize() [105]
ScriptableAgent_luabind::~ScriptableAgent_luabind(): [105]
TubeTravelSequenceAgent:__finalize() [104]
ScriptableAgent_luabind::~ScriptableAgent_luabind(): [104]
TubeTravelSequenceAgent:__finalize() [103]
ScriptableAgent_luabind::~ScriptableAgent_luabind(): [103]
TubeTravelSequenceAgent:__finalize() [102]
ScriptableAgent_luabind::~ScriptableAgent_luabind(): [102]
TubeTravelSequenceAgent:__finalize() [101]
ScriptableAgent_luabind::~ScriptableAgent_luabind(): [101]
TubeTravelSequenceAgent:__finalize() [100]
ScriptableAgent_luabind::~ScriptableAgent_luabind(): [100]
TubeTravelSequenceAgent:__finalize() [99]
ScriptableAgent_luabind::~ScriptableAgent_luabind(): [99]
TubeTravelSequenceAgent:__finalize() [98]
ScriptableAgent_luabind::~ScriptableAgent_luabind(): [98]
TubeTravelSequenceAgent:__finalize() [97]
ScriptableAgent_luabind::~ScriptableAgent_luabind(): [97]
TubeTravelSequenceAgent:__finalize() [96]
ScriptableAgent_luabind::~ScriptableAgent_luabind(): [96]
TubeTravelSequenceAgent:__finalize() [95]
ScriptableAgent_luabind::~ScriptableAgent_luabind(): [95]
TubeTravelSequenceAgent:__finalize() [94]
ScriptableAgent_luabind::~ScriptableAgent_luabind(): [94]
TubeTravelSequenceAgent:__finalize() [93]
ScriptableAgent_luabind::~ScriptableAgent_luabind(): [93]
TubeTravelSequenceAgent:__finalize() [92]
ScriptableAgent_luabind::~ScriptableAgent_luabind(): [92]
TubeTravelSequenceAgent:__finalize() [91]
ScriptableAgent_luabind::~ScriptableAgent_luabind(): [91]
TubeTravelSequenceAgent:__finalize() [90]
ScriptableAgent_luabind::~ScriptableAgent_luabind(): [90]
TubeTravelSequenceAgent:__finalize() [89]
ScriptableAgent_luabind::~ScriptableAgent_luabind(): [89]
TubeTravelSequenceAgent:__finalize() [88]
ScriptableAgent_luabind::~ScriptableAgent_luabind(): [88]
TubeTravelSequenceAgent:__finalize() [87]
ScriptableAgent_luabind::~ScriptableAgent_luabind(): [87]
TubeTravelSequenceAgent:__finalize() [86]
ScriptableAgent_luabind::~ScriptableAgent_luabind(): [86]
TubeTravelSequenceAgent:__finalize() [85]
ScriptableAgent_luabind::~ScriptableAgent_luabind(): [85]
TubeTravelSequenceAgent:__finalize() [84]
ScriptableAgent_luabind::~ScriptableAgent_luabind(): [84]
TubeTravelSequenceAgent:__finalize() [83]
ScriptableAgent_luabind::~ScriptableAgent_luabind(): [83]
TubeTravelSequenceAgent:__finalize() [82]
ScriptableAgent_luabind::~ScriptableAgent_luabind(): [82]
TubeTravelSequenceAgent:__finalize() [81]
ScriptableAgent_luabind::~ScriptableAgent_luabind(): [81]
TubeTravelSequenceAgent:__finalize() [80]
ScriptableAgent_luabind::~ScriptableAgent_luabind(): [80]
TubeTravelSequenceAgent:__finalize() [79]
ScriptableAgent_luabind::~ScriptableAgent_luabind(): [79]
First-chance exception at 0x01cf37f6 in nanite_debug.exe: 0xC0000005: Access violation reading location 0x00000028.
Unhandled exception at 0x01cf37f6 in nanite_debug.exe: 0xC0000005: Access violation reading location 0x00000028.
First-chance exception at 0x01cf37f6 in nanite_debug.exe: 0xC0000005: Access violation reading location 0x00000028.
Unhandled exception at 0x01cf37f6 in nanite_debug.exe: 0xC0000005: Access violation reading location 0x00000028.


I have also seen another variation of this problem where the assertion in wrapper_base.hpp on line 124 fails.  The code around this assertion is

            // get the function
            lua_State* L = m_self.state();
            m_self.get(L);
            assert(!lua_isnil(L, -1));               <<<<<<< fails
            detail::do_call_member_selection(L, name);


I have seen that someone else has come across this problem recently but there was no solution suggested for it. 

     http://stackoverflow.com/questions/6236827/assertion-failure-in-luabind<span onmouseout="cancel = false; window.setTimeout(WRCHideContent, 1000);" onmouseover="WRCShowContent({&#39;rating&#39;:{&#39;value&#39;:100,&#39;weight&#39;:93},&#39;flags&#39;:{&#39;it&#39;:1},&#39;ttl&#39;:3600,&#39;expireTime&#39;:&#39;20110706123649&#39;}, this.className);" class="wrc13" style="padding-right: 16px; width: 16px; height: 16px;">


Any help would be appreciated.  Let me know if you need more info.  Thanks!

    Drew

--
Drew McLean
Lead Tech Programmer
A Priori Games
<a href="tel:%28250%29%20508-3346" value="+12505083346" target="_blank">(250) 508-3346
www.apriorigames.com<span onmouseout="cancel = false; window.setTimeout(WRCHideContent, 1000);" onmouseover="WRCShowContent({&#39;rating&#39;:{&#39;value&#39;:-1,&#39;weight&#39;:-1},&#39;flags&#39;:{},&#39;ttl&#39;:3600,&#39;expireTime&#39;:&#39;20110706123748&#39;}, this.className);" class="wrc0" style="padding-right: 16px; width: 16px; height: 16px;">


------------------------------------------------------------------------------
All of the data generated in your IT infrastructure is seriously valuable.
Why? It contains a definitive record of application performance, security
threats, fraudulent activity, and more. Splunk takes this data and makes
sense of it. IT sense. And common sense.
http://p.sf.net/sfu/splunk-d2d-c2
_______________________________________________
luabind-user mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/luabind-user
Reply | Threaded
Open this post in threaded view
|

Re: Crash in wrapper_base.cpp

Nigel Atkinson-2

> On Sun, Jul 3, 2011 at 6:25 PM, Drew McLean <[hidden email]>
> wrote:
>         Hello,
>        
>         I am using Lua 0.9.1 in a custom game engine and am using the
>         feature of extending C++ objects using Lua via
>         luabind::wrap_base.  My C++ base class is called Agent and
>         contains a virtual function called Update().  I have created a
>         class called ScriptableAgent which extends Agent and
>         luabind::wrap_base.  Lua instances of derived classes are
>         stored in a global table in Lua to avoid garbage collection
>         occurring before the object should be destroyed.  Once created
>         in Lua they are passed to a C++ container which updates the
>         instances each frame.  Whenever I am done with an instance it
>         is removed from the container in C++ and is then removed from
>         the global Lua table so that it can be garbage collected.

I've hit this exact same problem, in a almost exact same situation - I
had a vector of game entities that I was looping through calling an
update function.  Also I was relying on the destructor and hence the
Luabind finaliser to remove entities from the list.  However Update was
being called between the time the Lua entity reference was set to nil,
and the time the object was destructed and removed from the list.  Even
a explicit garbage collection (or several) did not seem to work.

I never quite got to the bottom of it, however I have a hacky solution
that works.

This is my GameEntityWrapper:

class GameEntityWrapper : public GameEntity, public luabind::wrap_base
{
    public:

    virtual void update()
    {
        lua_State* L = m_self.state();
        m_self.get(L);
        if( ! lua_isnil( L, -1 ) ) // If the Lua side is not there
anymore just ignore.
            call<void>( "update" );
        lua_pop( L, 1 );
    }

    static void default_update( GameEntity* ptr )
    {
        ptr->GameEntity::update();
    }
};

If you interested in the rest have a look at:
https://github.com/merlinblack/Game-Engine-Testbed/blob/master/include/gameentity.h

This required a small change in wrapper_base.hpp on line 66 from

  private:
    wrapped_self_t m_self;

to

  protected:
    wrapped_self_t m_self;


This allows access to m_self in your wrapper class.  You might not even
need to recompile the library - how hacky is THAT! :-)

But there are bound to be better solutions, that probably do not require
changing Luabind. However this works for me. Perhaps the change to
wrapper_base.hpp might be considered for Luabind - or perhaps adding a
function along the lines of isValid() to wrap_base.

I really should figure out why doing an explicit garbage collection -
even several iterations - still did not prevent my crash....

Nigel


------------------------------------------------------------------------------
All of the data generated in your IT infrastructure is seriously valuable.
Why? It contains a definitive record of application performance, security
threats, fraudulent activity, and more. Splunk takes this data and makes
sense of it. IT sense. And common sense.
http://p.sf.net/sfu/splunk-d2d-c2
_______________________________________________
luabind-user mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/luabind-user
Reply | Threaded
Open this post in threaded view
|

Re: Crash in wrapper_base.cpp

Drew McLean
Hmmm, that's a possible crash workaround but I'm not sure it will help in my use case.  I think my scenario is a little different than yours since my object isn't supposed to be garbage collected at all because it hasn't been removed from my global Lua table.  It's almost like the garbage collection has erroneously chosen that instance to dispose of when it shouldn't have but also didn't call the finalizer.  I need my object to continue to function until I unregister it from the global Lua table.  This is why I think it's probably a Luabind bug as opposed to a usage bug. 

    Drew

On Wed, Jul 6, 2011 at 4:25 PM, Nigel Atkinson <[hidden email]> wrote:

> On Sun, Jul 3, 2011 at 6:25 PM, Drew McLean <[hidden email]>
> wrote:
>         Hello,
>
>         I am using Lua 0.9.1 in a custom game engine and am using the
>         feature of extending C++ objects using Lua via
>         luabind::wrap_base.  My C++ base class is called Agent and
>         contains a virtual function called Update().  I have created a
>         class called ScriptableAgent which extends Agent and
>         luabind::wrap_base.  Lua instances of derived classes are
>         stored in a global table in Lua to avoid garbage collection
>         occurring before the object should be destroyed.  Once created
>         in Lua they are passed to a C++ container which updates the
>         instances each frame.  Whenever I am done with an instance it
>         is removed from the container in C++ and is then removed from
>         the global Lua table so that it can be garbage collected.

I've hit this exact same problem, in a almost exact same situation - I
had a vector of game entities that I was looping through calling an
update function.  Also I was relying on the destructor and hence the
Luabind finaliser to remove entities from the list.  However Update was
being called between the time the Lua entity reference was set to nil,
and the time the object was destructed and removed from the list.  Even
a explicit garbage collection (or several) did not seem to work.

I never quite got to the bottom of it, however I have a hacky solution
that works.

This is my GameEntityWrapper:

class GameEntityWrapper : public GameEntity, public luabind::wrap_base
{
   public:

   virtual void update()
   {
       lua_State* L = m_self.state();
       m_self.get(L);
       if( ! lua_isnil( L, -1 ) ) // If the Lua side is not there
anymore just ignore.
           call<void>( "update" );
       lua_pop( L, 1 );
   }

   static void default_update( GameEntity* ptr )
   {
       ptr->GameEntity::update();
   }
};

If you interested in the rest have a look at:
https://github.com/merlinblack/Game-Engine-Testbed/blob/master/include/gameentity.h<span onmouseout="cancel = false; window.setTimeout(WRCHideContent, 1000);" onmouseover="WRCShowContent({&#39;rating&#39;:{&#39;value&#39;:97,&#39;weight&#39;:71},&#39;flags&#39;:{&#39;it&#39;:1},&#39;ttl&#39;:3600,&#39;expireTime&#39;:&#39;20110706172910&#39;}, this.className);" class="wrc13" style="padding-right: 16px; width: 16px; height: 16px;">

This required a small change in wrapper_base.hpp on line 66 from

 private:
   wrapped_self_t m_self;

to

 protected:
   wrapped_self_t m_self;


This allows access to m_self in your wrapper class.  You might not even
need to recompile the library - how hacky is THAT! :-)

But there are bound to be better solutions, that probably do not require
changing Luabind. However this works for me. Perhaps the change to
wrapper_base.hpp might be considered for Luabind - or perhaps adding a
function along the lines of isValid() to wrap_base.

I really should figure out why doing an explicit garbage collection -
even several iterations - still did not prevent my crash....

Nigel


------------------------------------------------------------------------------
All of the data generated in your IT infrastructure is seriously valuable.
Why? It contains a definitive record of application performance, security
threats, fraudulent activity, and more. Splunk takes this data and makes
sense of it. IT sense. And common sense.
http://p.sf.net/sfu/splunk-d2d-c2<span onmouseout="cancel = false; window.setTimeout(WRCHideContent, 1000);" onmouseover="WRCShowContent({&#39;rating&#39;:{&#39;value&#39;:-1,&#39;weight&#39;:-1},&#39;flags&#39;:{},&#39;ttl&#39;:3600,&#39;expireTime&#39;:&#39;20110706172910&#39;}, this.className);" class="wrc0" style="padding-right: 16px; width: 16px; height: 16px;">
_______________________________________________
luabind-user mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/luabind-user<span onmouseout="cancel = false; window.setTimeout(WRCHideContent, 1000);" onmouseover="WRCShowContent({&#39;rating&#39;:{&#39;value&#39;:-1,&#39;weight&#39;:-1},&#39;flags&#39;:{},&#39;ttl&#39;:3600,&#39;expireTime&#39;:&#39;20110706123649&#39;}, this.className);" class="wrc0" style="padding-right: 16px; width: 16px; height: 16px;">



--
Drew McLean
Lead Tech Programmer
A Priori Games
(250) 508-3346
www.apriorigames.com<span onmouseout="cancel = false; window.setTimeout(WRCHideContent, 1000);" onmouseover="WRCShowContent({&#39;rating&#39;:{&#39;value&#39;:-1,&#39;weight&#39;:-1},&#39;flags&#39;:{},&#39;ttl&#39;:3600,&#39;expireTime&#39;:&#39;20110706123748&#39;}, this.className);" class="wrc0" style="padding-right: 16px; width: 16px; height: 16px;">


------------------------------------------------------------------------------
All of the data generated in your IT infrastructure is seriously valuable.
Why? It contains a definitive record of application performance, security
threats, fraudulent activity, and more. Splunk takes this data and makes
sense of it. IT sense. And common sense.
http://p.sf.net/sfu/splunk-d2d-c2
_______________________________________________
luabind-user mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/luabind-user
Reply | Threaded
Open this post in threaded view
|

Re: Crash in wrapper_base.cpp

Nigel Atkinson-2
On Wed, 2011-07-06 at 17:45 -0700, Drew McLean wrote:
> Hmmm, that's a possible crash workaround but I'm not sure it will help
> in my use case.  I think my scenario is a little different than yours
> since my object isn't supposed to be garbage collected at all because
> it hasn't been removed from my global Lua table.  It's almost like the
> garbage collection has erroneously chosen that instance to dispose of
> when it shouldn't have but also didn't call the finalizer.  I need my
> object to continue to function until I unregister it from the global
> Lua table.  This is why I think it's probably a Luabind bug as opposed
> to a usage bug.  
Ah I see, hmm.

Perhaps when you 'unregister' an object, could you be zapping the wrong
one (the one before, or the one after, etc)? Or perhaps if you do many
at once, your doing 1 too many?

Nigel


------------------------------------------------------------------------------
All of the data generated in your IT infrastructure is seriously valuable.
Why? It contains a definitive record of application performance, security
threats, fraudulent activity, and more. Splunk takes this data and makes
sense of it. IT sense. And common sense.
http://p.sf.net/sfu/splunk-d2d-c2
_______________________________________________
luabind-user mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/luabind-user
Reply | Threaded
Open this post in threaded view
|

Re: Crash in wrapper_base.cpp

Drew McLean
I don't think that's the case since I'm printing at the point where I unregister an object (in a common function).  And there is no loop where I release a bunch at once, they each complete in their own time.  My global table uses the object as the key and the value.  Is there something wrong with that?  I can't see why.

   Drew


On Wed, Jul 6, 2011 at 6:39 PM, Nigel Atkinson <[hidden email]> wrote:
On Wed, 2011-07-06 at 17:45 -0700, Drew McLean wrote:
> Hmmm, that's a possible crash workaround but I'm not sure it will help
> in my use case.  I think my scenario is a little different than yours
> since my object isn't supposed to be garbage collected at all because
> it hasn't been removed from my global Lua table.  It's almost like the
> garbage collection has erroneously chosen that instance to dispose of
> when it shouldn't have but also didn't call the finalizer.  I need my
> object to continue to function until I unregister it from the global
> Lua table.  This is why I think it's probably a Luabind bug as opposed
> to a usage bug.
Ah I see, hmm.

Perhaps when you 'unregister' an object, could you be zapping the wrong
one (the one before, or the one after, etc)? Or perhaps if you do many
at once, your doing 1 too many?

Nigel


------------------------------------------------------------------------------
All of the data generated in your IT infrastructure is seriously valuable.
Why? It contains a definitive record of application performance, security
threats, fraudulent activity, and more. Splunk takes this data and makes
sense of it. IT sense. And common sense.
http://p.sf.net/sfu/splunk-d2d-c2
_______________________________________________
luabind-user mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/luabind-user



--
Drew McLean
Lead Tech Programmer
A Priori Games
(250) 508-3346
www.apriorigames.com


------------------------------------------------------------------------------
All of the data generated in your IT infrastructure is seriously valuable.
Why? It contains a definitive record of application performance, security
threats, fraudulent activity, and more. Splunk takes this data and makes
sense of it. IT sense. And common sense.
http://p.sf.net/sfu/splunk-d2d-c2
_______________________________________________
luabind-user mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/luabind-user
Reply | Threaded
Open this post in threaded view
|

Re: Crash in wrapper_base.cpp

Nigel Atkinson-2
On Thu, 2011-07-07 at 11:44 -0700, Drew McLean wrote:
> I don't think that's the case since I'm printing at the point where I
> unregister an object (in a common function).  And there is no loop
> where I release a bunch at once, they each complete in their own time.
> My global table uses the object as the key and the value.  Is there
> something wrong with that?  I can't see why.
>
>    Drew
I can not think of any reason why using the object as a key would not
work either.

Just had a thought - are the objects that are incorrectly getting
garbage collected actually getting collected (and destructed?), or is it
just the reference held in wrap_base getting zapped?

The reason I say this - is because a made a test program to try and
replicate what is happening in my game, however garbage collecting an
object resulted in destruction and freeing of memory immediately.
Somehow in my game I'm getting to call 'update' when the wrap_base
reference is nil yet the object is still 'alive'.

I'm quite interested in what you may find - seeing as I have a similar
but not quite same problem.

Nigel


------------------------------------------------------------------------------
All of the data generated in your IT infrastructure is seriously valuable.
Why? It contains a definitive record of application performance, security
threats, fraudulent activity, and more. Splunk takes this data and makes
sense of it. IT sense. And common sense.
http://p.sf.net/sfu/splunk-d2d-c2
_______________________________________________
luabind-user mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/luabind-user
Reply | Threaded
Open this post in threaded view
|

Re: Crash in wrapper_base.cpp

Nigel Atkinson-2
On Fri, 2011-07-08 at 09:44 +1000, Nigel Atkinson wrote:

> On Thu, 2011-07-07 at 11:44 -0700, Drew McLean wrote:
> > I don't think that's the case since I'm printing at the point where I
> > unregister an object (in a common function).  And there is no loop
> > where I release a bunch at once, they each complete in their own time.
> > My global table uses the object as the key and the value.  Is there
> > something wrong with that?  I can't see why.
> >
> >    Drew
> I can not think of any reason why using the object as a key would not
> work either.

I made a test program and it worked as expected until I added using the
objects as keys in a table. :-/

Next question is 'why?'.  However it's Friday and nearly time to go to
the pub.

Attached is my test program - it requires changing line 66 in
wrapper_base.hpp from private to protected, so it can print an error
rather than asserting.

Nigel

------------------------------------------------------------------------------
All of the data generated in your IT infrastructure is seriously valuable.
Why? It contains a definitive record of application performance, security
threats, fraudulent activity, and more. Splunk takes this data and makes
sense of it. IT sense. And common sense.
http://p.sf.net/sfu/splunk-d2d-c2
_______________________________________________
luabind-user mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/luabind-user

smash.cpp (2K) Download Attachment
Reply | Threaded
Open this post in threaded view
|

Re: Crash in wrapper_base.cpp

Drew McLean
Hmmm, I tried running your sample code and I seem to be getting the same results each time.  What lines did you modify between tests?

I tried removing "  v[obj] = obj\n" and "  v[a[i]] = nil\n" for the run that doesn't use keys as indices.

Seems like using an object as a key is perfectly ok.

From http://www.lua.org/pil/17.2.html<span onmouseout="cancel = false; window.setTimeout(WRCHideContent, 1000);" onmouseover="WRCShowContent({&#39;rating&#39;:{&#39;value&#39;:100,&#39;weight&#39;:16},&#39;flags&#39;:{},&#39;ttl&#39;:3600,&#39;expireTime&#39;:&#39;20110708120201&#39;}, this.className);" class="wrc11" style="padding-right: 16px; width: 16px; height: 16px;">:

     Once we use an object as a key in a table, we lock the object into existence. Lua cannot collect an object that is being used as a key


    Drew


On Thu, Jul 7, 2011 at 11:36 PM, Nigel Atkinson <[hidden email]> wrote:
On Fri, 2011-07-08 at 09:44 +1000, Nigel Atkinson wrote:
> On Thu, 2011-07-07 at 11:44 -0700, Drew McLean wrote:
> > I don't think that's the case since I'm printing at the point where I
> > unregister an object (in a common function).  And there is no loop
> > where I release a bunch at once, they each complete in their own time.
> > My global table uses the object as the key and the value.  Is there
> > something wrong with that?  I can't see why.
> >
> >    Drew
> I can not think of any reason why using the object as a key would not
> work either.


I made a test program and it worked as expected until I added using the
objects as keys in a table. :-/

Next question is 'why?'.  However it's Friday and nearly time to go to
the pub.

Attached is my test program - it requires changing line 66 in
wrapper_base.hpp from private to protected, so it can print an error
rather than asserting.

Nigel

------------------------------------------------------------------------------
All of the data generated in your IT infrastructure is seriously valuable.
Why? It contains a definitive record of application performance, security
threats, fraudulent activity, and more. Splunk takes this data and makes
sense of it. IT sense. And common sense.
http://p.sf.net/sfu/splunk-d2d-c2<span onmouseout="cancel = false; window.setTimeout(WRCHideContent, 1000);" onmouseover="WRCShowContent({&#39;rating&#39;:{&#39;value&#39;:-1,&#39;weight&#39;:-1},&#39;flags&#39;:{},&#39;ttl&#39;:3600,&#39;expireTime&#39;:&#39;20110708120001&#39;}, this.className);" class="wrc0" style="padding-right: 16px; width: 16px; height: 16px;">
_______________________________________________
luabind-user mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/luabind-user<span onmouseout="cancel = false; window.setTimeout(WRCHideContent, 1000);" onmouseover="WRCShowContent({&#39;rating&#39;:{&#39;value&#39;:-1,&#39;weight&#39;:-1},&#39;flags&#39;:{},&#39;ttl&#39;:3600,&#39;expireTime&#39;:&#39;20110708120001&#39;}, this.className);" class="wrc0" style="padding-right: 16px; width: 16px; height: 16px;">




--
Drew McLean
Lead Tech Programmer
A Priori Games
<a href="tel:%28250%29%20508-3346" value="+12505083346" target="_blank">(250) 508-3346
www.apriorigames.com<span onmouseout="cancel = false; window.setTimeout(WRCHideContent, 1000);" onmouseover="WRCShowContent({&#39;rating&#39;:{&#39;value&#39;:-1,&#39;weight&#39;:-1},&#39;flags&#39;:{},&#39;ttl&#39;:3600,&#39;expireTime&#39;:&#39;20110708115441&#39;}, this.className);" class="wrc0" style="padding-right: 16px; width: 16px; height: 16px;">


------------------------------------------------------------------------------
All of the data generated in your IT infrastructure is seriously valuable.
Why? It contains a definitive record of application performance, security
threats, fraudulent activity, and more. Splunk takes this data and makes
sense of it. IT sense. And common sense.
http://p.sf.net/sfu/splunk-d2d-c2
_______________________________________________
luabind-user mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/luabind-user
Reply | Threaded
Open this post in threaded view
|

Re: Crash in wrapper_base.cpp

Nigel Atkinson-2
On Fri, 2011-07-08 at 12:22 -0700, Drew McLean wrote:
> Hmmm, I tried running your sample code and I seem to be getting the
> same results each time.  What lines did you modify between tests?
>
> I tried removing "  v[obj] = obj\n" and "  v[a[i]] = nil\n" for the
> run that doesn't use keys as indices.
>
> Seems like using an object as a key is perfectly ok.

For me removing those same lines stops the printing of "Lua instance is
nil".  Putting them back brings them back.  They do not happen after the
explicit garbage collection.

It might be that using an object as a key just makes the problem more
likely rather than being the problem itself.

It's as if the "nil'ed" objects are in a half collected state.  The weak
reference held by wrap_base has been set to nil, however the finalise
and destructor have not been run yet - or indeed C++'s delete.

What compiler/machine are you using?  It might be a good thing that we
are seeing different results - it might lead to the bug faster.

I'm using gcc 4.5.2 on Linux 64bit

Nigel


------------------------------------------------------------------------------
All of the data generated in your IT infrastructure is seriously valuable.
Why? It contains a definitive record of application performance, security
threats, fraudulent activity, and more. Splunk takes this data and makes
sense of it. IT sense. And common sense.
http://p.sf.net/sfu/splunk-d2d-c2
_______________________________________________
luabind-user mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/luabind-user
Reply | Threaded
Open this post in threaded view
|

Re: Crash in wrapper_base.cpp

Drew McLean
Ooops, seems like I messed up my previous runs of your sample code somehow.  I do indeed have different results for the different runs and have attached them for you.  I expect that they'll be the same as yours.  For reference, I'm using Visual Studio 2008 on Windows 7 x64 but I'm building a 32 bit binary.

More importantly though, I have come across 2 interesting observations.  I've been tinkering with your code and also the code in my engine and have found a possible workaround. 

First, in my engine, if I simply add the following push of self onto the stack before calling the lua function then no crash! 

        lua_State *L = m_self.state();
        m_self.get(L);
        call<void>("overide");

I find it weird that it didn't cause a stack overflow but I tried it many times and let it run for a long time with no observed side effects other than it seeming to be working correctly.

The second observation is that when I put the extra push of self onto the stack into your sample code before calling overide() it caused an assert.  After digging around I saw that you didn't provide a constructor for your lua class.  Adding that in made the assert go away and also got rid of the "Lua instance is nil" messages. 

        "function Item:__init(i)\n"
        "    print('lua constructor')\n"
        "end\n"

So it seems we may have stumbled upon a workaround if it deems to have no side effects although I'm not really comfortable with not knowing why it works.  Let me know what you find with your engine.

    Drew


------------------------------------------------------------------------------
All of the data generated in your IT infrastructure is seriously valuable.
Why? It contains a definitive record of application performance, security
threats, fraudulent activity, and more. Splunk takes this data and makes
sense of it. IT sense. And common sense.
http://p.sf.net/sfu/splunk-d2d-c2
_______________________________________________
luabind-user mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/luabind-user
Reply | Threaded
Open this post in threaded view
|

Re: Crash in wrapper_base.cpp

Drew McLean
Heh, I may have spoken too soon.  I think having that extra reference on the stack is preventing garbage collection of the items, even with an explicit collectgarbage() call.  Any guess at why there wasn't a stack overflow? 


On Sat, Jul 9, 2011 at 4:44 PM, Drew McLean <[hidden email]> wrote:
Ooops, seems like I messed up my previous runs of your sample code somehow.  I do indeed have different results for the different runs and have attached them for you.  I expect that they'll be the same as yours.  For reference, I'm using Visual Studio 2008 on Windows 7 x64 but I'm building a 32 bit binary.

More importantly though, I have come across 2 interesting observations.  I've been tinkering with your code and also the code in my engine and have found a possible workaround. 

First, in my engine, if I simply add the following push of self onto the stack before calling the lua function then no crash! 

        lua_State *L = m_self.state();
        m_self.get(L);
        call<void>("overide");

I find it weird that it didn't cause a stack overflow but I tried it many times and let it run for a long time with no observed side effects other than it seeming to be working correctly.

The second observation is that when I put the extra push of self onto the stack into your sample code before calling overide() it caused an assert.  After digging around I saw that you didn't provide a constructor for your lua class.  Adding that in made the assert go away and also got rid of the "Lua instance is nil" messages. 

        "function Item:__init(i)\n"
        "    print('lua constructor')\n"
        "end\n"

So it seems we may have stumbled upon a workaround if it deems to have no side effects although I'm not really comfortable with not knowing why it works.  Let me know what you find with your engine.

    Drew




--
Drew McLean
Lead Tech Programmer
A Priori Games
(250) 508-3346
www.apriorigames.com<span onmouseout="cancel = false; window.setTimeout(WRCHideContent, 1000);" onmouseover="WRCShowContent({&#39;rating&#39;:{&#39;value&#39;:-1,&#39;weight&#39;:-1},&#39;flags&#39;:{},&#39;ttl&#39;:3600,&#39;expireTime&#39;:&#39;20110709125755&#39;}, this.className);" class="wrc0" style="padding-right: 16px; width: 16px; height: 16px;">


------------------------------------------------------------------------------
All of the data generated in your IT infrastructure is seriously valuable.
Why? It contains a definitive record of application performance, security
threats, fraudulent activity, and more. Splunk takes this data and makes
sense of it. IT sense. And common sense.
http://p.sf.net/sfu/splunk-d2d-c2
_______________________________________________
luabind-user mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/luabind-user
Reply | Threaded
Open this post in threaded view
|

Re: Crash in wrapper_base.cpp

Nigel Atkinson-2
In reply to this post by Drew McLean
Not sure about why you didn't get a Lua stack overflow - where you
popping the extra off?  Perhaps luabind does.

Are you still getting the "wrong" objects disappearing in your game - I
forgot about that bit.  

Thinking about how wrap_base works, I think it holds a weak reference to
the object, so perhaps thats why it appears "nil" immediately after you
do something like "obj = nil".  That rules out using the finaliser or
destructor (as I'm doing) for unregistering the object in C++ land,
unless you make sure to collect garbage before calling any object
methods.  However collecting garbage didn't work for my game for some
reason that I'll have to get to the bottom of.

> First, in my engine, if I simply add the following push of self onto
> the stack before calling the lua function then no crash!  
>
>         lua_State *L = m_self.state();
>         m_self.get(L);
>         call<void>("overide");

That is strange - I'm pretty sure the call function calls m_self.get(L)
internally - so somehow having two on the stack makes things work?  What
is the value of whatever got pushed onto the Lua stack?  nil sometimes?

> I find it weird that it didn't cause a stack overflow but I tried it
> many times and let it run for a long time with no observed side
> effects other than it seeming to be working correctly.
>
> The second observation is that when I put the extra push of self onto
> the stack into your sample code before calling overide() it caused an
> assert.  After digging around I saw that you didn't provide a
> constructor for your lua class.  Adding that in made the assert go
> away and also got rid of the "Lua instance is nil" messages.  
>
>         "function Item:__init(i)\n"
>         "    print('lua constructor')\n"
>         "end\n"

That is weird  - there is a C++ constructor bound. And why is it
constructing objects anyway!?

> So it seems we may have stumbled upon a workaround if it deems to have
> no side effects although I'm not really comfortable with not knowing
> why it works.  Let me know what you find with your engine.
>
>     Drew




------------------------------------------------------------------------------
All of the data generated in your IT infrastructure is seriously valuable.
Why? It contains a definitive record of application performance, security
threats, fraudulent activity, and more. Splunk takes this data and makes
sense of it. IT sense. And common sense.
http://p.sf.net/sfu/splunk-d2d-c2
_______________________________________________
luabind-user mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/luabind-user
Reply | Threaded
Open this post in threaded view
|

Re: Crash in wrapper_base.cpp

Drew McLean
Not sure about why you didn't get a Lua stack overflow - where you
popping the extra off?  Perhaps luabind does.

Nope, I'm not popping the extra self off of the stack, luabind (or somebody else) must be doing it somewhere.

Are you still getting the "wrong" objects disappearing in your game - I
forgot about that bit.

Yep, I'm still having that behaviour.  I still can't figure out why.

That is strange - I'm pretty sure the call function calls m_self.get(L)
internally - so somehow having two on the stack makes things work?  What
is the value of whatever got pushed onto the Lua stack?  nil sometimes?

I think the self value is alright.  What seems to be happening is some sort of side effect that causes the self value to be referenced somewhere and prevents garbage collection until the VM shuts down.  Initially, I thought I fixed the problem with that extra push but after letting the game run for 10 mins and then quitting it took a while to shut down... it was collecting everything at that time and there were tons of objects. 
 
That is weird  - there is a C++ constructor bound. And why is it
constructing objects anyway!?

I think the lua constructor should be optional be it seems to cause different behaviour if absent.  I recall seeing something like this as a bug in another mail thread but I forget where.  You are creating 1000 instances of the lua Item class in you script which extends the C++ class.  I actually renamed the Lua class from Item to LuaItem to clear up that ambiguity. 

So I'm not sure where to go from here except to start debugging the Lua and Luabind code itself.  Is there any way of escalating the issue with Rasterbar?  Seems like a really tricky one and I'm low on time to delve into this sort of thing unless I really have to.

    Drew


------------------------------------------------------------------------------
All of the data generated in your IT infrastructure is seriously valuable.
Why? It contains a definitive record of application performance, security
threats, fraudulent activity, and more. Splunk takes this data and makes
sense of it. IT sense. And common sense.
http://p.sf.net/sfu/splunk-d2d-c2
_______________________________________________
luabind-user mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/luabind-user
Reply | Threaded
Open this post in threaded view
|

Re: Crash in wrapper_base.cpp

Drew McLean
Hey all,

I'm still investigating the problem with m_self becoming invalid after the game runs for a while.  Nigel has been helping me troubleshoot and we've eliminated several cases.  Here is a more detailed depiction of the scenario.


C++ class declarations:

class RTTI
class Agent : public RTTI
class ScriptableAgent : public Agent
struct ScriptableAgent_luabind : public ScriptableAgent, public luabind::wrap_base


C++ class bindings to lua:

class_< apg::RTTI >("RTTI")
   ...
class_< apg::Agent, apg::RTTI  >("Agent")
   ...
class_< apg::ScriptableAgent, apg::ScriptableAgent_luabind, bases<apg::Agent, apg::RTTI> >("ScriptableAgent")
   ...


Lua code to create/destroy lua class instances:

g_LuaAgents = {}


function createScriptableAgent(klass, ...)
    -- create the agent
    local agent = _G[klass]( getContextPool(), 0 )
    agent:initialize(unpack(arg))
    agent.name = klass .. agent.actorId
   
    -- track the agent so it won't be garbage collected
    assert(g_LuaAgents[agent.actorId] == nil)
    g_LuaAgents[agent.actorId] = agent
   
    if APG_DEBUG then
        print('Registered lua agent: ' .. tostring(agent.actorId) .. '\n')
    end   
    getContextPool().agentContainer:addAgent(agent)
   
    return agent   
end

function destroyScriptableAgent(agent)
    if agent ~= nil then
        agent:cleanup()
        if APG_DEBUG then
            print('Unregistering lua agent: ' .. tostring(agent.actorId) .. '\n')
        end
   
        -- remove the reference to the agent so it can be garbage collected
        assert(agent ~= nil)
        assert(g_LuaAgents[agent.actorId] == agent)
        g_LuaAgents[agent.actorId] = nil   
    end
end



Here is the lua code that extends the C++ class:

class 'TubeTravelSequenceAgent' (ScriptableAgent)

function TubeTravelSequenceAgent:__init(contextPool, aid)
    ScriptableAgent.__init(self, contextPool, aid)
end

function TubeTravelSequenceAgent:__finalize()
     print('TubeTravelSequenceAgent:__finalize() [' .. tostring(self.actorId) .. ']\n')
end

function TubeTravelSequenceAgent:initialize()
    ScriptableAgent.initialize(self)
    ...
end

function TubeTravelSequenceAgent:update(delta)
    ScriptableAgent.update(self, delta)
    if ... then
       
self.contextPool.agentContainer:destroyAgent(self)
    end
end


The TubeTravelSequenceAgent instance is created in Lua by calling createScriptableAgent which creates the instance, adds it to the global lua table so it won't be garbage collected and then adds it to the AgentContainer in C++ which is essentially a list of objects which has update() called on them every frame.

The instance is updated every frame until it decides that it should be destroyed in which case it calls AgentContainer.destroyAgent() which will in turn remove the instance from the internal list and call the Lua function destroyScriptableAgent() with the instance as the parameter.  This function removes the instance from the global table and allows it to be garbage collected.


C++ code catching the error:

void ScriptableEntity_luabind::Update(real delta)
{
    lua_State *L = m_self.state();
    m_self.get(L);
    void* pData = lua_touserdata(L, 1);
    luabind::detail::object_rep* instance = static_cast<luabind::detail::object_rep*>(pData);
    luabind::detail::class_rep* crep = instance ? instance->crep() : NULL;
    lua_pop(L,1);

    if (!instance)
    {
        luabind::object g_LuaAgents = luabind::globals(L)["g_LuaAgents"];
        luabind::object actor = g_LuaAgents[m_ActorId];
        ASSERT(luabind::type(actor) != LUA_TNIL);

        apg::Agent* pMe = luabind::object_cast<apg::Agent*>(actor);
        ASSERT(pMe == this);
    }

    call<void>("update", delta);
}


Above is the code in the wrapped Update() function which calls into the Lua-derived class.  I added a bunch of error checking code to examine the m_self reference for the instance.  When the problem occurs the code will enter into the if block where I do some sanity checking. So what I'm seeing is that pData is NULL which  means the userdata is NULL. Then when I dig into the Lua global table holding all the agent references I see that the entry is still there and pointing to the correct Agent (which is this). So the question is who is clearing the userdata to NULL? It shouldn't be a garbage collection.  Does this look like slicing?

I'm personally suspecting a bug outside of my own code.  Any help anyone can give would be greatly appreciated. 

   Drew



------------------------------------------------------------------------------
BlackBerry&reg; DevCon Americas, Oct. 18-20, San Francisco, CA
The must-attend event for mobile developers. Connect with experts.
Get tools for creating Super Apps. See the latest technologies.
Sessions, hands-on labs, demos & much more. Register early & save!
http://p.sf.net/sfu/rim-blackberry-1
_______________________________________________
luabind-user mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/luabind-user