Segmentation fault定位 mips无事,x86挂死

进程挂死问题记录

背景

进程处于开发设备中中运行良好,输入指令无异常,近期部门为了调试方便,在编译环境中加入了x86_64环境,用于方便调试,同样指令x86_64中出现挂死现象。

现象

输入指令进程挂死
在这里插入图片描述
输入同样指令进程正常
在这里插入图片描述

分析

进程挂死后,查看日志文件中保存的挂死堆栈信息时发现,在执行strncmp过程中,进程挂掉。
在这里插入图片描述
查看命令对应的代码发现
在这里插入图片描述

分析函数入参发现第二个参数为固定字符串大小,第一个参数为外部传参,大致可定位是第一个参数导致挂死,对cipher地址进行打印出现0xffffffff9338c560,高8位地址出现全f,访问地址处于内核地址,导致挂死,至此问题定位于在编译执行过程中变量cipher被意外改变导致进程挂死。

定位

在这里插入图片描述

追踪cipher从申请到使用时地址变化,加%p打印发现调用函数内部定义变量申请内存后地址为0x55919338c560,函数返回后返回的函数地址为0xffffffff9338c560,高8位被截断且进行补全1操作,至此问题定位。

原因

平台架构不同,原先的设备环境mips为32位架构,现用于调试的x86为64位架构,函数指针在返回时进行了符号扩展操作,但为什么会出现符号扩展呢?
对编译过程中对于此文件的编译进行分析,发现在编译过程中出现告警提示
在这里插入图片描述

编译过程中未找到函数的定义,会发生隐式的整型向指针的转换,在x86_64中编译器会帮我们隐式定义一个int返回,即是有符号的32位给无符号的64位进行赋值,此时产生符号扩展。
在于C89有一个隐式声明规则(implicit declaration),当需要调用一个函数但找不到函数原型时,编译器会提供一个隐式声明,该隐式声明会假定函数返回值类型为int,C99已经去掉了这一规则,要求函数调用必须有函数声明,但gcc可能为了兼容老代码,并没有强制执行C99,只是给出了一个警告。在我们这个例子里,gcc找不到函数salt的原型,于是假定函数salt的返回值类型是int。

验证

为了验证我们的猜想,对编译出的文件使用objdump进行反汇编操作,查看salt函数返回过程中是否发生4字节向8字节的符号扩展。
在这里插入图片描述
如图在赋值时出现了movslq操作,证明此时有4字节向8字节的扩展操作。

解决方法

在文件中加入被调用函数的额外申明,或者加入头文件的引用,使编译器能够正确找到函数的定义,消除掉告警中的隐式转换。

总结

1.编译的时候最好加上 -Werror 参数,它要求GCC将所有的警告当成错误进行处理
2.灵活使用日志文件,打印等工具对问题进行分析定位
3.写代码时考虑应当跨平台产生的影响
在这里插入图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

吃饭第一名QAQ

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值