Dangling pointers Lua style...

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

Dangling pointers Lua style...

Nigel Atkinson-2
Consider a bound class without a bound constructor.  Instead elsewhere
there is a bound function to create and another to destroy.

Used something like this...

obj = CreateObject()

-- use the obj

DestroyObject( obj )

The destroy might do more, but ultimately deletes the object.  Problem
is in Lua, we now have a dangling pointer!  obj after the destroy call
still points somewhere, and if you accidentally use it bad things
happen.  Not good if the Lua scripts are from the end user.  They can't
be expected to write "obj = nil" after each call. :)

So how to automatically set obj to nil after a destroy call?

My thoughts lean towards “All problems in computer science can be solved
by another level of indirection”

In this case some sort of smart/auto pointer, and wrapper functions that
throw exceptions if the passed pointer points to bad data?

What are everyone's thoughts?  I have the feeling I've missed some
obvious answer.


------------------------------------------------------------------------------
Start uncovering the many advantages of virtual appliances
and start using them to simplify application deployment and
accelerate your shift to cloud computing.
http://p.sf.net/sfu/novell-sfdev2dev
_______________________________________________
luabind-user mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/luabind-user
Reply | Threaded
Open this post in threaded view
|

Re: Dangling pointers Lua style...

Evan Wies-2
You can try wrapping the Create/Destroy in a proxy class that uses
constructors/destructors instead?  It depends on how pervasive this
idiom is in your code.  From there, Luabind is pretty flexible with how
you can bind arbitrary functions to classes.

If you want to explicitly control lifetimes, check out how Corona deals
with a similar problem:
http://developer.anscamobile.com/content/application-programming-guide-graphics-and-drawing#Removing_Objects_Properly

-Evan


On 09/30/2010 09:28 AM, Nigel Atkinson wrote:

> Consider a bound class without a bound constructor.  Instead elsewhere
> there is a bound function to create and another to destroy.
>
> Used something like this...
>
> obj = CreateObject()
>
> -- use the obj
>
> DestroyObject( obj )
>
> The destroy might do more, but ultimately deletes the object.  Problem
> is in Lua, we now have a dangling pointer!  obj after the destroy call
> still points somewhere, and if you accidentally use it bad things
> happen.  Not good if the Lua scripts are from the end user.  They can't
> be expected to write "obj = nil" after each call. :)
>
> So how to automatically set obj to nil after a destroy call?
>
> My thoughts lean towards “All problems in computer science can be solved
> by another level of indirection”
>
> In this case some sort of smart/auto pointer, and wrapper functions that
> throw exceptions if the passed pointer points to bad data?
>
> What are everyone's thoughts?  I have the feeling I've missed some
> obvious answer.
>
>
> ------------------------------------------------------------------------------
> Start uncovering the many advantages of virtual appliances
> and start using them to simplify application deployment and
> accelerate your shift to cloud computing.
> http://p.sf.net/sfu/novell-sfdev2dev
> _______________________________________________
> luabind-user mailing list
> [hidden email]
> https://lists.sourceforge.net/lists/listinfo/luabind-user



------------------------------------------------------------------------------
Start uncovering the many advantages of virtual appliances
and start using them to simplify application deployment and
accelerate your shift to cloud computing.
http://p.sf.net/sfu/novell-sfdev2dev
_______________________________________________
luabind-user mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/luabind-user
Reply | Threaded
Open this post in threaded view
|

Re: Dangling pointers Lua style...

Nigel Atkinson-2
Yes, that would work. Thank you.  

I was trying to think of a generic solution, such as some sort of
"ward_ptr" that threw an exception on getPointer() if it was invalid.
However the problem is - how would such a class "know" when the pointer
it contains has been free'd.  It probably could be done via, heap
debugging functions or some such, but that's just yuck. (Slow,
non-portable, etc)

A wrapper class it is methinks!  But hang on moment...
would this work??  How clever is Luabind about this...

void Destroy( ward_ptr<myclass> ptr )
{
        ptr->Destroy();
        ptr.invalidate();
}

class_<myclass, ward_ptr>("myclass")
[
        .def("Create", MakeOne ) // MakeOne would return a myclass*
        bla bla bla
        .def("Destroy", Destroy )
]

Hmmmmm.

Nigel

On Thu, 2010-09-30 at 13:17 -0400, Evan Wies wrote:

