1、返回值处理

①  对返回空的指针没有检查有效性就使用,导致隐患;

EAP_HANDLER_S *EAP_Handler()
{
    ...
    pstHandler = EAP_Handler_New(pstInstance);
    if(NULL == pstHandler)
    {
        return NULL;
    }
    ...
}

ULONG EAP_OFFLOAD_Authentication()
{
    pstTunnelHandler = EAP_Handler(pstInstance);
    if(ERROR_SUCCESS != EAP_MSCHAPV_TryOffLoad(pstTunnelHandler))
    {
        ....
    }
}

ULONG EAP_MSCHAPV_TryOffLoad(pstHandler))
{
    pstEapDs = pstHandler->pstEAP_Ds;   // 可能访问空指针 
    ......
}

 

②  对执行失败的情况没有处理,导致隐患;

ULONG SVPN_UAM_AddResGroup()
{
    pstResGroup = SVPN_Pub_SafeMalloc( ...,sizeof(SVPN_UAM_RESGROUP_S));
    if(NULL == pstResGroup)
    {
        return ERROR_FAILED;
    }
    
    (VOID)SVPN_UAM_AddResGroupToArray(pstResGroupHead, pstResGroup);
    ...
}

ULONG SVPN_UAM_AddResGroupToArray(SVPN_RESGROUP_HEAD_S *pstResGroupHead,
                                  SVPN_UAM_RESGROUP_S *pstResGroup)
{
    ULONG ulIndex = 0;
    ulIndex = SVPN_UAM_RESGROUP_INDEX(...);
    
    if(NULL != pstResGroupHead->ppstResGroup[ulIndex])
    {
        return ERROR_FAILED;
    }
}

 

③ 将不是BOOL类型的值强制转化为布尔类型;

ULONG NAT_DisplayStatistics(...)
{
    ulRet = IPC_RPC_SynCall();
    if( (BOOL_T)ulRet )           // 应该更换为 if(ERROR_SUCCESS != ulRet)
    {
        return ERROR_FAILED;
    }
}

 

④ 返回值比较的目标不是操作成功的返回值;

#if ( CONFIG_HA == TRUE )
if(ERROR_SUCCESS != HA_GetBoardType)   // 此处应该修改为if(HA_AMB != HA_GetBoardType)
{
    return ERROR_SUCCESS;
}
#endif

 

2、断言的使用

2.1、对程序运行中可能发生的情况使用断言处理

断言用于程序运行中不应该发生的情况进行检查;条件判断用于对程序运行过程中可能发生的情况进行检查

① 断言中不能含有业务逻辑,只能是逻辑表达式;

DBGASSERT (ulLen = (ULONG)strlen(pcString));
    
DBGASSERT(ERROR_SUCCESS == IF_GetDataByIfType(...,IF_TEMPLETNAME,,(szIPCLITemplate)));

 

② 对能发生的情况断言;

pszTemp = MEM_Malloc(MID_8021X|SID_DOTIX_EAD,usDataLen);
if( pszTemp == NULL )
{
    DBGASSERT(0);
    return ERROR_FAILED;
}

 

断言推荐用法:

① 模块当前支持的规格假设

ulNameLen = (ULONG)strlen(pHostName);
DBGASSERT(ulNameLen < DNS_DOMAINNAME_LEN);

 

② 模块的实现约束或者流程假设

switch(ulPrintType)
{
    case ACFP_PRINT_SERVER:
    {
        break;
    }
    default:
    {
        DBGASSERT(0);
        break;
    }
}

 

③ 函数参数合法性检查

ULONG DOTIX_TxReqID(IN_SC_MSG_S *pstMsg)
{
     DBGASSERT(NULL == pstMsg)
     ......
}

 

3、系统资源的使用

① 资源的申请释放不在同层次;

