1

===编辑===

问题实际上比这简单得多,任何采用表的包装函数都会导致问题。如果我包装一个采用 luabind::object 的函数,并使用表参数调用该函数,那么 gc 会导致无效的 free()。我开始认为这可能是某种疯狂的编译/链接问题,因为我编译的 luabind dylib 中有 lua 符号(导致这些符号的两个副本,一个在该库中,一个在我的二进制文件中)。也许我有一些 lua 静态变量或其他东西的副本?我可能只是在这里抓住稻草。

===编辑===

在 mac os x 10.6 上使用 luabind 0.9 和 gcc 4.2.1

我看到使用 lua 表中的 default_converter 会出现什么问题(也许?)。

我试图在我的代码中为各种类似列表的类型定义转换器,特别是 std::vector。当我使用这样的 default_converter 将表传递给 c++ 方法时,只要调用垃圾收集器,lua 就会在无效指针上使用 free() 崩溃。

我可能在这里遗漏了一些简单的东西,但我无法弄清楚。

谢谢!

* Lua 代码 *


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++ 代码 *


#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;
}
4

1 回答 1

2

是的,我想通了。事实证明,luabind 根本没有任何问题,除了它的构建方式。mac os x 上的 jam 构建系统导致静态 lua 库与 luabind 共享库链接,当我链接我的最终二进制文件时导致重复符号(和重复的静态变量)。虽然它没有链接整个lua 库,所以你仍然需要再次链接 liblua.a。

Take this explanation with a grain of salt, but it's my best guess; I'm not an expert at how the Mac OS X linker works. I do know that when I built luabind statically, everything works fine.

So, for anyone building lubabind in mac, build statically. There are also other problems with the jam built shared lib that you'd have to fix, like the fact that @executable_path is wrong. Static build was dead simple.

于 2010-02-07T18:20:34.123 回答