Possible problem with default_converter and tables

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

Possible problem with default_converter and tables

Catherine West
Using luabind 0.9 and gcc 4.2.1 on mac os x 10.6

I'm seeing what could (maybe?) be a problem with using a default_converter from lua tables.

I'm trying to define converters for various list-like types in my code, specifically std::vector.  When I pass a table to a c++ method with such a default_converter, lua crashes with free() on an invalid pointer as soon as the garbage collector is called.

I'm probably missing something simple here, but I can't figure it out.

Keep in mind that this is my first project with either lua or luabind, please be gentile if I'm missing something obvious :)

Thank you!

*** Lua Code ***

function first ()
  -- Doesn't crash
  -- t = TestClass(1, 3)

  -- Crashes
  t = TestClass({1, 2, 3})

  print(t:get(0))
  print(t:get(1))
  print(t:get(2))
end

function second ()
  print("About to call collectgarbage...")
  collectgarbage()
  print("Done calling collectgarbage!")
end

function test ()
  first()
  second()
end

*** C++ Code ***

#include <iostream>
#include <lua.hpp>

#include <luabind/luabind.hpp>
#include <luabind/operator.hpp>

using namespace std;
using namespace luabind;

namespace luabind {
  template<typename ListType>
  struct default_converter<std::vector<ListType> > : native_converter_base<std::vector<ListType> > {
    static int compute_score(lua_State* L, int index) {
      return lua_type(L, index) == LUA_TTABLE ? 0 : -1;
    }

    std::vector<ListType> from(lua_State* L, int index) {
      std::vector<ListType> list;
      for (luabind::iterator i(luabind::object(luabind::from_stack(L, index))), end; i != end; ++i)
        list.push_back(luabind::object_cast<ListType>(*i));

      return list;
    }

    void to(lua_State* L, const std::vector<ListType>& l) {
      luabind::object list = luabind::newtable(L);
      for (size_t i = 0; i < l.size(); ++i)
        list[i+1] = l[i];

      list.push(L);
    }
  };
}

class TestClass {
public:
  TestClass(std::vector<int> v) : m_vec(v) {}

  TestClass(int b, int e) {
    for (int i = b; i <= e; ++i)
      m_vec.push_back(i);
  }

  int get(size_t i) const {
    return m_vec[i];
  }

private:
  std::vector<int> m_vec;
};

int main(int argc, char** argv) {
  if (argc != 2) {
    cout << "usage: " << argv[0] << " <scriptname>" << endl;
    return -1;
  }

  std::string scriptName = argv[1];
  lua_State* L = (lua_State*) lua_open();
  luaL_openlibs(L);

  open(L);

  module(L)
  [
    class_<TestClass>("TestClass")
      .def(constructor<std::vector<int> >())
      .def(constructor<int, int>())
      .def("get", &TestClass::get)
  ];

  if (luaL_loadfile(L, scriptName.c_str()) || lua_pcall(L, 0, 0, 0)) {
    cout << "Script error: " << lua_tostring(L, -1) << endl;
    return -1;
  }

  call_function<void>(globals(L)["test"]);

  lua_close(L);
  return 0;
}
------------------------------------------------------------------------------
The Planet: dedicated and managed hosting, cloud storage, colocation
Stay online with enterprise data centers and the best network in the business
Choose flexible plans and management services without long-term contracts
Personal 24x7 support from experience hosting pros just a phone call away.
http://p.sf.net/sfu/theplanet-com
_______________________________________________
luabind-user mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/luabind-user
Reply | Threaded
Open this post in threaded view
|

Re: Possible problem with default_converter and tables

Catherine West
Okay, I figured it out.  Turns out the problem I was describing was way more fundamental... any parameter that was passed by lua into c++ and was a table, was causing the gc to fail later.  Really had nothing to do with default_converter.

The problem was actually compilation related.  I'm compiling this on Mac OS X, and compiling a shared library (the default) seems to act a little funny.  I looked at the symbol table for the final shared library, and it included parts of the static lua library (I don't know if this is normal).  This, in the way I was compiling, would have resulted in duplicate symbols from liblua.a in my final binary.  I suspect that this was causing duplicate per-dylib static variables (or something) that were confusing lua itself.

Take this explanation with a huge grain of salt, though; I'm not an expert.  What I do know, is that when I recompiled luabind as a static library, my problem disappeared.  Sorry for cluttering the list with unrelated problems :)

One other thing... compiling the shared library variant of luabind in Mac OS X yields another irritating problem.  For example, the @executable_path dylib symbol is incorrect in the finaly libluabind.dylib, and you have to change it to ../Frameworks/libluabind.dylib with install_name_tool in order to build an app directory correctly.  (I'm not sure if this is fixable, or even an error.  I'm not an expert)  Might it be possible to set the default target for the darwin toolset to build the static version of luabind, or at least say something about it in the documentation?  The static version of the library seems to work great, and is dead simple.

Thanks!

On Feb 6, 2010, at 7:33 PM, Catherine West wrote:

