cppbind: fix possible usage of expired object from Nasal

This commit is contained in:
Thomas Geymayer
2014-03-11 15:36:57 +01:00
parent f40efe66fa
commit b2d9385f46
3 changed files with 100 additions and 17 deletions

View File

@@ -24,6 +24,8 @@
#include "NasalObjectHolder.hxx"
#include <simgear/debug/logstream.hxx>
#include <simgear/structure/SGWeakReferenced.hxx>
#include <simgear/structure/SGWeakPtr.hxx>
#include <boost/bind.hpp>
#include <boost/call_traits.hpp>
@@ -121,20 +123,21 @@ namespace nasal
/**
* Hold callable method and convert to Nasal function if required.
*/
class MethodHolder
class MethodHolder:
public SGWeakReferenced
{
public:
virtual ~MethodHolder() {}
naRef get_naRef(naContext c)
{
if( !_obj )
_obj = ObjectHolder::makeShared(createNasalObject(c));
return _obj->get_naRef();
if( !_obj.valid() )
_obj.reset(createNasalObject(c));
return _obj.get_naRef();
}
protected:
ObjectHolderRef _obj;
ObjectHolder _obj;
virtual naRef createNasalObject(naContext c) = 0;
};
@@ -155,6 +158,9 @@ namespace nasal
{};
}
typedef SGSharedPtr<internal::MethodHolder> MethodHolderPtr;
typedef SGWeakPtr<internal::MethodHolder> MethodHolderWeakPtr;
/**
* Class for exposing C++ objects to Nasal
*
@@ -208,7 +214,6 @@ namespace nasal
typedef boost::function<naRef(naContext, raw_type&)> getter_t;
typedef boost::function<void(naContext, raw_type&, naRef)> setter_t;
typedef boost::function<naRef(raw_type&, const CallContext&)> method_t;
typedef boost::shared_ptr<internal::MethodHolder> MethodHolderPtr;
class MethodHolder:
public internal::MethodHolder
@@ -219,11 +224,27 @@ namespace nasal
{}
protected:
typedef SGSharedPtr<MethodHolder> SharedPtr;
typedef SGWeakPtr<MethodHolder> WeakPtr;
method_t _method;
virtual naRef createNasalObject(naContext c)
{
return naNewFunc(c, naNewCCodeU(c, &MethodHolder::call, this));
return naNewFunc
(
c,
naNewCCodeUD( c,
&MethodHolder::call,
new WeakPtr(this),
&destroyHolder )
);
}
static void destroyHolder(void* user_data)
{
delete static_cast<WeakPtr*>(user_data);
}
static naRef call( naContext c,
@@ -232,12 +253,16 @@ namespace nasal
naRef* args,
void* user_data )
{
MethodHolder* holder = static_cast<MethodHolder*>(user_data);
if( !holder )
WeakPtr* holder_weak = static_cast<WeakPtr*>(user_data);
if( !holder_weak )
naRuntimeError(c, "invalid method holder!");
try
{
SharedPtr holder = holder_weak->lock();
if( !holder )
throw std::runtime_error("holder has expired");
return holder->_method
(
requireObject(c, me),
@@ -490,7 +515,7 @@ namespace nasal
*/
Ghost& method(const std::string& name, const method_t& func)
{
_members[name].func.reset( new MethodHolder(func) );
_members[name].func = new MethodHolder(func);
return *this;
}

View File

@@ -25,7 +25,8 @@ namespace nasal
//----------------------------------------------------------------------------
ObjectHolder::~ObjectHolder()
{
naGCRelease(_gc_key);
if( !naIsNil(_ref) )
naGCRelease(_gc_key);
}
//----------------------------------------------------------------------------
@@ -34,6 +35,32 @@ namespace nasal
return _ref;
}
//----------------------------------------------------------------------------
void ObjectHolder::reset()
{
if( !naIsNil(_ref) )
naGCRelease(_gc_key);
_ref = naNil();
_gc_key = 0;
}
//----------------------------------------------------------------------------
void ObjectHolder::reset(naRef obj)
{
if( !naIsNil(_ref) )
naGCRelease(_gc_key);
_ref = obj;
_gc_key = naGCSave(obj);
}
//----------------------------------------------------------------------------
bool ObjectHolder::valid() const
{
return !naIsNil(_ref);
}
//----------------------------------------------------------------------------
ObjectHolderRef ObjectHolder::makeShared(naRef obj)
{
@@ -43,7 +70,16 @@ namespace nasal
//----------------------------------------------------------------------------
ObjectHolder::ObjectHolder(naRef obj):
_ref(obj),
_gc_key(naGCSave(obj))
_gc_key(0)
{
if( !naIsNil(obj) )
naGCSave(obj);
}
//----------------------------------------------------------------------------
ObjectHolder::ObjectHolder():
_ref(naNil()),
_gc_key(0)
{
}

View File

@@ -37,6 +37,16 @@ namespace nasal
{
public:
/**
* @param obj Object to save
*/
explicit ObjectHolder(naRef obj);
/**
*
*/
ObjectHolder();
/**
*
*/
@@ -47,6 +57,23 @@ namespace nasal
*/
naRef get_naRef() const;
/**
* Release the managed object
*/
void reset();
/**
* Replaces the managed object (the old object is released)
*
* @param obj New object to save
*/
void reset(naRef obj);
/**
* Check if there is a managed object
*/
bool valid() const;
/**
* Save the given object as long as the returned holder exists.
*
@@ -57,11 +84,6 @@ namespace nasal
protected:
naRef _ref;
int _gc_key;
/**
* @param obj Object to save
*/
ObjectHolder(naRef obj);
};
} // namespace nasal