罕见的 coredump 了
最近,项目在越南版删档测试的时候,发生了罕见的 coredump,简单记一点排查日志
目前的敏感词过滤是在 C 层做判定的,先后经过几个项目考验,模块算是比较稳定了。越南版有个需求,需要将敏感词里的空格去掉。比如敏感词是 abc,现在不能说 abc 了,但是玩家可以输入 a b c,所以需要过滤掉空格。有同事就对 C 层改了一下,判断 rune 是 32 的时候,就继续判断后续字符,出事的代码大致如下:
lua_rawgeti(L, 1, j); uint32_t rune = (uint32_t)lua_tointeger(L, -1);
+ if (rune == 32) {
+ continue;
+ }
lua_pop(L, 1);
-
if(node == NULL) {
node = table_get(dict, rune);
} else {
这里会跳过 lua_pop 语句,导致之前 lua_rawgeti 的结果残留在栈上。但这个缺陷不会马上让进程挂掉,而是将栈弄坏一点点。我们来看 Lua 的栈定义:
1 /*
2 ** 'per thread' state
3 */
4 struct lua_State {
5 CommonHeader;
6 unsigned short nci; /* number of items in 'ci' list */
7 lu_byte status;
8 StkId top; /* first free slot in the stack */
9 global_State *l_G;
10 CallInfo *ci; /* call info for current function */
11 const Instruction *oldpc; /* last pc traced */
12 StkId stack_last; /* last free slot in the stack */
13 StkId stack; /* stack base */
14 UpVal *openupval; /* list of open upvalues in this stack */
15 GCObject *gclist;
16 struct lua_State *twups; /* list of threads with open upvalues */
17 struct lua_longjmp *errorJmp; /* current error recover point */
18 CallInfo base_ci; /* CallInfo for first level (C calling Lua) */
19 volatile lua_Hook hook;
20 ptrdiff_t errfunc; /* current error handling function (stack index) */
21 int stacksize;
22 int basehookcount;
23 int hookcount;
24 unsigned short nny; /* number of non-yieldable calls in stack */
25 unsigned short nCcalls; /* number of nested C calls */
26 l_signalT hookmask;
27 lu_byte allowhook;
28 };
lua_State 的 stack 是一个指针,指向一个动态申请的 TValue 指针数组。这个栈不仅是 lua 和 C 交互的时候,用于双方交换数据;lua 函数调用的时候,也会将函数参数压栈(当然,调用关系不在这个栈上,而是通过 CallInfo 指针组织的双向链表来记录)Lua 默认会给函数初始化 20 个格子,也可以通过 lua_checkstack 函数去增加栈的大小。L->top 指向的是栈上的第一个可用空槽,L->top 在正常使用的时候会小于 L->ci->top,lua 自带有 api_check 来检查。之前为了压榨性能,api_check 也关掉了,所以没检查出 stack overflow。
当一个 C 函数不断往栈上 push 函数,超过栈的大小后,会写坏什么内存就没法确定了。出事的时候,写坏的是另一个协程的 stack,另一个协程正准备 resume 回来,但是栈上存的 ci->func 是 TValue(正数 32),不是一个函数类型,就 coredump 了。
稳妥起见,以后改 C 代码还是走一下 code review 吧,自己也打开 api_check 检查一下。。查这个问题花了很久,还有一个原因是其他同学搞混了线上版本,我看的是有问题的版本,结果另一个分支上的是没问题的版本,以为正式服上跑的是没问题的版本,查了好久。。。