好多人都问FreeSWITCH崩溃如何调试,昨天,我正好遇到一个崩溃的情况,很快就找到原因并修复了,简单记录一下,供大家参考。
崩溃发生在master版本上。在视频会议中,当试图播放一个PDF文件时崩溃:
conference 3000 play /tmp/test.pdf
PDF文件支持用到了mod_imagic模块。该模块是我写的,以前是好的,现在出现了崩溃,说明遇到了意外的情况。
我接下来试了PNG文件:
conference 3000 play /tmp/test.png
一样的崩溃。
PDF文件支持是在mod_png中。接着,我试了类似的MP4文件:
conference 3000 play /tmp/test.mp4
MP4不崩溃。
MP4文件在mod_vlc和mod_av中都有支持,我仅试了mod_av。
异同点:mod_imagick和mod_png崩溃,mod_av正常。
conference play 用到了File Interface接口,初步断该接口在mod_av中实现是正确的,而在其它两个模块中有问题。
该文件接口除了可以在conference中调用外,也可以直接用playback,因而,我试了:
<action application=“playback” data=“/tmp/test.pdf”/>
<action application=“playback” data=“/tmp/test.png”/>
<action application=“playback” data=“/tmp/test.mp4”/>
播放都正常,不崩溃。因而,问题缩小为仅在conference中使用该文件接口时崩溃。
好了,挂上lldb(我在Mac上使用llvm,相当于Linux上的gdb和gcc)
ps aux | grep freeswitch #找到FreeSWITCH进程号
lldb
lldb> attach 30918 # FreeSWITCH进程号
continue #继续
重新尝试conference 3000 play /tmp/test.pdf,系统崩溃,看lldb中显示以下消息:
Process 30918 stopped
* thread #36: tid = 0xb53e6, 0x00000001061b5a6b mod_imagick.so`imagick_file_read_video(handle=<unavailable>, frame=0x0000000000000000, flags=<unavailable>) + 987 at mod_imagick.c:317, stop reason = EXC_BAD_ACCESS (code=1, address=0x70)
frame #0: 0x00000001061b5a6b mod_imagick.so`imagick_file_read_video(handle=<unavailable>, frame=0x0000000000000000, flags=<unavailable>) + 987 at mod_imagick.c:317
314
315 if ((context->reads++ % 20) == 0) {
316 switch_img_copy(context->img, &dup);
-> 317 frame->img = dup;
318 context->sent++;
319 } else {
320 if ((flags && SVR_BLOCK)) {
从上面的消息看在执行到mod_imagick.c的317行出错。尝试打印更详细的信息
(lldb) print frame->img
error: Couldn't apply expression side effects : Couldn't dematerialize a result variable: couldn't read its memory
(lldb) print frame
(switch_frame_t *) $2 = 0x0000000000000000
显示frame的值是NULL空指针。其实这一步不是必须的,因为在出错信息的第一行已经显示了frame是NULL了。检查了imagick_file_read_video函数,发现并没有处理frame为NULL的情况。那么,frame为什么是NULL了呢?为什么以前是好用的呢?继续跟踪,输入bt(back trace)看一下调用栈:
(lldb) bt
* thread #36: tid = 0xb53e6, 0x00000001061b5a6b mod_imagick.so`imagick_file_read_video(handle=<unavailable>, frame=0x0000000000000000, flags=<unavailable>) + 987 at mod_imagick.c:317, stop reason = EXC_BAD_ACCESS (code=1, address=0x70)
* frame #0: 0x00000001061b5a6b mod_imagick.so`imagick_file_read_video(handle=<unavailable>, frame=0x0000000000000000, flags=<unavailable>) + 987 at mod_imagick.c:317
frame #1: 0x0000000100c41cec libfreeswitch.1.dylib`switch_core_file_read_video(fh=<unavailable>, frame=<unavailable>, flags=<unavailable>) + 44 at switch_core_file.c:588
frame #2: 0x00000001036c312f mod_conference.so`fnode_check_video(conference=0x00007fd43b847f20, fnode=0x00007fd43b10e320) + 47 at mod_conference.c:1937
frame #3: 0x00000001036be83d
配合源代码逐一检查每一层调用,发现在fnode_check_video函数中(mod_conference.c:1937行)有如下调用
switch_core_file_read_video(&fnode->fh, NULL, SVR_CHECK)
该函数调用的第二个参数就是我们要的frame,而在调用时就直接传入了NULL指针。由于在mod_imagick中没有考虑frame是NULL的情况,因而出现崩溃。
问题是,既然以前没有处理NULL的情况一切都是正常的,说明是上面传入NULL的调用是后来又加上的。
果然,通过检查mod_conference.c的修改历史,发现在385a3b5这次提交中增加了该函数调用,并且,修改时仅修改了mod_av和mod_vlc,在里面加入了一项检查:
if ((flags & SVR_CHECK)) {
return SWITCH_STATUS_BREAK;
}
而类似的检查函数并没有加到mod_imagick和mod_png中。因而导致调用时出错。
在上面的检查中,SVR_CHECK是原函数调用的第三个参数,在调用时仅检查了该标志值,而没有检查frame是否是NULL。因而,我们仅通过阅读代码不容易找到其中的关联性。所幸,这块代码加入的时间不长,我们很快就找到了对应的修改发现了其中的问题。
我把这段代码块也同样加入到了mod_imagick和mod_png中,就不再崩溃了。修复的代码可以通过点击「阅读原文」查看。
类似这样的例子对你有用吗?
别忘点赞 :) 。
本文分享自 FreeSWITCH中文社区 微信公众号,前往查看
如有侵权,请联系 cloudcommunity@tencent.com 删除。
本文参与 腾讯云自媒体分享计划 ,欢迎热爱写作的你一起参与!