Browsed by
标签: 段错误

linux 定位段错误的一个方法

linux 定位段错误的一个方法

背景:程序出现段错误,没有core文件产生,日志没来得及写堆栈信息。

步骤1:使用dmesg查看系统运行信息。

cstaspee[10259]: segfault at 4 ip 00007fdb92acd1df sp 00007fd9c5e65d20 error 6 in libcsta_scm.so[7fdb92aba000+1c000]

发现在cstaspee在调用libcsta_scm.so动态库出现段错误。

步骤2:计算错误点在动态库的地址

7fdb92aba000为模块(libcsta_scm.so)载入地址,
00007fdb92acd1df为程序崩溃点ip指令地址,
相减   00007fdb92acd1df - 7fdb92aba000 = 131DF,
差值为错误点在动态库的地址。

步骤3:使用objdump命令反汇编 或 addr2line

objdump -d libcsta_scm.so > /tmp/xxx.txt

xxx.txt部分文件内容

00000000000130df <_Z30csta_scm_baseServiceEventSetupP13STRUCT_CM_MSGiii>:
   130df:    55                       push   %rbp
   130e0:    48 89 e5                 mov    %rsp,%rbp
   130e3:    48 83 ec 30              sub    $0x30,%rsp
   130e7:    48 89 7d e8              mov    %rdi,-0x18(%rbp)
   130eb:    89 75 e4                 mov    %esi,-0x1c(%rbp)
   130ee:    89 55 e0                 mov    %edx,-0x20(%rbp)
   130f1:    89 4d dc                 mov    %ecx,-0x24(%rbp)
   130f4:    c7 45 fc 00 00 00 00     movl   $0x0,-0x4(%rbp)
   130fb:    e9 16 02 00 00           jmpq   13316 <_Z30csta_scm_baseServiceEventSetupP13STRUCT_CM_MSGiii+0x237>
   13100:    48 8b 0d d1 8e 20 00     mov    0x208ed1(%rip),%rcx        # 21bfd8 <[email protected]@Base-0x428>
   13107:    8b 45 fc                 mov    -0x4(%rbp),%eax
   1310a:    48 63 d0                 movslq %eax,%rdx
   1310d:    8b 45 e4                 mov    -0x1c(%rbp),%eax
   13110:    48 63 f0                 movslq %eax,%rsi
   13113:    48 89 d0                 mov    %rdx,%rax
   13116:    48 c1 e0 03              shl    $0x3,%rax
   1311a:    48 01 d0                 add    %rdx,%rax
   1311d:    48 c1 e0 06              shl    $0x6,%rax
   13121:    48 69 d6 d8 39 28 00     imul   $0x2839d8,%rsi,%rdx
   13128:    48 01 d0                 add    %rdx,%rax
   1312b:    48 01 c8                 add    %rcx,%rax
   1312e:    48 05 c0 09 04 00        add    $0x409c0,%rax
   13134:    8b 40 04                 mov    0x4(%rax),%eax
   13137:    83 f8 01                 cmp    $0x1,%eax
   1313a:    0f 85 8e 00 00 00        jne    131ce <_Z30csta_scm_baseServiceEventSetupP13STRUCT_CM_MSGiii+0xef>
   13140:    8b 45 fc                 mov    -0x4(%rbp),%eax
   13143:    48 63 d0                 movslq %eax,%rdx
   13146:    48 89 d0                 mov    %rdx,%rax
   13149:    48 c1 e0 03              shl    $0x3,%rax
   1314d:    48 01 d0                 add    %rdx,%rax
   13150:    48 c1 e0 06              shl    $0x6,%rax
   13154:    8b 55 e4                 mov    -0x1c(%rbp),%edx
   13157:    48 63 d2                 movslq %edx,%rdx
   1315a:    48 69 d2 d8 39 28 00     imul   $0x2839d8,%rdx,%rdx
   13161:    48 01 d0                 add    %rdx,%rax
   13164:    48 8d 90 c0 09 04 00     lea    0x409c0(%rax),%rdx
   1316b:    48 8b 05 66 8e 20 00     mov    0x208e66(%rip),%rax        # 21bfd8 <[email protected]@Base-0x428>
   13172:    48 01 d0                 add    %rdx,%rax
   13175:    48 83 c0 0c              add    $0xc,%rax
   13179:    0f b6 00                 movzbl (%rax),%eax
   1317c:    84 c0                    test   %al,%al
   1317e:    74 4e                    je     131ce <_Z30csta_scm_baseServiceEventSetupP13STRUCT_CM_MSGiii+0xef>
   13180:    48 8b 0d 51 8e 20 00     mov    0x208e51(%rip),%rcx        # 21bfd8 <[email protected]@Base-0x428>
   13187:    8b 45 fc                 mov    -0x4(%rbp),%eax
   1318a:    48 63 d0                 movslq %eax,%rdx
   1318d:    8b 45 e4                 mov    -0x1c(%rbp),%eax
   13190:    48 63 f0                 movslq %eax,%rsi
   13193:    48 89 d0                 mov    %rdx,%rax
   13196:    48 c1 e0 03              shl    $0x3,%rax
   1319a:    48 01 d0                 add    %rdx,%rax
   1319d:    48 c1 e0 06              shl    $0x6,%rax
   131a1:    48 69 d6 d8 39 28 00     imul   $0x2839d8,%rsi,%rdx
   131a8:    48 01 d0                 add    %rdx,%rax
   131ab:    48 01 c8                 add    %rcx,%rax
   131ae:    48 05 00 0a 04 00        add    $0x40a00,%rax
   131b4:    0f b7 40 0c              movzwl 0xc(%rax),%eax
   131b8:    0f b7 c0                 movzwl %ax,%eax
   131bb:    89 c7                    mov    %eax,%edi
   131bd:    e8 8e 0d ff ff           callq  3f50 <[email protected]>
   131c2:    83 f8 01                 cmp    $0x1,%eax
   131c5:    75 07                    jne    131ce <_Z30csta_scm_baseServiceEventSetupP13STRUCT_CM_MSGiii+0xef>
   131c7:    b8 01 00 00 00           mov    $0x1,%eax
   131cc:    eb 05                    jmp    131d3 <_Z30csta_scm_baseServiceEventSetupP13STRUCT_CM_MSGiii+0xf4>
   131ce:    b8 00 00 00 00           mov    $0x0,%eax
   131d3:    84 c0                    test   %al,%al
   131d5:    0f 84 37 01 00 00        je     13312 <_Z30csta_scm_baseServiceEventSetupP13STRUCT_CM_MSGiii+0x233>
   131db:    48 8b 45 e8              mov    -0x18(%rbp),%rax
   131df:    c7 40 04 01 00 00 00     movl   $0x1,0x4(%rax)
   131e6:    48 8b 45 e8              mov    -0x18(%rbp),%rax
   131ea:    c7 80 08 01 00 00 00     movl   $0x0,0x108(%rax)