> You can try wrapping the Create/Destroy in a proxy class that uses
> constructors/destructors instead?  It depends on how pervasive this
> idiom is in your code.  From there, Luabind is pretty flexible with how
> you can bind arbitrary functions to classes.
>
> If you want to explicitly control lifetimes, check out how Corona deals
> with a similar problem:
> http://developer.anscamobile.com/content/application-programming-guide-graphics-and-drawing#Removing_Objects_Properly
>
> -Evan
>
>
> On 09/30/2010 09:28 AM, Nigel Atkinson wrote:
> > Consider a bound class without a bound constructor.  Instead elsewhere
> > there is a bound function to create and another to destroy.
> >
> > Used something like this...
> >
> > obj = CreateObject()
> >
> > -- use the obj
> >
> > DestroyObject( obj )
> >
> > The destroy might do more, but ultimately deletes the object.  Problem
> > is in Lua, we now have a dangling pointer!  obj after the destroy call
> > still points somewhere, and if you accidentally use it bad things
> > happen.  Not good if the Lua scripts are from the end user.  They can't
> > be expected to write "obj = nil" after each call. :)
> >
> > So how to automatically set obj to nil after a destroy call?
> >
> > My thoughts lean towards “All problems in computer science can be solved
> > by another level of indirection”
> >
> > In this case some sort of smart/auto pointer, and wrapper functions that
> > throw exceptions if the passed pointer points to bad data?
> >
> > What are everyone's thoughts?  I have the feeling I've missed some
> > obvious answer.
> >
> >
> > ------------------------------------------------------------------------------
> > Start uncovering the many advantages of virtual appliances
> > and start using them to simplify application deployment and
> > accelerate your shift to cloud computing.
> > http://p.sf.net/sfu/novell-sfdev2dev
> > _______________________________________________
> > luabind-user mailing list
> > [hidden email]
> > https://lists.sourceforge.net/lists/listinfo/luabind-user
>
>
>
> ------------------------------------------------------------------------------
> Start uncovering the many advantages of virtual appliances
> and start using them to simplify application deployment and
> accelerate your shift to cloud computing.
> http://p.sf.net/sfu/novell-sfdev2dev
> _______________________________________________
> luabind-user mailing list
> [hidden email]
> https://lists.sourceforge.net/lists/listinfo/luabind-user



------------------------------------------------------------------------------
Start uncovering the many advantages of virtual appliances
and start using them to simplify application deployment and
accelerate your shift to cloud computing.
http://p.sf.net/sfu/novell-sfdev2dev
_______________________________________________
luabind-user mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/luabind-user
Reply | Threaded
Open this post in threaded view
|

Re: Dangling pointers Lua style...

eduard mueller
We had the same problem: access to dead objects from within Lua should
always cleanly fire Lua errors instead of crashing. We ended up in
using our own weak_ptr impl to solve this. If there are more elegant
solutions to solve this problem (invalidating all refs in Lua as soon
as the C++ object dies for example), I would also be very interested
to hear about this.

Our weak ptr basically works like:

===

/* baseclass for something a WeakPtr can point to */

class WeakReferenceable
{
public:
  virtual ~WeakReferenceable()
  {
    // Invalidate all weakptrs that point to "this" (accesses a static map
    // of all registered WeakReferenceables)
    WeakPtrBase::WeakRefDying(this);
  }
};


/* non templated baseclass for a WeakPtr */

class WeakPtrBase
{
public:
  WeakPtrBase(WeakReferenceable* ptr)
    : _weak_ptr(ptr)
  {
    // keep track of WeakPtrBase <-> Weakreferenceable links in a static map
    RegisterWeakRef(this, ptr);
  }

  ~WeakPtrBase()
  {
    // get rid of WeakPtrBase <-> Weakreferenceable links in the static map
    UnregisterWeakRef(this, _weak_ptr);
  }

protected:
  virtual void WeakReferenceableDying() = 0;
};

===

/* final weak ptr impl. Guaranteed to point to NULL or a valid
   object. Can only wrap WeakReferenceable's  */

template <class Class>
class WeakPtr
{
public:
  WeakPtr(Class* ptr)
    : WeakPtrBase(ptr),
     _class_ptr(ptr) { }

private:
  virtual void WeakReferenceableDying()
  {
     // invalidate our pointer to the deleted object
     _class_ptr = NULL;
  }

  // ptr access, copy and stuff...
};


====

Then in luabind:

// hold objects in WeakPtrs always:

class MyClass : public Weakreferenceable { }

class_<MyClass , WeakPtr<MyClass> >("myclass")

// pointer access from luabind can now deal with NULL pointers

