cppbind: fix possible usage of expired object from Nasal
This commit is contained in:
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user