5

背景

我与 Watusimoto 合作开发游戏Bitfighter。我们使用 LuaWrapper 的变体将我们的 c++ 对象与游戏中的 Lua 对象连接起来。我们还使用 Lua 的一种变体,称为lua-vec来加速向量运算。

我们一直在努力解决一段时间以来一直困扰我们的错误。将发生随机崩溃,表明元表已损坏。请参阅此处了解 Watusimoto 关于该问题的帖子。我不确定这是因为元表损坏,并且看到了一些我想在这里问的非常奇怪的行为。

问题表现

例如,我们创建一个对象并将其添加到这样的级别:

t = TextItem.new()
t:setText("hello")
levelgen:addItem(t)

但是,游戏有时(并非总是)会崩溃。出现错误:

attempt to call missing or unknown method 'addItem' (a nil value)

使用在回答上述 Watusimoto 的帖子时给出的建议,我已将最后一行更改为以下内容:

local ok, res = pcall(function() levelgen:addItem(t) end)

if not ok then
    local s = "Invalid levelgen value: "..tostring(levelgen).." "..type(levelgen).."\n"

    for k, v in pairs(getmetatable(levelgen)) do 
        s = s.."meta "..tostring(k).." "..tostring(v).."\n"
    end

    error(res..s)
end

这会打印出元表,以了解levelgen从其中调用方法时出错的情况。

然而,这很疯狂,当它失败并打印出元表时,元表正是它应该的样子(通过正确的addItem调用和一切)。如果我在脚本加载时打印元表levelgen,并且当它使用pcall上面失败时,它们是相同的,每个调用和指向 userdata 的指针都是相同的并且应该是相同的。

就好像元表levelgen是随机地自发消失一样。

有人知道发生了什么吗?

谢谢

注意:这不仅仅发生在levelgen对象上。例如,它也发生在TestItem上面提到的对象上。实际上,相同的代码在我的计算机上levelgen:addItem(t)崩溃了,但在另一个开发人员的计算机上崩溃了,t:setText("hello")并且出现了相同的错误消息missing or unknown method 'setText' (a nil value)

4

3 回答 3

2

与任何谜团一样,您需要将其一层一层剥开。我建议执行 Lua 的相同步骤,并尝试检测所采用的路径与您的预期不同的地方:

返回什么getmetatable(levelgen).__index?如果是表格,则检查其内容是否为addItem. 如果它是一个函数,那么尝试调用它(table, "addItem")并查看它返回的内容。

检查getmetatable调用前后(或失败时)是否返回对同一对象的引用。

调用是否有几个级别的元表间接?如果是这样,请尝试通过显式调用遵循相同的路径,并查看差异在哪里。

weak如果没有其他引用,您是否使用可能导致值消失的键?

当您检测到它失败并继续查看它是否稍后再次“找到”该方法时,您是否可以提供一个“默认”值?或者当它坏了,之后的每个电话都坏了?

如果您为 addItem 保存一个适当的值并在检测到它已损坏时“修复”它怎么办?

如果你只是简单地处理错误(就像你做的那样)并调用它 10 次怎么办?它会至少显示一次有效结果(失败后)吗?100 次?如果你在它工作时继续调用相同的方法,它会失败吗?这可能会帮助您提出更具重现性的错误。

我不熟悉 LuaWrapper 来提供更具体的问题,但如果我是你,我会采取这些步骤。

于 2013-02-17T22:54:38.417 回答
2

我强烈怀疑问题是你有一个类似于这个的类或结构:

struct Foo
{
    Bar bar;
    // Other fields follow
}

你已经通过 LuaWrapper 将 Foo 和 Bar 暴露给 Lua。这里重要的一点是,它是结构bar上的第一个字段Foo。或者,您可能有一些从其他基类继承的类,并且派生类和基类都暴露给 LuaWrapper。

LuaWrapper 使用一个名为 Identifier 的函数来唯一地跟踪每个对象(例如给定对象是否已经添加到 Lua 状态)。默认情况下,它使用对象地址作为键。在上述情况下,Foo 和 Bar 可能在内存中具有相同的地址,因此 LuaWrapper 可能会感到困惑。

这可能会导致在尝试查找方法时抓取错误对象的元表。显然,由于它正在查看错误的元表,它不会找到您想要的方法,因此看起来好像您的元表神秘地丢失了条目。

我检查了一项更改,该更改跟踪每个对象的每种类型的数据,而不是一大堆。如果您将您的 LuaWrapper 副本更新到存储库中的最新版本,我相当肯定您的问题将得到解决。

于 2013-02-23T03:49:10.803 回答
1

与上游(commit 3c54015)LuaWrapper 合并后,这个问题就消失了。这似乎是 LuaWrapper 中的一个错误。

谢谢亚历克斯!

于 2013-06-25T00:27:41.100 回答