template<class T>
T* get_pointer(WeakPtr<T> const& Ptr)
{
  if (Ptr.Object() == NULL)
  {
    throw std::logic_error("trying to access an object which is not or
no longer available.");
  }

  return Ptr.Object();
}

===

get_pointer above assumes that accessing a NULL WeakPtr is an error.
If you want to allow NULL access, then this of course can't make the
Lua objects nil. You would have to add an extra function, like i.g:
is_ptr_valid(WeakPtr<T>) to check for NULL in Lua...

Hope it helps. Let me know if you are interested in the complete impl...

Greets,
Eduard



On Fri, Oct 1, 2010 at 00:52, Nigel Atkinson <[hidden email]> wrote:

> Yes, that would work. Thank you.
>
> I was trying to think of a generic solution, such as some sort of
> "ward_ptr" that threw an exception on getPointer() if it was invalid.
> However the problem is - how would such a class "know" when the pointer
> it contains has been free'd.  It probably could be done via, heap
> debugging functions or some such, but that's just yuck. (Slow,
> non-portable, etc)
>
> A wrapper class it is methinks!  But hang on moment...
> would this work??  How clever is Luabind about this...
>
> void Destroy( ward_ptr<myclass> ptr )
> {
>        ptr->Destroy();
>        ptr.invalidate();
> }
>
> class_<myclass, ward_ptr>("myclass")
> [
>        .def("Create", MakeOne ) // MakeOne would return a myclass*
>        bla bla bla
>        .def("Destroy", Destroy )
> ]
>
> Hmmmmm.
>
> Nigel
>
> On Thu, 2010-09-30 at 13:17 -0400, Evan Wies wrote:
>> You can try wrapping the Create/Destroy in a proxy class that uses
>> constructors/destructors instead?  It depends on how pervasive this
>> idiom is in your code.  From there, Luabind is pretty flexible with how
>> you can bind arbitrary functions to classes.
>>
>> If you want to explicitly control lifetimes, check out how Corona deals
>> with a similar problem:
>> http://developer.anscamobile.com/content/application-programming-guide-graphics-and-drawing#Removing_Objects_Properly
>>
>> -Evan
>>
>>
>> On 09/30/2010 09:28 AM, Nigel Atkinson wrote:
>> > Consider a bound class without a bound constructor.  Instead elsewhere
>> > there is a bound function to create and another to destroy.
>> >
>> > Used something like this...
>> >
>> > obj = CreateObject()
>> >
>> > -- use the obj
>> >
>> > DestroyObject( obj )
>> >
>> > The destroy might do more, but ultimately deletes the object.  Problem
>> > is in Lua, we now have a dangling pointer!  obj after the destroy call
>> > still points somewhere, and if you accidentally use it bad things
>> > happen.  Not good if the Lua scripts are from the end user.  They can't
>> > be expected to write "obj = nil" after each call. :)
>> >
>> > So how to automatically set obj to nil after a destroy call?
>> >
>> > My thoughts lean towards “All problems in computer science can be solved
>> > by another level of indirection”
>> >
>> > In this case some sort of smart/auto pointer, and wrapper functions that
>> > throw exceptions if the passed pointer points to bad data?
>> >
>> > What are everyone's thoughts?  I have the feeling I've missed some
>> > obvious answer.
>> >
>> >
>> > ------------------------------------------------------------------------------
>> > Start uncovering the many advantages of virtual appliances
>> > and start using them to simplify application deployment and
>> > accelerate your shift to cloud computing.
>> > http://p.sf.net/sfu/novell-sfdev2dev
>> > _______________________________________________
>> > luabind-user mailing list
>> > [hidden email]
>> > https://lists.sourceforge.net/lists/listinfo/luabind-user
>>
>>
>>
>> ------------------------------------------------------------------------------
>> Start uncovering the many advantages of virtual appliances
>> and start using them to simplify application deployment and
>> accelerate your shift to cloud computing.
>> http://p.sf.net/sfu/novell-sfdev2dev
>> _______________________________________________
>> luabind-user mailing list
>> [hidden email]
>> https://lists.sourceforge.net/lists/listinfo/luabind-user
>
>
>
> ------------------------------------------------------------------------------
> Start uncovering the many advantages of virtual appliances
> and start using them to simplify application deployment and
> accelerate your shift to cloud computing.
> http://p.sf.net/sfu/novell-sfdev2dev
> _______________________________________________
> luabind-user mailing list
> [hidden email]
> https://lists.sourceforge.net/lists/listinfo/luabind-user
>