> Using luabind 0.9 and gcc 4.2.1 on mac os x 10.6
>
> I'm seeing what could (maybe?) be a problem with using a default_converter from lua tables.
>
> I'm trying to define converters for various list-like types in my code, specifically std::vector.  When I pass a table to a c++ method with such a default_converter, lua crashes with free() on an invalid pointer as soon as the garbage collector is called.
>
> I'm probably missing something simple here, but I can't figure it out.
>
> Keep in mind that this is my first project with either lua or luabind, please be gentile if I'm missing something obvious :)
>
> Thank you!
>
> *** Lua Code ***
>
> function first ()
>  -- Doesn't crash
>  -- t = TestClass(1, 3)
>
>  -- Crashes
>  t = TestClass({1, 2, 3})
>
>  print(t:get(0))
>  print(t:get(1))
>  print(t:get(2))
> end
>
> function second ()
>  print("About to call collectgarbage...")
>  collectgarbage()
>  print("Done calling collectgarbage!")
> end
>
> function test ()
>  first()
>  second()
> end
>
> *** C++ Code ***
>
> #include <iostream>
> #include <lua.hpp>
>
> #include <luabind/luabind.hpp>
> #include <luabind/operator.hpp>
>
> using namespace std;
> using namespace luabind;
>
> namespace luabind {
>  template<typename ListType>
>  struct default_converter<std::vector<ListType> > : native_converter_base<std::vector<ListType> > {
>    static int compute_score(lua_State* L, int index) {
>      return lua_type(L, index) == LUA_TTABLE ? 0 : -1;
>    }
>
>    std::vector<ListType> from(lua_State* L, int index) {
>      std::vector<ListType> list;
>      for (luabind::iterator i(luabind::object(luabind::from_stack(L, index))), end; i != end; ++i)
>        list.push_back(luabind::object_cast<ListType>(*i));
>
>      return list;
>    }
>
>    void to(lua_State* L, const std::vector<ListType>& l) {
>      luabind::object list = luabind::newtable(L);
>      for (size_t i = 0; i < l.size(); ++i)
>        list[i+1] = l[i];
>
>      list.push(L);
>    }
>  };
> }
>
> class TestClass {
> public:
>  TestClass(std::vector<int> v) : m_vec(v) {}
>
>  TestClass(int b, int e) {
>    for (int i = b; i <= e; ++i)
>      m_vec.push_back(i);
>  }
>
>  int get(size_t i) const {
>    return m_vec[i];
>  }
>
> private:
>  std::vector<int> m_vec;
> };
>
> int main(int argc, char** argv) {
>  if (argc != 2) {
>    cout << "usage: " << argv[0] << " <scriptname>" << endl;
>    return -1;
>  }
>
>  std::string scriptName = argv[1];
>  lua_State* L = (lua_State*) lua_open();
>  luaL_openlibs(L);
>
>  open(L);
>
>  module(L)
>  [
>    class_<TestClass>("TestClass")
>      .def(constructor<std::vector<int> >())
>      .def(constructor<int, int>())
>      .def("get", &TestClass::get)
>  ];
>
>  if (luaL_loadfile(L, scriptName.c_str()) || lua_pcall(L, 0, 0, 0)) {
>    cout << "Script error: " << lua_tostring(L, -1) << endl;
>    return -1;
>  }
>
>  call_function<void>(globals(L)["test"]);
>
>  lua_close(L);
>  return 0;
> }


------------------------------------------------------------------------------
The Planet: dedicated and managed hosting, cloud storage, colocation
Stay online with enterprise data centers and the best network in the business
Choose flexible plans and management services without long-term contracts
Personal 24x7 support from experience hosting pros just a phone call away.
http://p.sf.net/sfu/theplanet-com
_______________________________________________
luabind-user mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/luabind-user
Reply | Threaded
Open this post in threaded view
|

Re: Possible problem with default_converter and tables

Daniel Wallin
On Sun, Feb 07, 2010 at 05:10:32AM -0600, Catherine West wrote:

> Okay, I figured it out.  Turns out the problem I was describing was
> way more fundamental... any parameter that was passed by lua into c++
> and was a table, was causing the gc to fail later.  Really had nothing
> to do with default_converter.
>
> The problem was actually compilation related.  I'm compiling this on
> Mac OS X, and compiling a shared library (the default) seems to act a
> little funny.  I looked at the symbol table for the final shared
> library, and it included parts of the static lua library (I don't know
> if this is normal).

It is if you link to a static Lua library. At least on my OSX install,
that's all I have.

> This, in the way I was compiling, would have resulted in duplicate
> symbols from liblua.a in my final binary.  I suspect that this was
> causing duplicate per-dylib static variables (or something) that were
> confusing lua itself.

AFAIK, this should just work. Can you reproduce this? I would be
interested in the command line you used to build the library and final
executable. Is it possible that luabind was inadvertently linked against
a different Lua library than your executable?

> One other thing... compiling the shared library variant of luabind in
> Mac OS X yields another irritating problem.  For example, the
> @executable_path dylib symbol is incorrect in the finaly
> libluabind.dylib, and you have to change it to
> ../Frameworks/libluabind.dylib with install_name_tool in order to
> build an app directory correctly.  (I'm not sure if this is fixable,
> or even an error.  I'm not an expert)

I'm not sure what I can do about this. What is executable_path set to?

> Might it be possible to set the default target for the darwin toolset
> to build the static version of luabind, or at least say something
> about it in the documentation?  The static version of the library
> seems to work great, and is dead simple.

Yes, that's certainly possible. I'd like to make sure we can't do
anything better before doing that though.

--
Daniel Wallin
BoostPro Computing
http://www.boostpro.com

------------------------------------------------------------------------------
Download Intel&#174; Parallel Studio Eval
Try the new software tools for yourself. Speed compiling, find bugs
proactively, and fine-tune applications for parallel performance.
See why Intel Parallel Studio got high marks during beta.
http://p.sf.net/sfu/intel-sw-dev
_______________________________________________
luabind-user mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/luabind-user