From: Thomas Geymayer Date: Tue, 11 Mar 2014 14:36:57 +0000 (+0100) Subject: cppbind: fix possible usage of expired object from Nasal X-Git-Url: https://git.mxchange.org/?a=commitdiff_plain;h=b2d9385f467acf8ac6b93cdac0c72370f6aca842;p=simgear.git cppbind: fix possible usage of expired object from Nasal --- diff --git a/simgear/nasal/cppbind/Ghost.hxx b/simgear/nasal/cppbind/Ghost.hxx index b52f825e..6bde8679 100644 --- a/simgear/nasal/cppbind/Ghost.hxx +++ b/simgear/nasal/cppbind/Ghost.hxx @@ -24,6 +24,8 @@ #include "NasalObjectHolder.hxx" #include +#include +#include #include #include @@ -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 MethodHolderPtr; + typedef SGWeakPtr MethodHolderWeakPtr; + /** * Class for exposing C++ objects to Nasal * @@ -208,7 +214,6 @@ namespace nasal typedef boost::function getter_t; typedef boost::function setter_t; typedef boost::function method_t; - typedef boost::shared_ptr MethodHolderPtr; class MethodHolder: public internal::MethodHolder @@ -219,11 +224,27 @@ namespace nasal {} protected: + + typedef SGSharedPtr SharedPtr; + typedef SGWeakPtr 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(user_data); } static naRef call( naContext c, @@ -232,12 +253,16 @@ namespace nasal naRef* args, void* user_data ) { - MethodHolder* holder = static_cast(user_data); - if( !holder ) + WeakPtr* holder_weak = static_cast(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; } diff --git a/simgear/nasal/cppbind/NasalObjectHolder.cxx b/simgear/nasal/cppbind/NasalObjectHolder.cxx index e2f190b0..45e929ec 100644 --- a/simgear/nasal/cppbind/NasalObjectHolder.cxx +++ b/simgear/nasal/cppbind/NasalObjectHolder.cxx @@ -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) { } diff --git a/simgear/nasal/cppbind/NasalObjectHolder.hxx b/simgear/nasal/cppbind/NasalObjectHolder.hxx index 47b13d52..94f94e05 100644 --- a/simgear/nasal/cppbind/NasalObjectHolder.hxx +++ b/simgear/nasal/cppbind/NasalObjectHolder.hxx @@ -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