------------------------------------------------------------------------------
Start uncovering the many advantages of virtual appliances
and start using them to simplify application deployment and
accelerate your shift to cloud computing.
http://p.sf.net/sfu/novell-sfdev2dev
_______________________________________________
luabind-user mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/luabind-user
Reply | Threaded
Open this post in threaded view
|

Re: Dangling pointers Lua style...

Nigel Atkinson-2
Ah ha! Eduard Mueller, you have inspired me to my own solution!  

Well I'm still testing however.... ;-)

I quite like the look of your solution too.  It works similarly but
different!

Mine basically involves a smart pointer that throws on accessing a null
pointer.  It does not look after the lifetime of the pointed to object
however - which is what I wanted.

This is enabled by two wrapper funcs around the normal API supplied
Create and Destroy functions.  The former stuffs the pointer from the
API Create into a ward_ptr, and the later marks the ward_ptr as
'invalid' after invoking the normal API Destroy.

A difference is there is no deriving from classes.

Code and my test use are attached.  If you see any holes -  please tell
me! ;-) I had to do some double indirection as the ward_ptr's get copied
around (a lot!), and changes (i.e. invalidation) had to affect all that
where pointing in the same direction. :-)  I might change the heap
allocs to use a stl container perhaps... they might get fragmenty after
a bit of use.

Nigel

On Fri, 2010-10-01 at 01:58 +0200, eduard mueller wrote:

