IT技术博客大学习 共学习 共进步
全部 移动开发 后端 数据库 AI 算法 安全 DevOps 前端 设计 开发者

一个链接 lua 引起的 bug , 事不过三

云风的 BLOG 2012-01-24 13:38:13 累计浏览 2,059 次
本机暂存

    今天花了将近 3 个小时帮同事看一个崩在 lua VM 中的 bug 结果打乱了进度,没有在年前把预想的东西做完。其实说起来这不是个大问题,以前也碰到过。我检讨自己没有在看到出错时的调用栈时去看一眼 lua 相关的代码。如果是那样,因为以前遇到过同样的问题,所以就可以条件反射出问题原因,而不用荒废宝贵了数小时时间了。

    唉,这下整合的进度没接上,过年不能自己一个人接着做下面的活了。

    下面记录一下这个 bug ,提醒自己第三次遇到时不用再花时间找问题:

    问题的缘由是因为的不同的 lua 扩展库链接的时候多链接了一份 lua 库,导致进程内有超过一份 lua 库。这是在写 Makefile 时不小心造成的。知道原因后自然很容易解决。要么把 lua 编译成 .so ;要么只有嵌入的主框架使用 -E 参数静态链接 lua 的静态库。这里就不展开说了。

    用了 lua 十年,绝对不是第一次帮其他用 lua 的同学指出这个问题。下面要讨论的是错误产生后,程序是怎么崩溃的。

    lua 的代码中几乎没有使用全局变量。就是说,lua 的 api 的相关状态仅存在于参数 L 中,而和库无关。这点 lua 实现的是很漂亮的。对于一个无外部状态的 api ,理论上无论代码段在进程内被链接再多次,都不会有副作用的。但副作用的确又发生了,为何?

    问题出在 ltable.c 中引用了一个静态全局变量 dummynode_ 。这个东西是做什么用的呢?

    在 lua table 实现中,为了不让 hash part 为空的时候不引用 NULL 指针(一种优化),而引用了这个 dummynode ,这样就可以减少操作表时的判断操作。

    由于这个 dummynode 是静态分配出来的特殊节点,所以是不能调用内存管理函数去释放它的。lua 另外用一个宏来判断一个节点是否为 dummynode 。

#define isdummy(n)      ((n) == dummynode)

    当进程中链接了多份 lua 库时,就出现了多份 dummynode 对象,自然 isdummy 的行为就可能不正确了。那么接下来的释放工作则会崩掉,看起来段错误会发生在 lua_Alloc 中。

    问题多出现在运行过程中,向空 table 插入第一个 hash 值时,也就是 luaH_resize 函数的最后一行:

 if (!isdummy(nold))
    luaM_freearray(L, nold, cast(size_t, twoto(oldhsize))); /* free old array */

    或是关闭 lua state 时,释放 table 时,的 luaH_free 函数最前面:

  if (!isdummy(t->node))
    luaM_freearray(L, t->node, cast(size_t, sizenode(t)));

    之所以我把代码和出错位置列出来,是因为我今天不是第一次专门分析这个点了。如果我下午在刚出问题时,能够在看到 stack traceback 信息的函数名)luaH_resize 打开 lua 的源代码看一眼的话,我相信我能立刻回想起上次分析这个问题的情景,从而节省掉后来浪费在查别的地方上的无尽时间。

    希望经过这次,下次有人向我反应类似问题时,我能直接对应到问题。

同分类推荐文章

  1. 等了十年的 Go 链式管道,终于来了:seq 让你像写 Scala 一样写 Go (2026-06-25 18:38:18)
  2. Go 实验特性详解 (2026-06-21 10:05:27)
  3. amd64 微架构级别对 Go 程序性能提升多少? (2026-06-21 09:38:49)

查看更多 后端 文章 →

建议继续学习

  1. Java程序员应该知道的10个eclipse调试技巧 (累计阅读 8,012)
  2. Python程序的执行原理 (累计阅读 7,333)
  3. 使用gdb调试运行时的程序小技巧 (累计阅读 7,208)
  4. 程序员最怕的事 (累计阅读 6,923)
  5. 使用GDB调试多进程程序 (累计阅读 6,365)
  6. 一个程序员的血泪史 (累计阅读 6,324)
  7. 为什么C语言需要函数声明 (累计阅读 5,720)
  8. Nginx与Lua (累计阅读 5,672)
  9. php调试利器之phpdbg (累计阅读 5,675)
  10. 近距离端详Android ART运行时库 (累计阅读 5,580)