luabind 中 default_converter 和表的问题

发布于 2024-08-20 08:20:21 字数 2929 浏览 5 评论 0原文

===编辑===

问题实际上比这简单得多,任何采用表的包装函数都会导致问题。如果我包装一个采用 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;
}

===Edit===

The problem is actually much simpler than this, any wrapped function that takes a table is causing the problem. If I wrap a function that takes luabind::object, and call that function with a table argument, then the gc causes an invalid free(). I'm starting to think that this may be some kind of crazy compilation/linking problem, as my compiled luabind dylib has lua symbols in it (resulting in two copies of those symbols, one in that library and one in my binary). Maybe I have duplicates of some lua static variables or something? I might just be grasping at straws here.

===Edit===

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.

Thanks!

* 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;
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

空袭的梦i 2024-08-27 08:20:21

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

对这个解释持保留态度,但这是我最好的猜测;我不是 Mac OS X 链接器工作原理的专家。我确实知道,当我静态构建 luabind 时,一切正常。

因此,对于在 mac 中构建 lubabind 的人来说,请静态构建。 jam 构建的共享库还存在其他问题,您必须修复这些问题,例如 @executable_path 错误。静态构建非常简单。

Yeah, I figured it out. Turns out that luabind didn't have any problems at all, except for the way it was built. The jam build system, on mac os x, causes the static lua library to be linked in with the luabind shared library, causing duplicate symbols (and duplicate static variables) when I link my final binary. It didn't have the entire lua library linked in though, so you still have to link liblua.a in again.

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文