Lua 5.2.2 中的一处 Bug

 
 

Han 通过 Google 阅读器发送给您的内容:

 
 

于 13-4-18 通过 云风的 BLOG 作者:云风

前几天, Lua 5.2.2 发布了, 主要是修复了 4 个 Lua 5.2.1 中已知的 bug . 其中包括前段时间一个同学和我在 email 交流中讨论的一个问题.

我把 Lua 5.2.2 更新到公司项目的主干上,同时需要对我的那本 《Lua 源码欣赏》做一些更新,需要把这次的代码更改同步到书里去。这个工作很繁琐,但有它的价值。比如我发现了 Lua 5.2.2 比 5.2.1 的更改远不只官方宣布了 4 处 bugfix ,还有一些小调整,让 Lua 的源码更规整一些。

阿楠同学因为这段时间一直在维护 UniLua 这个 C# 版的 Lua 项目,我就随便和他通告了一下这次的一些代码变更,方便他同步到 UniLua 项目中去。

讨论之中,他提到 luaD_precall 函数的实现有些诡异之处,没有看明白。我顺着他指出的位置又仔细阅读了一下,果然发现这里存在一个隐藏很深的 Bug 。

准确说,这不是 Lua 5.2 引入的新 Bug , 至少在 Lua 5.1 年代就存在了。只不过很难触碰到触发条件。

理解了代码后,我构造了一小段 Lua 代码,可以让 Bug 暴露出来。

 function f(p1,p2,p3,p4,p5,p6,p7,p8,p9,...)   local a1,a2,a3,a4,a5,a6,a7   local a8,a9,a10,a11,a12,a13,a14 end  f() 

运行这段 Lua 代码会让 Lua 虚拟机崩溃。我的修复 patch 如下:

 diff --git a/src/ldo.c b/src/ldo.c index aafa3dc..a901e6c 100644 --- a/src/ldo.c +++ b/src/ldo.c @@ -324,7 +324,7 @@ int luaD_precall (lua_State *L, StkId func, int nresults) {      case LUA_TLCL: {  /* Lua function: prepare its call */        StkId base;        Proto *p = clLvalue(func)->p; -      luaD_checkstack(L, p->maxstacksize); +      luaD_checkstack(L, p->maxstacksize + p->numparams);        func = restorestack(L, funcr);        n = cast_int(L->top - func) - 1;  /* number of real arguments */        for (; n < p->numparams; n++) 

已经提交到 lua mailling list 里去了。Bug 的成因是:在 Lua 函数执行时,先按编译时统计出来的需要的寄存器个数扩展了堆栈。但是,如果函数有不定个数的参数,且调用者没有给完固定参数个数,会触发一个边界条件复制传入参数,结果是让预留的栈空间有可能不够。


4 月 18 日补充:

由于这是因为内存写越界造成的 bug , 所以是否会立即导致程序崩溃和编译环境有关.

我使用的是 mingw32 ,且打开了 -g 选项。

如果想确保看到问题,可以在 luaconf.h 里加上

 #include "assert.h" #define lua_assert assert 

这样就会触发定义好的 assert 条件。


 
 

可从此处完成的操作:

 
 

评论

此博客中的热门博文

浅析Linux Kernel 哈希路由表实现(一)

通过blktrace, debugfs分析磁盘IO

ext4 bigalloc 答疑