segfault when get_pointer returns null

Andreas Grob <[email protected]>
Newsgroups gmane.comp.lang.lua.bind.user
Message-ID <1298761033.6662.42.camel@debian>
Hello all,

right now I am trying to write a wrapping pointer to hold objects passed
to luabind. The idea is to change the behaviour of get_pointer at
runtime to invalidate objects.
While I can wrap null pointers and receive luabind::error upon trying to
call a member, the program segfaults in luabind when I change the result
of get_pointer from a normal pointer to null at a later time, i.e. after
passing the wrapped object to luabind.

Here is the stacktrace when get_pointer just returned null before the
segfault:

#0  luabind::detail::pointer_holder<fuse_ptr<myclass>, void const>::get
(this=0x805b630, target=3)
    at /usr/include/luabind/detail/instance_holder.hpp:100
#1  0x0804bd60 in luabind::detail::object_rep::get_instance
(this=0x805b62c, target=3)
    at /usr/include/luabind/detail/object_rep.hpp:59
#2  0x0804f99a in luabind::detail::ref_converter::match<myclass>
(this=0xbfffee94, L=0x80550a8, index=1)
    at /usr/include/luabind/detail/policy.hpp:402
#3  0x0804f776 in luabind::detail::invoke_member<void (myclass::*)(),
boost::mpl::vector2<void, myclass&>, luabind::detail::null_type>
(L=0x80550a8, self=..., ctx=..., f=@0x805a5b8)
at /usr/include/luabind/detail/call.hpp:257
#4  0x0804f6d3 in luabind::detail::invoke0<void (myclass::*)(),
boost::mpl::vector2<void, myclass&>, luabind::detail::null_type,
boost::is_void<void> > (L=0x80550a8, self=..., ctx=..., f=@0x805a5b8,
policies=...) at /usr/include/luabind/detail/call.hpp:78
#5  0x0804f698 in luabind::detail::invoke<void (myclass::*)(),
boost::mpl::vector2<void, myclass&>, luabind::detail::null_type> (
    L=0x80550a8, self=..., ctx=..., f=@0x805a5b8, policies=...)
at /usr/include/luabind/detail/call.hpp:101
#6  0x0804f5d6 in luabind::detail::function_object_impl<void
(myclass::*)(), boost::mpl::vector2<void, myclass&>,
luabind::detail::null_type>::entry_point (L=0x80550a8)
at /usr/include/luabind/make_function.hpp:62
[...calls from lua...]