VOID ETH_VEMacOnMain(IN ULONG ulIfIndex ......)
{
    (VOID)IF_SelectHandle_Register(MID_ETHER, &ulSelHandle);
    while(BOOL_TRUE == IF_IsValidIfIndex(ulWalkIfIndex))
    {
        ...
        if(ulIfSlot == ulVERelySlot)
        {
            ...
            IF_SelectHandle_UnRegister(&ulSelHandle);   
            return;
        }
    }
    return;
}

 

② 在成对的系统资源操作之间异常退出

ULONG SVPN_SCFM_SaveDomainCfgFile()
{
    ulFileID = SVPN_SCFM_FOpen();
    ...
    if(ERROR_FAILED == ulRet)
    {
        ...
        return ERROR_FAILED;
    }
    SVPN_SCFM_FClose();
    return ulRet;
}

 

③ 资源申请应该在合法性检查和前提条件OK之后进行

VOID VRRP_SendLogPacketError()
{
    pduMsg = IC_CreateMsgPdu();
    if(NULL == pduMsg)
    {
        return;
    }
    
    if(pstStandBy->ucPacketErrorType == (UCHAR)ulType)
    {
        pstStandBy->ulCorrectPacketCnt = 0;
        return;
    }
}

 

④ 将申请的资源直接赋给间接变量:多级指针和全局变量

#define MAC_ADDRESS_LEN
#define MAC_LEN

*ppSendData = MEM_Malloc(MID_XXX,sizeof(UCHAR)*MAC_ADDRESS_LEN);
if(NULL == *ppSendData)
{
    return ERROR_FAILED;
}
MEM_Copy(*ppSendData,aucMacAddr,MAC_LEN);

 

ULONG MWI_AddEtity(...)
{
    pstEntity->pstAuthInfo = MEM_Malloc(MID_VOICE_SIP, sizeof(SIPAUTHINFO_S));
    if(NULL == pstEntity->pstAuthInfo)
    {
        return ERROR_FAILEDL;
    }
    
    MEM_Copy(pstEntity->pstAuthInfo, pstAuthInfo, sizeof(SIPAUTHINFO_S));
    ...
        
    if(NULL == pstLastEntity)
    {
        return ERROR_FAILED;
    }
}

 

4、内存释放

① 错误的释放函数

ULONG QOS_ATMSecondHalfTrans(IN ULONG ulIfIndex, IN MBUF_S *pstMBuf, IN VOID *pQoSDB)
{
    ...
    pstAtmPVC = (ATM_PVC_S *)(MBUF_GET_LINK_ATM_PVCINFO(pstMBuf));
    if(NULL != pstAtmPVC)
    {
        return QOS_ATMPVC_Transmit(pstAtmPVC, pstMBuf);
    }
    MEM_Free(pstMBuf);  /* 此处应该调用MBUF_Destroy函数*/
    return ERROR_FAILED;
}

 

 重复释放;

ULONG RD_PKT_AccessReject_Proc(RD_fmtPkt_s *pstPkt)
{
    pstAuthReject = MEM_Malloc(...,sizeof(SC_AUTHENFAILURE_S));
    if(NULL == pstAuthReject)
    {
        return SC_FAILED;
    }
    ....
    ulRet = RD_SendMsg(SC_MODULE_SRVCTRL,usMsgType,(ULONG)usUserIndex,
                       SC_OE_RDS_REJECT,(ULONG)pstAuthReject);
    if(SC_FAILED == ulRet)
    {
        MEM_Free(pstAuthReject);
    }
    
}

 

③  释放后再使用

ULONG FR_InarpReportSend(FR_INTERFACE_S *pstFrIf,....)
{
    (VOID)FR_SecondHalfTransmit(ulIfIndex, pMBuf, NULL);  
    ...
    FR_DEBUG_PACKET(pstFrIf, FR_PAC_OUT, &stFhQ992, ulMsgLen, (ULONG)FR_PAC_ARP, pMBuf); // FR_SecondHalfTransmit函数中pMBuf已经被释放
}
 

 

④ 释放前没有摘链

