看见了If,就想Else
看见malloc,就去Free
函数调用要小心,需要看看返回值。
看到for循环,就边界值。
看见return要注意,要去前面资源。
看见数组把神提,问题往往在下标。
不要小看字符串,长度是个大问题。
得到函数不要急,看看变量初始化,各种路径要小心。
赋值函数最危险,变量没有初始化。
九句句真言不孤立,相互结合显神威。
真言详解
1. 看见If,就想Else
看到if语句,就要想到else语句。如果没有else语句,就要分析是不需要,还是异常情况没有处理,如果是异常情况没有处理,可以提单。
2. 看见malloc,就去Free
看到malloc语句分配了内存,立即停下正常走读,看malloc代码之后,是否在所有程序的返回分支中都有释放语句。
典型案例:
U32 DEV_IfSetSectionEnable(DEV_IF_T *pIfIns)
{
    CHAR * pSectionName = NULL;
    ULONG ulMsg[4];
   
    /* 向配置文件发送消息write的返回值DEV_IF_READ_SECTION, 进行配置下载 */
    pSectionName = VOS_Malloc(MOD_DEV, MAX_INTERFACE_NAME_LEN+1);
    if ( pSectionName != NULL )
    {
        VOS_strcpy(pSectionName,pIfIns->ifName);
        ulMsg[0] = MID_DEV;
        ulMsg[1] = MID_CFM;
        ulMsg[2] = DEV_CFM_ENABLE_SECTION;
        ulMsg[3] = (ULONG)pSectionName;
        VOS_Que_Write(ulVRPQID_CFM , ulMsg, VOS_NO_WAIT, 0);
        return SUCCESS;
    }
    return DEV_ERR_NOMEMORY; 
   
}
该函数有了VOS_Malloc,但没有看到free。于是在下面的代码中寻,发现VOS_Que_Write中自动实现free功能。代码看似没有问题,但我们发现VOS_Que_Write的返回值没有判断,如果VOS_Que_Write返回失败,free语句就没有被执行到。这样可以确认该函数存在内存泄露隐患。该代码最终修改:
U32 DEV_IfSetSectionEnable(DEV_IF_T *pIfIns)
{
    CHAR * pSectionName = NULL;
    ULONG ulMsg[4];
    ULONG rc;
   
    /* 向配置文件发送消息DEV_IF_READ_SECTION, 进行配置下载 */
    if(pIfIns == NULL || (VOS_strlen( pIfIns->ifName) > (MAX_INTERFACE_NAME_LEN+1)))
    {
        return DEV_ERR_GEN;
    }
       
    pSectionName = VOS_Malloc(MOD_DEV, MAX_INTERFACE_NAME_LEN+1);
    if ( pSectionName != NULL )
    {
        VOS_strcpy(pSectionName,pIfIns->ifName);
        ulMsg[0] = MID_DEV;
        ulMsg[1] = MID_CFM;
        ulMsg[2] = DEV_CFM_ENABLE_SECTION;
        ulMsg[3] = (ULONG)pSectionName;
        rc = VOS_Que_Write(ulVRPQID_CFM , ulMsg, VOS_NO_WAIT, 0);
        if(rc != SUCCESS)
        {
            rc = VOS_Free(pSectionName);
            VOS_DBGASSERT(rc == VOS_OK);
            return DEV_ERR_GEN;       
        }
        return SUCCESS;
    }
    return DEV_ERR_NOMEMORY; 
   
}
3. 函数调用要小心,需要看看返回值。
看到函数调用,要养成习惯,进入函数内部瞄一眼。看看函数的正常值和异常值都是什么。看看返回值需不需要判断。看看有没有参数理解不一致的地方。例如:
    if ( VOS_strnicmp(szFullName, DEV_ATM_NAME , DEV_ATM_NAMELEN) == 0 )
    {
        ulIfType = DEV_GetIfTypeFromIfName( szFullName );
        if ( ulIfType == -1 )
        {
            EXEC_OutString( ulExecID, "\r\nUnknown interface type" );
            return VOS_ERR;
        }   
        /*得到端口的索引*/
        ulRet = DEV_GetIfIndexFromIfName( szFullName, &ulIfIndex);
        if (SUCCESS  !=  ulRet)
        {
            EXEC_OutString( ulExecID, "\r\nUnknown interface number" );
            return VOS_ERR;
        }
        /*判断端口是否已经存在*/
                pIfIns = DEV_GetIfFromIndex(ulIfIndex);
        if(NULL == pIfIns)
        {
            rc = DEV_Cnsl_CreateIf(ulExecID, ulIfType, ulIfIndex, ulSubType);
            if(SUCCESS != rc)
            {
                return SUCCESS;
            }
            pIfIns = DEV_GetIfFromIndex(ulIfIndex);
            if(NULL == pIfIns)
            {
            COUT_OUTPUT_DIAG(MOD_DEV, COUT_LEVEL_WARNING, "pIfIns = NULL is invalid %s.%d"
                , __FILE__, __LINE__);
                return DEV_ERR_GEN;
            }
函数使用-1作为非法值,而在DEV_GetIfTypeFromIfName函数中:
U32 DEV_GetIfTypeFromIfName(CHAR *ifName)
{
    CHAR szIfType[20]; //接口的类型字符串
    U32    ulIfType;
    U32 strLen;
    U32 i;
    if(NULL ==ifName)
    {
    COUT_OUTPUT_DIAG(MOD_DEV, COUT_LEVEL_WARNING, "ifName = NULL in GetIfTypeFromIfName  %s.%d", __FILE__, __LINE__);               
    return DEV_ERR_VALUE;
    }
    strLen = VOS_strlen(ifName);
    if(0 == strLen)
    {
        /*字符串为空,返回错误*/
    COUT_OUTPUT_DIAG(MOD_DEV, COUT_LEVEL_WARNING, "strlen = 0 %s.%d", __FILE__, __LINE__);               
        return DEV_ERR_VALUE;
    }
       
    VOS_Mem_Set(szIfType, 0, sizeof(szIfType));
    /*---------------------------------------------------------*/
    /*从字符串的尾部向前查,直到到第一个不是数字的字符    */
    /*---------------------------------------------------------*/
    for(i = strLen-1; i >= 0; i--)
    {
        /*字符不等于'.', '/'或数字字符时循环结束*/
        if(ifName[i] != '.' && ifName[i] != '/'
            && (ifName[i] < '0' || ifName[i] > '9'))
            break;
    }
    VOS_strncpy(szIfType, ifName, i+1);
    ulIfType = DEV_IfStringToType( szIfType );
    return ulIfType;
}
函数的一个错误返回值是DEV_ERR_VALUE很显然,两边参数理解不一致。
4. 看到for循环,就边界值。
看到for循环,就要看看边界值是否合理。如果循环变量是数组的下标,更加需要注意。例如:
U8* DEV_IfTypeToString(U32 ulIfType)
{
    U32 i;
    // change to user type
    ulIfType = DEV_IfUserType(ulIfType);
   
    for(i=0;ulIfType != -1 && i<DEV_USERIFTYPE_NUM
            && UserIfTypes[i].ulIfType!=-1;i++)
    {
        if (UserIfTypes[i].ulIfType == ulIfType)
            return UserIfTypes[i].pIfTypeString;
    }
    return "unknown-interface";
}
函数中:
#define DEV_USERIFTYPE_NUM  9     // number of UserIfTypes, NOT DEV_IFTYPE_MAX_NUM!!!
而数组:
    static IfTypeList_S UserIfTypes[] =
    {
        { DEV_IFTYPE_ATM, "Atm", "ATM interface" ,3, 0, DEV_AATMIF_LOGIF_MAX_NUM},
#ifndef ISN_MODIFIED
//Modified by:  liyanmin

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。