看着貌似吓人的底层问题,其实错在原本的自身

过程   

近期遇到一个问题,一个在Linux下运行的C语言程序,突然因为某段代码合入后,就导致程序稳定崩溃!

程序崩溃的位置只是具有一个大方向,崩溃堆栈位置不定,而且是某些不应该出现的运行堆栈逻辑,以及曾出现过非法指令的信号异常core文件。

通过逐步试验,发现:

1、撤销掉新增的代码合入,就不会出现问题;还据此发布了版本

2、如果使用O0编译程序,就不会出现崩溃问题;但使用O3优化编译就出现崩溃。怀疑是因为某些编译器代码优化导致的问题,这个就深层次了:(  看着听吓人的!

3、旁路掉某一个模块的代码,也不会出现问题

当时,是一头雾水,搞不清楚明确的方向!

幸运的时,将研究的重点放在旁路的模块中,通过对代码不断二分旁路,找到问题的根源在于,某段代码对于栈内存的非法覆盖。

示例代码

// 出错代码示意

typedef struct {
    int msgType;
    unsigned int msgLen;
    // C语言结构体的惯用法,指向头部区域后面第一个字节
    unsigned char abData[0];
} T_SomeAck; 




void f(T_SomeAck* ptAck)
{
  ...

  memcpy(ptAck->abData, srcData, someSize);

  ...
}



int main(int argc, char **argv)
 {
    // 栈上没有分配那么大的内存;
    // 解决办法: 
    // 1、结构体定义足够内存 
    // 2、符合C语言结构体此类惯用法,从大的缓冲区中转型;用具体结构体定义,区分头部和尾部

    T_SomeAck  tAck;
    
    ...

    f(&tAck);

    ....

    return 0;
  
 }



结论

回想整个问题解决过程,才逐渐明白过来,就一个非法指令的信号异常处理现象,以及其它莫名奇妙、不该运行的崩溃堆栈,就可以怀疑到是因为内存被非法覆盖后引起的崩溃问题。

因为非法覆盖的是函数返回地址等关键信息,最终导致的崩溃!


附录

照例说,valgrind可以发现栈内存越界的问题,后面再试试故障场景是否可以使用工具发现

# valgrind 可以检查出此处的内存异常

#include <stdlib.h>
#include <stdio.h>
#include <string.h>

static int foo(void)
  {
      int a = 1;
      char b[32];

      printf("before memset\n");
      memset(b, 0, 64); /* stomps the stack */
      printf("after memset\n");

      return 0;
  }


 int main(int argc, char **argv)
 {
     int x;

     printf("before foo()\n");
     x = foo();
     printf("after foo()\n");
     return 0;
 }

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值