Hello!
2012/9/19 Shrimp:
> 我刚才用的最新的lua-redis-parser,在同事的x86_64的slackware上跟我的ubuntu都报segment
> fault,开发机用的还是centos也是一样。
> 用Lua 5.1.4和Lua 5.1.5都一样。
> 与nginx无关,也跟ngx_openresty无关,
> 就只是测试lua-redis-parser的build_query函数,测试代码也只有三行。
>
> ---test.lua
>
> parser = require("redis.parser")
> q =
> {"a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a"}
> local query = parser.build_query(q)
>
OK,我在 Amazon Linux AMI 上使用源码编译的 lua 5.1.5 运行你的这个用例,可以复现此问题。使用
-DLUA_USE_APICHECK 选项编译 lua 5.1.5 可以启用 lua 解释器内部的断言,于是我得到了下面的断言失败:
lua: lapi.c:573: lua_rawgeti: Assertion `L->top < L->ci->top' failed.
此断言清楚地显示 Lua 栈溢出了。根据 lua-redis-parser 的 build_query() 方法的实现,在遍历 query
table 的时候,确实只往栈上压入新值(即 lua_rawgeti 调用),却并没有及时弹出这些值,从而在 query
数组含有许多元素的时候会出现 Lua 栈溢出。
我已经向 lua-redis-parser 的 git master 提交了一个补丁修正了这个问题:
https://github.com/agentzh/lua-redis-parser/commit/c54e33f
同时,我修改了测试用例,从而使得这个栈溢出错误在我的 Fedora 上也能复现:
parser = require("redis.parser")
q = {}
for i = 1,2048 do
table.insert(q, "a")
end
local query = parser.build_query(q)
我的 Fedora yum 源里的 lua 5.1.4 包自己修改了 luaconf.h,调大了 LUAI_MAXCSTACK
的值,因此用你原先的示例无法复现 segfault.
已经标记了 lua-redis-parser 的 v0.10 版本:
https://github.com/agentzh/lua-redis-parser/tags/
和新的 ngx_openresty 1.2.3.3rc3 预发布版:
http://agentzh.org/misc/nginx/ngx_openresty-1.2.3.3rc3.tar.gz
同时抄送给 openresty 邮件列表:https://groups.google.com/group/openresty
这样其他用户如果使用老版本时遇到此问题,也可以 google 到答案 :)
Thanks!
-agentzh
>
> 2012/9/19 Shrimp
>>
>> Hi,
>>
>> 师父啊,我今天在我的笔记本上运行了一段代码,segment fault了,在我们的开发机上也是,用的是标准Lua 5.1.4。
>>
>> 附上代码,仿照你的redis.parser的testcase写的,只要q的个数大于43个就会报这个错。
>>
>> 我用valgrind跑这个Lua脚本,报redis-parser.c的lua_pushlstring那个函数invalid write了
>>
>> ------ test.lua
>> cjson = require('cjson')
>> parser = require("redis.parser")
>> q =
>> {"a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a"}
>> local query = parser.build_query(q)
>> print("query == " .. cjson.encode(query))
>
>