[gcc][glibc]va_start嵌套导致的问题

2019-05-06 14:31:11 浏览数 (1)

前言

使用tgt-1.0.75创建好target之后,在initiator端执行login操作大约卡3s~5s左右。同时观察tgt,CPU消耗到达100%。

一度怀疑是glibc的版本问题,在多个发行版上测试,有的发行版上会coredump。

分析

backtrace

用gdb分析coredump文件,拿到backtrace:

代码语言:javascript复制
Program terminated with signal SIGSEGV, Segmentation fault.
 #0  0x00007f58a410ccc0 in _IO_vfprintf_internal (s=s@entry=0x7ffdec98fdc0, format=<optimized out>,
    format@entry=0x432bc8 "d Mode page %d (0xx), index: %dn", ap=ap@entry=0x7ffdec98ff38) at vfprintf.c:1632
 #1  0x00007f58a41d4896 in ___vsnprintf_chk (s=0x7ffdec990010 "", maxlen=<optimized out>, flags=1,
    slen=<optimized out>, format=0x432bc8 "d Mode page %d (0xx), index: %dn", args=args@entry=0x7ffdec98ff38)
    at vsnprintf_chk.c:63
 #2  0x00007f58a41d47f8 in ___snprintf_chk (s=<optimized out>, maxlen=<optimized out>, flags=<optimized out>,
    slen=<optimized out>, format=<optimized out>) at snprintf_chk.c:34
 #3  0x000000000041f6e7 in scsi_sprintf (str=<optimized out>, size=<optimized out>, format=0x432a88 "%-*s",
    format=0x432a88 "%-*s") at util.h:255
 #4  0x000000000042043a in spc_inquiry (host_no=<optimized out>, cmd=0x123ff40) at spc.c:343
 #5  0x000000000041935a in target_cmd_perform (tid=<optimized out>, cmd=0x123ff40) at target.c:1168
 #6  0x000000000040a66b in iscsi_target_cmd_queue (task=0x123fe70) at iscsi/iscsid.c:1387
 #7  iscsi_scsi_cmd_execute (task=task@entry=0x123fe70) at iscsi/iscsid.c:1407
 #8  0x000000000040a93e in iscsi_task_execute (task=task@entry=0x123fe70) at iscsi/iscsid.c:1527
 #9  0x000000000040b817 in iscsi_task_queue (task=0x123fe70) at iscsi/iscsid.c:1614
 #10 iscsi_task_rx_done (conn=0x123b360) at iscsi/iscsid.c:1744
 #11 iscsi_rx_handler (conn=conn@entry=0x123b360) at iscsi/iscsid.c:2222
 #12 0x0000000000411f48 in iscsi_tcp_event_handler (fd=<optimized out>, events=1, data=0x123b360)
    at iscsi/iscsi_tcp.c:278
 #13 0x00000000004152df in event_loop () at tgtd.c:432
 #14 0x0000000000407191 in main (argc=<optimized out>, argv=<optimized out>) at tgtd.c:624

backtrace正常,相关的参数也是正常的,和预期的现象不符合。

gcc & glibc的版本问题

一共测试了三个版本,分别是:

gcc-5.4/glibc-2.23 --> coredump

代码语言:javascript复制
gcc-6.3/libc-2.24 --> CPU 100%

gcc-7.3/libc-2.27 --> coredump

不同的版本的gcc和glibc的情况,并非完全一致。

tgt的版本对比

考虑到tgt是一个比较稳定的软件,尝试回退到上一个版本1.0.74,发现login操作瞬间完成。

在两个版本之间,除了README更新,只有一个代码更新的commit : https://github.com/fujita/tgt/commit/2de8bebe132e3b998bf4848d0bd22b50367ad4b8

发现这里有改动导致的问题。

va_start嵌套的问题

va_start经常被用来处理可变参数的情况,经过测试发现,在处理"%-*s"这个特定的格式情况下,如果父函数先调用va_start处理,子函数再调用va_start处理,就会出现上述的bug。因为sprintf函数本身也是使用了va_start,而且tgt封装的函数也使用了va_start,导致了这个问题。

采用了walk around的方式来修复这个问题,避免va_start的嵌套即可。

给maintainer发送了patch,maintainer接受并push到了upstream。

https://github.com/fujita/tgt/commit/0bf3f6915282dc8df2f02e6da30814951e52d179

最新的upstream和下一个版本,将会修复这个问题。

0 人点赞