在xxx.txt文件中查找步骤2的地址131DF,
可以知道问题出在csta_scm_baseServiceEventSetup
(echo _Z30csta_scm_baseServiceEventSetupP13STRUCT_CM_MSGiii |   c++filt     )

或者直接使用addr2line命令查看错误出在哪个文件哪一行。

addr2line -e libcsta_scm.so 131df

总结

dmesg 查看崩溃的信息,计算崩溃地址。

objdump或addr2line 找出断点所在的文件及位置。

wordpress 502

wordpress 502


1.问题

搬瓦工逐步淘汰OpenVZ,OpenVZ 不能续费,只能重新选购KVM。意味着自己的wordpress要迁移到新的VPS。https://bandwagonhost.com/

安装完lnmp,数据库恢复、wordpress相关文件copy到新虚机,nginx配置,DNS解析,可以顺利访问网站,但是登陆后台部分页面出现502。

2.定位

nginx/1.14.0、mysql/5.5.60、php/ 5.6.36版本都是和原来一致的,试了网上的一些方法后都不行。然后自己乖乖的定位。 通过dmesg命令或 查看/var/log/syslog,发现php-fpm在调用libssl.so.1.1时出现段错误。

迁移前后的系统存在着差异,迁移前用的ubuntu 16.04,迁移后ubuntu 18.04,libssl版本一个1.0一个1.1,存在这差异。

3.解决

最后的解决方案,重新安装lnmp环境,php版本选择PHP 7.0.30,运行正常。
PHP 7.0.30依然依赖libssl.so.1.1但不会像5.5.60那样出现段错误,502页面也不出现了。


4.总结

以后干脆搞搞整成docker image得了。

5.题外话

迁移的时候看了两眼access.log,发现有人弱口令爆破自己的网站,哈哈哈。这小破站也值得搞?就怕贼惦记啊。
正好一直找不到好的弱口令集合,打算整理一下,整个弱口令集。

sprintf 段错误

sprintf 段错误

最近迁移代码测试功能的时候发现一个段错误,打印堆栈显示std::string析构时段错误。最后分析原因:sprintf造成字符数组内存溢出,踩内存,导致附近std::string对象被改修,析构时产生段错误。

原代码