VOID PT_WEB_DelUser(IN_DLL_NODE_S *pstNode)
{
    pstUserInfo = (PT_WEB_USER_S *) DLL_GET_HANDLE(pstNode);
    MEM_Free(pstUserInfo);
    pstUserInfo = NULL;
    DLL_Delete(&g_stPtWebUserDll, pstNode);
    MEM_Free(pstNode);
    pstNode = NULL;
    return;
}

修改如下:

VOID PT_WEB_DelUser(IN DLL_NODE_S *pstNode)
{
    DLL_Delete(&g_stPtWebUserDll, pstNode);
    pstUserInfo = (PT_WEB_USER_S *)DLL_GET_HANDLE(pstNode);
    MEM_Free(pstUserInfo);
    MEM_Free(pstNode);
    return;
}

 

5、内存越界

① 字符串拷贝越界

ULONG CFM_ECF_BuildRun()
{
    ...
    ulLen = (ULONG)strlen(szCmdBuf);
    pcTmp = MEM_Malloc(MID_CFM|SID_CHAR, ulLen);
    if(NULL == pcTmp)
    {
        return ERROR_FAILED;
    }
    
    strncpy(pcTmp, szCmdBuf, ulLen);
    ...
}

 

② 字符串拼装越界

VOID FTPS_StartUserTask(ULONG ulExecID, ULONG ulSocketID)
{
    CHAR szTaskName[4];
    
    ulIndex = CLI_VecterSet(g_pstFtpUserVector, (VOID*)lpFTPUSerData);
    FTPS_InitFTPUserData(lpFTPUserData, lSocketID, ulExecID, ulIndex);
    (VOID)snprintf(szTaskName, "FC%d", ulIndex); // ulIndex可能为-1,此时需要占用5个字节,超出了4
    ...
    return;
}

 

③ strncpy拷贝长度使用错误;

CHAR szCertDomain[MAX_CERTDOMAIN_LEN + 1];
if(BOOL_TRUE != bUndoFlag)
{
    strncpyl(szCertDomain, pcDomain, (ULONG)strlen(pcDomain));  // 此处应该以目的缓冲区为依据,(ULONG)strlen(pcDomain) 应该修改为MAX_CERTDOMAIN_LEN
}

 

④ 内存清零错误,导致未初始化内容;

ULONG TEL_ConvertCRLF()
{
    CHAR *pcBuf = NULL;
    
    ulStrLen = (ULONG) strlen(pszSourceStr);
    pcBuf = (CHAR*)MEM_Malloc( MID_TEL_CLIENT, ulStrLen*2 + 1 );
    if(NULL == pcBuf)
    {
        return ERROR_FAILED;
    }
    
    MEM_ZERO(pcBuf,sizeof(pcBuf));  // sizeof(pcBuf)为4,只清零了4个字节
}

 

⑤ 计算字符串长度使用sizeof;

#define SVPN_CGI_URL_PATH_HEAD_LEN  (sizeof("/svpn.cn") - 1)  // 此处sizeof应该修改为strlen 

 

6、空指针/野指针

① 释放全局句柄资源后没有清理句柄本身;

(VOID)TWL_DeleteTwlInstance(g_ulAAATwlHandle);
  g_ulAAATwlHandle = TWL_INVALID_HANDLE;  // 此行不能遗漏

 

② 释放内存后没有清理数据结构上的指针;

ULONG WS_CM_Create()
{
    pstLinkCtrl = (WS_CM_CTL_S *) MEM_Malloc(MID_WS_CM, sizeof(WS_CM_CTL_S));
    ...
    g_astCtrl[ulIndex].pstCtrl = pstLinkCtrl;
    
    DLL_Init_Node(&(pstLinkCtrl->stList), pstLinkCtrl);
    
    if(...)
    {
        (VOID)MEMP_Free(pstLinkCtrl);
        return ERROR_FAILED;
    }
}

 

③ 访空指针;