If continued it segfaults in frame 3, line 287:
(c0.apply(L, LUABIND_DECORATE_TYPE(a0), index0).*f)(


My question is: Why is the call to a member of null not detected and an
exception thrown?

The code is attached (using lua 5.1.4 and luabind 0.9.1).

Thank you very much.

Best regards,
Andreas

------------------------------------------------------------------------------
Free Software Download: Index, Search & Analyze Logs and other IT data in 
Real-Time with Splunk. Collect, index and harness all the fast moving IT data 
generated by your applications, servers and devices whether physical, virtual
or in the cloud. Deliver compliance at lower cost and gain new business 
insights. http://p.sf.net/sfu/splunk-dev2dev

_______________________________________________
luabind-user mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/luabind-user
fuse_ptr.hpp (text/x-c++hdr, 3 KB)
#ifndef __FUSE_PTR_HPP__
#define __FUSE_PTR_HPP__

#include <map>
#include <iostream>

template<class T>
class fuse_ptr
{
    private:
        // pointer to the object
        T** ptr;
        
        // container for all references from pointers to associated fuse_ptrs
        static std::multimap<T*,fuse_ptr<T> * > fusebox;

    public:
        // contructor for null pointer
        fuse_ptr()
        {
            ptr = new T*;
            *ptr = 0;
        }
        
        // constructor for objects
        fuse_ptr( T* p )
        {
            ptr = new T*;
            *ptr = p;
            std::cout << this << " is now fuse for " << *ptr << std::endl;
            fusebox.insert( std::pair<T*,fuse_ptr<T> * >(p,this) );
        }

        // copy constructor
        fuse_ptr( fuse_ptr const & p )
        {
            ptr = new T*;
            *ptr = *(p.ptr);
            std::cout << this << " is now fuse for " << *ptr << std::endl;
            fusebox.insert( std::pair<T*,fuse_ptr<T> * >(*ptr,this) );
        }
        
        // pointer access
        T* get() const
        {
            std::cout << "Getting ptr of " << this << ": " << *ptr << std::endl;
            return *ptr; 
        }
        
        operator T*() const
        {
            return get();
        }
        
        T* operator->() const
        {
            return get();
        }
        
        operator bool() const
        {
            return get() != 0;
        }
        
        // virtual destructor
        virtual ~fuse_ptr()
        {
            if( *ptr != 0 )
            {
                std::pair< typename std::multimap<T*,fuse_ptr<T> * >::iterator, typename std::multimap<T*,fuse_ptr<T> * >::iterator > range = fusebox.equal_range( *ptr );
                typename std::multimap<T*,fuse_ptr<T> * >::iterator it;
                for( it = range.first; it != range.second && it->second != this; ++it );
                if( it != range.second )
                {
                    std::cout << this << " is not any longer fuse for " << it->first << std::endl;
                    fusebox.erase( it );
                }
            }
            delete ptr;
            ptr = 0;
        }

        // sets all associated fuse_ptrs' contents to null and removes them from fusebox
        static void blow_fuse( T* p )
        {
            std::pair< typename std::multimap<T*,fuse_ptr<T> * >::iterator, typename std::multimap<T*,fuse_ptr<T> * >::iterator > range = fusebox.equal_range( p );
            typename std::multimap<T*,fuse_ptr<T> * >::iterator it;
            for( it = range.first; it != range.second; ++it )
            {
                std::cout << "Setting *ptr of " << it->second << " = 0" << std::endl;
                *(it->second->ptr) = 0;
            }
            fusebox.erase( p );
        }
};

template<class T>
std::multimap<T*,fuse_ptr<T> * > fuse_ptr<T>::fusebox;

// returns p.get()
template<class T>
T* get_pointer( fuse_ptr<T> const & p )
{
    return p.get();
}

#endif
main.cpp (text/x-c++src, 1.9 KB)
#include <iostream>
#include <sstream>
#include "fuse_ptr.hpp"

#include <lua5.1/lua.hpp>
#include <luabind/luabind.hpp>

using namespace std;
using namespace luabind;

class myclass
{
    public:
    myclass()
    {
        cout << "myclass created: " << this << endl;
        someint = 42;
    }
    myclass(int dummy)
    {
        cout << "myclass created: " << this << endl;
        someint = dummy;
    }
    ~myclass()
    {
        fuse_ptr<myclass>::blow_fuse( this );
        cout << "myclass destructed: " << this << endl;
    }
    virtual void dosomething()
    {
        cout << "someint == " << someint << endl;
    }
    protected:
    int someint;
};

int main(void)
{
    lua_State* L = lua_open();
    luaL_openlibs( L );
    open( L );

    module(L)
        [
        class_<myclass, fuse_ptr<myclass> >("myclass")
        .def( "dosomething", &myclass::dosomething )
        ];

    const char* src = "function doStuff()"
                      "    stored_myc:dosomething();"
                      "end;"
                      "function storeMyc( myc )"
                      "    stored_myc = myc;"
                      "end;";

    if( luaL_dostring( L, src ) )
    {
        cout << "Error:" <<  lua_tostring( L, -1 ) << endl;
    }

    try
    {
        myclass* p = new myclass(100);
        myclass* q = 0;

        // using q here instead of p works
        fuse_ptr<myclass> f(p);
        globals( L )["storeMyc"](f);

        globals( L )["doStuff"]();

        delete p;
        p=0;

        globals( L )["doStuff"]();
        
        delete q;
        q=0;

    }
    catch(luabind::error e)
    {
        cout<<"caught exception..."<<endl;
        cout<<e.what()<<endl;
        std::string err = lua_tostring(L, -1);
        lua_pop(L, 1);
        cout<<err<<endl;
    }
    cout << "closing luaState..." << endl;
    lua_close( L );
    cout << "return 0" << endl;
    return 0;
}
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.