看见了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小时内删除。
发表评论