> We had the same problem: access to dead objects from within Lua should
> always cleanly fire Lua errors instead of crashing. We ended up in
> using our own weak_ptr impl to solve this. If there are more elegant
> solutions to solve this problem (invalidating all refs in Lua as soon
> as the C++ object dies for example), I would also be very interested
> to hear about this.
>
> Our weak ptr basically works like:
>
> ===
>
> /* baseclass for something a WeakPtr can point to */
>
> class WeakReferenceable
> {
> public:
>   virtual ~WeakReferenceable()
>   {
>     // Invalidate all weakptrs that point to "this" (accesses a static map
>     // of all registered WeakReferenceables)
>     WeakPtrBase::WeakRefDying(this);
>   }
> };
>
>
> /* non templated baseclass for a WeakPtr */
>
> class WeakPtrBase
> {
> public:
>   WeakPtrBase(WeakReferenceable* ptr)
>     : _weak_ptr(ptr)
>   {
>     // keep track of WeakPtrBase <-> Weakreferenceable links in a static map
>     RegisterWeakRef(this, ptr);
>   }
>
>   ~WeakPtrBase()
>   {
>     // get rid of WeakPtrBase <-> Weakreferenceable links in the static map
>     UnregisterWeakRef(this, _weak_ptr);
>   }
>
> protected:
>   virtual void WeakReferenceableDying() = 0;
> };
>
> ===
>
> /* final weak ptr impl. Guaranteed to point to NULL or a valid
>    object. Can only wrap WeakReferenceable's  */
>
> template <class Class>
> class WeakPtr
> {
> public:
>   WeakPtr(Class* ptr)
>     : WeakPtrBase(ptr),
>      _class_ptr(ptr) { }
>
> private:
>   virtual void WeakReferenceableDying()
>   {
>      // invalidate our pointer to the deleted object
>      _class_ptr = NULL;
>   }
>
>   // ptr access, copy and stuff...
> };
>
>
> ====
>
> Then in luabind:
>
> // hold objects in WeakPtrs always:
>
> class MyClass : public Weakreferenceable { }
>
> class_<MyClass , WeakPtr<MyClass> >("myclass")
>
> // pointer access from luabind can now deal with NULL pointers
>
> template<class T>
> T* get_pointer(WeakPtr<T> const& Ptr)
> {
>   if (Ptr.Object() == NULL)
>   {
>     throw std::logic_error("trying to access an object which is not or
> no longer available.");
>   }
>
>   return Ptr.Object();
> }
>
> ===
>
> get_pointer above assumes that accessing a NULL WeakPtr is an error.
> If you want to allow NULL access, then this of course can't make the
> Lua objects nil. You would have to add an extra function, like i.g:
> is_ptr_valid(WeakPtr<T>) to check for NULL in Lua...
>
> Hope it helps. Let me know if you are interested in the complete impl...
>
> Greets,
> Eduard
>
>
>
> On Fri, Oct 1, 2010 at 00:52, Nigel Atkinson <[hidden email]> wrote:
> > Yes, that would work. Thank you.
> >
> > I was trying to think of a generic solution, such as some sort of
> > "ward_ptr" that threw an exception on getPointer() if it was invalid.
> > However the problem is - how would such a class "know" when the pointer
> > it contains has been free'd.  It probably could be done via, heap
> > debugging functions or some such, but that's just yuck. (Slow,
> > non-portable, etc)
> >
> > A wrapper class it is methinks!  But hang on moment...
> > would this work??  How clever is Luabind about this...
> >
> > void Destroy( ward_ptr<myclass> ptr )
> > {
> >        ptr->Destroy();
> >        ptr.invalidate();
> > }
> >
> > class_<myclass, ward_ptr>("myclass")
> > [
> >        .def("Create", MakeOne ) // MakeOne would return a myclass*
> >        bla bla bla
> >        .def("Destroy", Destroy )
> > ]
> >
> > Hmmmmm.
> >
> > Nigel
> >
> > On Thu, 2010-09-30 at 13:17 -0400, Evan Wies wrote:
> >> You can try wrapping the Create/Destroy in a proxy class that uses
> >> constructors/destructors instead?  It depends on how pervasive this
> >> idiom is in your code.  From there, Luabind is pretty flexible with how
> >> you can bind arbitrary functions to classes.
> >>
> >> If you want to explicitly control lifetimes, check out how Corona deals
> >> with a similar problem:
> >> http://developer.anscamobile.com/content/application-programming-guide-graphics-and-drawing#Removing_Objects_Properly
> >>
> >> -Evan
> >>
> >>
> >> On 09/30/2010 09:28 AM, Nigel Atkinson wrote:
> >> > Consider a bound class without a bound constructor.  Instead elsewhere
> >> > there is a bound function to create and another to destroy.
> >> >
> >> > Used something like this...
> >> >
> >> > obj = CreateObject()
> >> >
> >> > -- use the obj
> >> >
> >> > DestroyObject( obj )
> >> >
> >> > The destroy might do more, but ultimately deletes the object.  Problem
> >> > is in Lua, we now have a dangling pointer!  obj after the destroy call
> >> > still points somewhere, and if you accidentally use it bad things
> >> > happen.  Not good if the Lua scripts are from the end user.  They can't
> >> > be expected to write "obj = nil" after each call. :)
> >> >
> >> > So how to automatically set obj to nil after a destroy call?
> >> >
> >> > My thoughts lean towards “All problems in computer science can be solved
> >> > by another level of indirection”
> >> >
> >> > In this case some sort of smart/auto pointer, and wrapper functions that
> >> > throw exceptions if the passed pointer points to bad data?
> >> >
> >> > What are everyone's thoughts?  I have the feeling I've missed some
> >> > obvious answer.
> >> >
> >> >
> >> > ------------------------------------------------------------------------------
> >> > Start uncovering the many advantages of virtual appliances
> >> > and start using them to simplify application deployment and
> >> > accelerate your shift to cloud computing.
> >> > http://p.sf.net/sfu/novell-sfdev2dev
> >> > _______________________________________________
> >> > luabind-user mailing list
> >> > [hidden email]
> >> > https://lists.sourceforge.net/lists/listinfo/luabind-user
> >>
> >>
> >>
> >> ------------------------------------------------------------------------------
> >> Start uncovering the many advantages of virtual appliances
> >> and start using them to simplify application deployment and
> >> accelerate your shift to cloud computing.
> >> http://p.sf.net/sfu/novell-sfdev2dev
> >> _______________________________________________
> >> luabind-user mailing list
> >> [hidden email]
> >> https://lists.sourceforge.net/lists/listinfo/luabind-user
> >
> >
> >
> > ------------------------------------------------------------------------------
> > Start uncovering the many advantages of virtual appliances
> > and start using them to simplify application deployment and
> > accelerate your shift to cloud computing.
> > http://p.sf.net/sfu/novell-sfdev2dev
> > _______________________________________________
> > luabind-user mailing list
> > [hidden email]
> > https://lists.sourceforge.net/lists/listinfo/luabind-user
> >
>
> ------------------------------------------------------------------------------
> Start uncovering the many advantages of virtual appliances
> and start using them to simplify application deployment and
> accelerate your shift to cloud computing.
> http://p.sf.net/sfu/novell-sfdev2dev
> _______________________________________________
> luabind-user mailing list
> [hidden email]
> https://lists.sourceforge.net/lists/listinfo/luabind-user

------------------------------------------------------------------------------
Start uncovering the many advantages of virtual appliances
and start using them to simplify application deployment and
accelerate your shift to cloud computing.
http://p.sf.net/sfu/novell-sfdev2dev
_______________________________________________
luabind-user mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/luabind-user

main.cpp (1K) Download Attachment
ward_ptr.hpp (2K) Download Attachment