if(response_code == 200)
{
	sprintf(temp,"HTTP请求成功[%s]", strResponce.c_str());
	dispPlayMsg("HTTP请求",index,temp,WEB_LOG);
	
	return TRUE;
}

strResponce为http的响应结果,平时的都是本公司的soap服务,返回
字节数都很少,测试时的服务返回长度超过temp长度,溢出,踩内存。

修改后

if(response_code == 200)
{
	//sprintf易造成越界,导致段错误
	snprintf(temp, sizeof(temp), "HTTP请求成功[%s]", strResponce.c_str());
	dispPlayMsg("HTTP请求",index,temp,WEB_LOG);

	return TRUE;
}

慎用sprintf,尽量使用snprintf。
原来工作中就遇到过sprintf造成的段错误。

printf/sprintf/NULL 空指针问题

printf/sprintf/NULL 空指针问题

最近从windows到linux 迁移代码,遇到了一个sprintf参数空指针段错误。

很疑惑,按说项目这么久不该出现段错误。

1.代码

原代码(用到msxml)

sprintf(pItemData.szNodeText,"%s",(const char*)nodeptr->Gettext());

移植后的代码(用到libxml2)

xmlCharTemp = xmlNodeGetContent(xmlChildNode);

sprintf(pItemData.szNodeText,"%s", (const char*)xmlCharTemp);

xmlFree(xmlCharTemp);

用什么xml解析库并不关键,关键是sprintf的参数都有可能是空指针。

于是乎实验了一下,发现vc++6.0 和 g++编译器存在差异性。

 

 

Windows-vc++6.0-sprintf截图

 

 

Linux-g++sprintf-截图

2.G++为什么会出现这种情况?

输出汇编代码

g++ test.cpp -S -o test.S

 .file "test.cpp"
.section .rodata
.LC0:
.string "%s"
.text
.globl main
.type main, @function
main:
.LFB0:
.cfi_startproc
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
movq %rsp, %rbp
.cfi_def_cfa_register 6
subq $32, %rsp
movq $0, -8(%rbp)
leaq -32(%rbp), %rax
movl $0, %edx
movl $.LC0, %esi
movq %rax, %rdi
movl $0, %eax
call sprintf
leaq -32(%rbp), %rax
movq %rax, %rdi
call puts
movq -8(%rbp), %rdx
leaq -32(%rbp), %rax
movq %rdx, %rsi
movq %rax, %rdi
call strcpy
leaq -32(%rbp), %rax
movq %rax, %rdi
call puts
movl $0, %eax
leave
.cfi_def_cfa 7, 8
ret
.cfi_endproc
.LFE0:
.size main, .-main
.ident "GCC: (GNU) 4.8.5 20150623 (Red Hat 4.8.5-28)"
.section .note.GNU-stack,"",@progbits


会发现两次调用sprintf,第一次调用的call sprintf,第二次调用的call strcpy。

3.printf也会存在类似的段错误

Windows-vc++6.0-printf截图

 

Linux-g++-printf-截图

 

g++汇编代码

.file "test2.cpp"
.section .rodata
.LC0:
.string "%s"
.LC1:
.string "%s \n"
.text
.globl main
.type main, @function
main:
.LFB0:
.cfi_startproc
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
movq %rsp, %rbp
.cfi_def_cfa_register 6
subq $32, %rsp
movl %edi, -20(%rbp)
movq %rsi, -32(%rbp)
movq $0, -8(%rbp)
movq -8(%rbp), %rax
movq %rax, %rsi
movl $.LC0, %edi
movl $0, %eax
call printf
movq -8(%rbp), %rax
movq %rax, %rsi
movl $.LC1, %edi
movl $0, %eax
call printf
movq -8(%rbp), %rax
movq %rax, %rdi
call puts
movl $0, %eax
leave
.cfi_def_cfa 7, 8
ret
.cfi_endproc
.LFE0:
.size main, .-main
.ident "GCC: (GNU) 4.8.5 20150623 (Red Hat 4.8.5-28)"
.section .note.GNU-stack,"",@progbits

会发现前两次调用的call printf,而第三次调用call puts。

 

4.总结

尽量不要期待编译器去做空指针的判断优化,因为大多数情况下你不知道编译器是怎么实现的,况且编译器间存在差距,自己保证参数的不为空指针。

 

最后代码无奈改成了这个样子。

sprintf(pItemData.szNodeText,"%s", xmlCharTemp!=NULL?(const char*)xmlCharTemp:"(null)");

参考:https://stackoverflow.com/questions/11589342/what-is-the-behavior-of-printing-null-with-printfs-s-specifier