一起空指针引发的程序问题的排查过程

      【文章摘要

       在C程序中,指针操作是难点和精华所在。指针一旦使用不当,极有可能造成程序的崩溃。

       本文对一空指针引发的程序问题的排查过程进行了详细的介绍,为相关软件问题的分析及解决提供了有益的参考。

 

        一、问题描述

       最近,某程序在测试过程中突然崩溃。日志中出现如下内容:

       #0  0xf64f2b3a in FunctionA(event=666,dlgindex=0, ucErrNo=1 '\001') at src/A.c:6838

       #1  0xf64e3a4f in FunctionB(in=0x80efd4d"") at src/A.c:2781

       #2  0xf64dba3b in FunctionC(in=0x80efd4d"", out=0x0, dataPtr=0x0) at src/A.c:303

 

        二、日志内容分析

        通过以上日志文件内容,我们可以看出如下信息:

        第一,程序最终是在FunctionA函数中崩溃的,该函数有三个入参:event、dlgindex和ucErrNo。其中,出问题时的event为666,dlgindex为0,ucErrNo为1。

        第二,调用FunctionA的是FunctionB函数,该函数只有一个入参:in。

 

        三、问题的排查过程

       通过对日志内容的分析,我们查看了event为666的程序代码,主要用于从数据库中获取某几个系统参数的值。其整个执行流程如图1所示。

图1 程序执行流程

 

         通过图1,我们可以看到,程序问题出现在了数据库在设定的时间之内没有应答而进入超时处理的流程中。

         我们又仔细查看了日志信息,发现出问题的地方在“A.c”文件的第6838行。该行及前一行代码如下:

         pReq  = (T_RetInfoFromReqMsg*)DlgBuf[dlgindex].para;  (6837行代码)

         flowid  = pReq->flowid;                               (6838行代码)

        第6837行代码对pReq指针赋值,第6838行代码将pReq对应的结构体中的flowid变量赋给整型变量flowid。

        看到这里,我们就怀疑“DlgBuf[dlgindex].para”指针的值有问题。我们又仔细查看了程序代码,发现该指针是在向数据库发消息的函数中被赋值的。其代码如下:

UINT32 SendToDB(…, UINT8 *para, UINT32 paraLen)

{

    ……

    if ((para != NULL)&& (paraLen > 0))

    {

        memcpy(DlgBuf[iDlgIndex].para, para,(int)paraLen);

    }

    ……

}

        整个DlgBuf是在程序刚启动的时候被初始化的。我们又看了调用SendToDB函数的代码行,如下:

SendToDB(…, NULL, 0);

        可以看到,传入的para指针的值为空(NULL),paraLen的值为0。根据SendToDB函数的代码流程,DlgBuf[iDlgIndex].para不会被赋值,那么它就会为空(NULL)。

       这就是程序问题的原因所在。向数据库发消息的时候,DlgBuf[iDlgIndex].para指针为空(NULL),那么在处理数据库超时的流程中,因为序列号是同一个,则DlgBuf[dlgindex].para指针也为空(NULL),这也导致pReq指针为空。后面要用到该指针对应的结构体中的值,就会找不到,因此程序便崩溃了。

       为了验证我们的想法是否正确,我们修改了调用SendToDB函数的代码,不传空指针进去,如下:

T_RetInfoFromReqMsg tRetInfoFromReqMsg = {0};

……

SendToDB(…, &tRetInfoFromReqMsg, sizeof(T_RetInfoFromReqMsg));

        对修改后的程序进行测试,就不会出现问题了。

 

        四、总结

        通过本次问题排查,我们总结出的经验有以下几个:

        (1) 对于指针的使用,一定要小心。对于重要的指针,一定要先检查其是否有准确的值之后再使用,避免使用空指针。

        (2) 不管是在哪个函数中,在使用指针之前,一定要先检查该指针是否为空(NULL)。这也算是对程序进行异常保护。

 

        程序问题在所难免,但解决问题的方法也是千变万化。确实,只要我们善于总结,善于分析,那么任何程序问题都是可以解决的。

 

 

 

 

(本人微博:http://weibo.com/zhouzxi?topnav=1&wvr=5,微信号:245924426,欢迎关注!)

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

周兆熊-IT

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

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

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

打赏作者

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

抵扣说明:

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

余额充值