[alibaba/tengine]当启用 OpenSSL 异步模式时 LuaJIT 出现 memory corruption

2024-06-26 909 views
8

Tengine 团队,你们好!

最近我们正在尝试在我们的 Nginx 服务里集成 QAT 加速的功能,我们发现在使用 QAT 服务的情况下(且同时使用 OpenSSL 异步模式),我们的 Nginx worker 进程经常会崩溃,比如出现以下的堆栈:

image

经过一段时间的排查,我们发现问题似乎是因为 LuaJIT 和 OpenSSL 异步模式之间存在一些冲突(猜测),OpenSSL 异步模式下似乎使用了 setjmp/longjmpmakecontext/swapcontext 等函数实现控制流的切换,我不太清楚这些函数是否会干扰到 LuaJIT。

禁用 OpenSSL 异步模式或者关闭 LuaJIT 的即时编译功能都能够修复该问题,不过代价对我们来说都比较昂贵。

鉴于 Tengine 也集成了 ngx_lua,并且支持使用异步 SSL 模式,我想请教下是否你们也出现过这类问题,以及是否有合适的解决办法?

  • OpenSSL: 基于官方的 1.1.1-pre2
  • Nginx: 基于官方的 1.13.9
  • Linux Kernel: 4.9.0
  • LuaJIT: v2.1-20171103

Best Regards Alex Zhang

回答

4
  1. 确定下lj的状态,是否再jit :https://github.com/openresty/openresty-gdb-utils#lvmst
  2. 如果1.中返回的是lua(trace)状态,则再执行 ltrace 可以具体看到哪个lua代码被jit掉了, x/100i <mcode_start> 产出jit后生成的优化的机器码
  3. 如果1.中返回的是lua(trace)状态,则再执行 lir 确定具体lua opcode被tracing过程中产生的ir
  4. 拿2.和3.中的机器码和ir对比,看是否机器码有问题,如果没问题则可能是 部分状态(结构体,内存对象)被写乱

信息同步:线下沟通,关闭JIT该问题不再复现

2

另外 luajit的编译参数提供下(如果有的话),另外机器架构提供是x64还是x86的

2

@chobits

崩溃时 LuaJIT 的状态为:

(gdb) lvmst
current VM state: Trace recorder

另外我们编译 LuaJIT 的时候没有携带额外的参数,一切应该都是默认的选项。 机器架构是 x64 的。

0

补充:

发现另外一种崩溃时的堆栈:

#0  0x00007f547ee5c1bc in snapshot_framelinks (topslot=0x415c3f6d " \v", J=0x416e7558, map=0x41396700) at lj_snap.c:124
#1  snapshot_stack (nsnapmap=431, snap=0x415c3f68, J=0x416e7558) at lj_snap.c:163
#2  lj_snap_add (J=0x416e7558) at lj_snap.c:191
#3  0x00007f547ee614df in lj_record_ins (J=0x416e7558) at lj_record.c:2023
#4  0x00007f547ee77495 in trace_state (L=0x416e7378, dummy=<optimized out>, ud=0x416e7558) at lj_trace.c:670
#5  0x00007f547ee38f56 in lj_vm_cpcall () from /usr/local/marco/luajit/lib/libluajit-5.1.so.2
#6  0x00007f547ee765df in lj_trace_ins (J=0x416e7558, pc=<optimized out>) at lj_trace.c:729
#7  0x00007f547ee42b0a in lj_dispatch_call (L=0x416e7378, pc=0x4156e0ec) at lj_dispatch.c:493
#8  0x00007f547ee3a5ca in lj_vm_hotcall () from /usr/local/marco/luajit/lib/libluajit-5.1.so.2
#9  0x00007f547ee4807d in lua_pcall (L=<optimized out>, nargs=<optimized out>, nresults=<optimized out>, errfunc=<optimized out>) at lj_api.c:1129
#10 0x0000000000555f2e in ngx_http_lua_cache_load_code (log=0x543b2d8, L=0x416e7378, key=0x1687448 "nhli_fff835480c574b40e7fa56e821097732")
    at /root/alex/marco/deps/lua-nginx-module-0.10.11h/src/ngx_http_lua_cache.c:56
#11 0x0000000000556105 in ngx_http_lua_cache_loadbuffer (log=0x543b2d8, L=0x416e7378, src=0x16873e8 "\n    if not ngx.is_subrequest then\n        return \"1\"\n    end\n",
    src_len=62, cache_key=0x1687448 "nhli_fff835480c574b40e7fa56e821097732", name=0x6c613b "=set_by_lua")
    at /root/alex/marco/deps/lua-nginx-module-0.10.11h/src/ngx_http_lua_cache.c:148
#12 0x000000000054b7aa in ngx_http_lua_filter_set_by_lua_inline (r=0x5411050, val=0x7ffc50cff4e0, v=0x541fae8, data=0x1687428)

image

#define frame_prevl(f)      ((f) - (1+LJ_FR2+bc_a(frame_pc(f)[-1])))
#define frame_pc(f)     (mref((f)->fr.tp.pcr, const BCIns))
#define mref(r, t)  ((t *)(void *)(uintptr_t)(r).ptr32)
(gdb) p frame.fr.tp.pcr
$7 = {ptr32 = 4294967284}

貌似这个值被写乱了?

3

补充: 关闭 LuaJIT 的 JIT 功能后,崩溃现象仍然存在,关闭 OpenSSL 异步模式后崩溃现象不再出现。

9

cc @weicz11, any idea for this?

6

在 ngx_lua 一些函数内加了某些 OpenSSL 异步模式相关的函数后,问题似乎已经得到解决,非常感谢帮助!

5

能具体说下你加了什么OpenSSL的异步模式相关函数吗?@tokers

9

@weicz11

ngx_http_lua_ffi_ssl_set_der_certificate 函数举例,这个函数最终调用的 OpenSSL 的 SSL_add0_chain_cert 涉及一些摘要计算等操作,如果开启 OpenSSL 异步模式,则可能触发一次协程上下文切换,我在 ngx_http_lua_ffi_ssl_set_der_certificate 里加了

ASYNC_block_pause();

阻止上下文切换的发生。

7

@tokers 这个有点像关键区的操作,我理解你应该在你需要保护的地方block pause然后过后再unblock pause,否则可能你想使用异步的地方也没法跑异步了

1

@weicz11 是的。

9

@tokers 那看来真的是两个协程的实现互相干扰了,头大的问题。。。