ULONG ALTIPv6_NumAddNode()
{
    PACCESSLISTGROUP_IPv6_S pstGroup = NULL;
    
    if(ulAclNum < ACL_BAS_MIN)
    {
        ulErrCode = ACL_ERROR_INVALID_NUM;
        goto Exit;
    }
    ...
Exit:
    if(ACL6_SUCCESS == ulErrCode)
    {
        (VOID)ACL_IPv6_SendToDp(ulAclNum, ....);
    }
    ACLIPv6_SetGroupNextID(pstGroup);
    return ulErrCode;
}

VOID ACLIPv6_SetGroupNextID(PACCESSLISTGROUP_IPv6_S *pstGroup)
{
    switch(pstGroup->eGroupType)
    {
         ......
    }
}

 

7、未初始化

① 特定情况下对未初始化的结构变量的字段赋值,或者结构体成员初始化不完全;;

VOID PT_WEB_ProcWsConnInMsg()
{
    WS_CM_ASYN_S stSYN;
    if(CONNECTION_TYPE_SSL == pstNewConn->ulConnectType)
    {
        stSYN.ulEventID =SE_ASYNC;
    }
    
    stSYN.ulQueueID = g_ulPT_WebConAsyncQueMsgID;
    stSYN.ulPointer = ulConnID;
    stSYN.ulWakeTaskID = g_ulPT_MainTaskID;
}

 

② 函数的入参没有被初始化;

ULONG CFG_GetSlotIDFromMsg(...)    
{
    ULONG ulNoneSelfSlotMask;
    ...
    (VOID)HA_SetMemberSlot(ulBoard, &ulNodeSelfSlotMask);
}

 

8、代码冗余

① 反复多重间接寻址访问数据,反复调用相同或类似的大段代码

② 临时使用小内存(<256字节),不需要申请动态内存, 可以使用局部变量

③ 结构体成员每个都赋值;

④ 拷贝常量字符串;

(VOID) Res_LoadString(...,&pszResInfo);
sprintf(szBuf,pszResInfo);
if(EXEC_DISPLAY_STOP == EXEC_OutStringWait(ulExecID, szBuf,&ulCurLine))
{
    return ERROR_FAILED;
}

可以修改为如下

(VOID) Res_LoadString(...,&pcResInfo);
if(EXEC_DISPLAY_STOP == EXEC_OutStringWait(ulExecID, pcResInfo,&ulCurLine))
{
    return ERROR_FAILED;
}

⑤ 没有必要为字符串申请静态的数据空间;

#define  DP_NATPT_LOG_BUFFER_SIZE  512
枚举 DP_NATPT_MAXMUM 的值为61

CHAR g_szDPNatptDbgMsg[DP_NATPT_MAXMUM+1][DP_NATPT_LOG_BUFFER_SIZE]=
{
    "The pointer to MBUF is null. \r\n";
    "Failed to malloc memory for natpt,so drop the packet. \r\n";
    "Failed to TR send \r\n";
    ...
}

上述全局变量 g_szDPNatptDbgMsg 占用的空间为 62 * 512 = 31K 字节

修改如下:

CHAR *g_apcDPNatptDbgMsg[DP_NATPT_MAXMUM+1]
{
    "The pointer to MBUF is null. \r\n";
    "Failed to malloc memory for natpt,so drop the packet. \r\n";
    "Failed to TR send \r\n";
    ...
}

 

⑥  反复计算循环条件

ULONG CFM_GetDividerNum(const UCHAR *pucFileName)
{
    for(ulLoop = 0; ulLoop<(ULONG)strlen((CHAR*)pucFileName);; ulLoop++)
    {
        ......
    }
}

 

9、编程接口

模块接口或者驱动接口使用错误,导致功能或资源类问题异常

 

10、资源型接口设计

① 释放参数携带的资源时规则不一致:例如成功时释放,失败时不释放

② 复合资源的申请和释放没有封装 或申请释放函数封装不对称

③ 资源创建/获取型函数没有将资源作为返回值,而是作为输出参数

posted on 2024-11-20 22:25  轩~邈  阅读(68)  评论(0)    收藏  举报