Klocwork的常见错误和处理方法

klocwork扫描后的常见问题是分等级的:

1:Critical   2:Error   3:Warning     4:Review 等。

 

目前的部门要求处理1-2两个等级的问题,常见问题有以下几类:

 

1、函数中的异常处理缺少返回值

类似这种表述:

28 (Local) /home/cps/VersionUpdateTool/DBConfig_navigate.cpp:3626 FUNCRET.GEN (1:Critical) Analyze
Non-void function does not return value
Current status 'Analyze'

----------------------------------------

这种问题的处理,不用说就很简单啦,下面是网上的一个例子:

WORD32 Test(WORD32 *p, WORD32 *q)

{

     WORD32 dwBindType = 0;

     if ((NULL == p) || (NULL == q))

     {

         SF_ASSERT(0);

         return SFWD_ERROR;        //导致与预期返回的结果不符

     }

     return SFWD_OK;

}

断言需要做异常处理的,并不是断言就完事了,如果tr掉,继续往下走,可能会出现跑飞或单板重启等严重问题;

在release版本,断言是被忽略的;debug版本,适当增加断言,当出现异常时,容易定位问题。

 

 

2、函数在异常退出前务必要释放先前申请的内存

类似下面这种表述:

27 (Local) /home/cps/VersionUpdateTool/DBConfig_navigate.cpp:349 MLK.MIGHT (2:Error) Analyze
Possible memory leak. Dynamic memory stored in 'object' allocated through function 'new' at line 276 can be lost at line 349
  * DBConfig_navigate.cpp:271: Continue loop iteration, while j<s->_obIds.size() is true
  * DBConfig_navigate.cpp:276: Dynamic memory stored in 'object' is allocated by calling function 'new'.
  * DBConfig_navigate.cpp:349: Dynamic memory stored in 'object' is lost.
Current status 'Analyze'

----------------------------------------------

这种问题的处理大家也是一目了然,就是把一些new过的对象,忘记在某些位置释放的,按照报错的提示进行释放即可。

这种问题经常出现在某个函数内,中间有return或者continue的地方。

下面还是网上的一个例子:

 

SOCK_PKTINFO* Test(WORD32 dwReplyType)

{

    BYTE *pValidatePkt = NULL;

    SOCK_PKTINFO *pPktInfo = NULL;

 

    pValidatePkt = (BYTE *) XOS_GetUB(VER_REPLY_PKTLEN);

    if (NULL == pValidatePkt)

    {

        ROSNG_TRACE_ERROR("Error: XOS_GetUB failed!\n");

        return NULL;

    }

    MEMSET(pValidatePkt, 0, VER_REPLY_PKTLEN);

 

    if (TOPO_REPLY_OK == dwReplyType)

    {

        MEMCPY(&pValidatePkt[4], "YES", 4);

    }

    else

    {

        SF_ASSERT(0);

        XOS_RetUB(pValidatePkt);

        return NULL;

    }

    return pPktInfo;

}

这段代码其实有几个问题:

1.没有遵守谁申请谁释放的原则,C语言很容易出现内存泄漏,但遵守规范,这种泄漏就会少很多;

  除了申请的内存需要缓存而不是在一个消息中释放外(比如分片组包的情况),报文处理中基本上可以做到谁申请谁释放;

2.在异常流程,没有释放内存,这个是非常容易犯的错误;

3.如果是临时申请内存,应该使用PUB_GetLocalUB/PUB_RetLoacalUB这对接口;

 

再来一个例子:

      case *******

       {

            *****************

            *******************

            if(nums!=0)
            {
                CPS_ORM_msFlush(m_wiringSmHandle, 1);
                //delete[ ] obIds;
            }
            
            if(obIds!=NULL)
            {
                delete[ ] obIds;
            }

            
            break;
     }
    case MULTIPLE_CHOICE_DATA:
    {

           。。。。。。。。。

上面的例子中,如果重复delete,也会报错哦!

 

 

3、函数内对空指针进行引用操作

类似下面这种表述:

32 (Local) /home/cps/VersionUpdateTool/md5.cpp:267 NPD.FUNC.MUST (1:Critical) Analyze
Pointer 's' returned from call to function 'strdup' at line 263 may be NULL and will be dereferenced at line 267.
  * md5.cpp:263: 'mstr' is assigned the return value from function 'strdup'.
  * md5.cpp:265: s = mstr
  * md5.cpp:267: 's' is explicitly dereferenced.
Current status 'Analyze'

-------------------------------

这类问题的处理办法也没啥说的,就是使用前记得判断是否为NULL:

主要注意的是,判断后如果需要return,记得看一看问题2,是否需要释放内存,否则又会报出内存泄露的问题。

下面还是网上的例子:

VOID Test(SFWD_NBR_INFO *pNbrInfo)

{

    WORD32 *pIndex = NULL;

 

    if(NULL == pNbrInfo)

    {

        ROSNG_TRACE_ERROR("Error: Para is NULL!\n");

        SF_ASSERT(0);

        return;

    }

 

    if(0 == pNbrInfo->wActiveNbrNum)

    {

        pIndex = sfwd_node_new(sizeof(WORD32));

        if(NULL == pIndex)

        {

            ROSNG_TRACE_ERROR("Error: sfwd_node_new return NULL!\n");

            return;

        }

        * pIndex = pVifInfo->dwIndex;

       

    }

    XOS_RawPrint("gIndex = %d, pNbrInfo->dwNbrStatus = %d\n", * pIndex, pNbrInfo->dwNbrStatus);

    //这里如果没有执行上面if语句内的代码,就会导致对空指针进行操作;

    return;

}

不管是打印还是语句,只有是访问指针指向的内容,先想想这个指针有没有为空或非法地址的情况;

 

 

4、函数中数组操作的越界访问

类似这种表述:

 (Local) /home/cps/VersionUpdateTool/xml_split.h:111 ABV.TAINTED (1:Critical) Analyze
Array 'path' of size 1024 may use index value(s) 1024
  * xml_split.h:107: Array 'path' size is 1024.
  * xml_split.h:111: 'path' is passed as an argument to function 'strncat'.
    * OS_NS_string.inl:262: 'strncat' is called.
  * xml_split.h:108: Array 'path' of size 0 is retrieved from function 'memset'.
  * xml_split.h:111: Result of expression 'charlength($1)+min(charlength($2),$3)' is [0,1024].
Current status 'Analyze'

-------------------------------------------------

这类问题的处理在初始化时约定数组长度,并且在需要时判断长度即可。

下面是一个网上的例子:

 

WORD32 Test(SFWD_TOPO_PKT_CAP_IF_INFO_T *pIfInfo, WORD32 gIndex)

{

    WORD32 dwSubslot = 0;

    WORD32 dwSubindex = 0;

    WORD16 if_type = 0;

 

    if (NULL == pIfInfo)

    {

        ROSNG_TRACE_ERROR("sfwd_topo_pkt_cap_get_ifinfo: inParam is NULL!\n");

        SF_ASSERT(0);

        return FALSE;

    }

 

    if ((gIndex <= 0))

    {

        ROSNG_TRACE_ERROR("sfwd_topo_pkt_cap_get_ifinfo: Para error!\n");

        SF_ASSERT(0);

        return FALSE;

    }

 

    dwSubslot = gIndex / MAX_IF_NUMBER_PERCARD;

    dwSubindex = gIndex % MAX_IF_NUMBER_PERCARD;

    if((dwSubslot >= MAX_SUBCARD_NUMBER) || (dwSubindex > MAX_IF_NUMBER_PERCARD))  

    {

        ROSNG_TRACE_WARNING("sfwd_topo_pkt_cap_get_ifinfo: invalid subslot or subindex.\n");

        SF_ASSERT(0);

        return FALSE;

    }

    if_type = gInterface[dwSubslot][dwSubindex].wType;

    //在对gInterface数组进行访问时,如果dwSubslot、dwSubindex的下标值超出了该数组声明的大小可能产生越界。所以,需要根据代码的上下文来对数组的下标做有效性检查(并不是所有的数组访问都检查,有些是没必要的)

 

    return TRUE;

}

 

#define SFWD_SUBCARD_NO_CHECK(A, B)    ((A >= MAX_SUBCARD_NUMBER) || (B > MAX_IF_NUMBER_PERCARD))

数组越界也是经常犯的错误,对数组的访问,加一下检查;考虑到会频繁出现数组下标的检查,可以写一个类似上面的宏;

 

 

5、某些对象未初始化

类似这种表述的为未初始化:

(1)

(Local) /home/cps/VersionUpdateTool/main.cpp:705 UNINIT.STACK.MUST (1:Critical) Analyze
'wf.ulKeyNumber' is used uninitialized in this function.
  * main.cpp:700: 'wf.ulKeyNumber' is declared.
  * main.cpp:705: 'wf.ulKeyNumber' is used, but is uninitialized.
Current status 'Analyze'

 

(2)

20 (Local) /home/cps/VersionUpdateTool/VersionUpdate_workbench.cpp:3682 UNINIT.STACK.MIGHT (1:Critical) Analyze
'modelVersionShowDlg.m_pQuitBtn' might be used uninitialized in this function.
  * VersionUpdate_workbench.cpp:3615: g_versionName==2||g_versionName==3||g_versionName==5 is true
  * VersionUpdate_workbench.cpp:3681: 'modelVersionShowDlg.m_pQuitBtn' is declared.
  * VersionUpdate_workbench.cpp:3682: 'modelVersionShowDlg.m_pQuitBtn' is used, but is uninitialized.
Current status 'Analyze'

 

这类问题也很好处理,在构造或定义时,初始化即可。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值