低级错误案例集汇总.docx

上传人:b****3 文档编号:11148301 上传时间:2023-05-29 格式:DOCX 页数:72 大小:46.13KB
下载 相关 举报
低级错误案例集汇总.docx_第1页
第1页 / 共72页
低级错误案例集汇总.docx_第2页
第2页 / 共72页
低级错误案例集汇总.docx_第3页
第3页 / 共72页
低级错误案例集汇总.docx_第4页
第4页 / 共72页
低级错误案例集汇总.docx_第5页
第5页 / 共72页
低级错误案例集汇总.docx_第6页
第6页 / 共72页
低级错误案例集汇总.docx_第7页
第7页 / 共72页
低级错误案例集汇总.docx_第8页
第8页 / 共72页
低级错误案例集汇总.docx_第9页
第9页 / 共72页
低级错误案例集汇总.docx_第10页
第10页 / 共72页
低级错误案例集汇总.docx_第11页
第11页 / 共72页
低级错误案例集汇总.docx_第12页
第12页 / 共72页
低级错误案例集汇总.docx_第13页
第13页 / 共72页
低级错误案例集汇总.docx_第14页
第14页 / 共72页
低级错误案例集汇总.docx_第15页
第15页 / 共72页
低级错误案例集汇总.docx_第16页
第16页 / 共72页
低级错误案例集汇总.docx_第17页
第17页 / 共72页
低级错误案例集汇总.docx_第18页
第18页 / 共72页
低级错误案例集汇总.docx_第19页
第19页 / 共72页
低级错误案例集汇总.docx_第20页
第20页 / 共72页
亲,该文档总共72页,到这儿已超出免费预览范围,如果喜欢就下载吧!
下载资源
资源描述

低级错误案例集汇总.docx

《低级错误案例集汇总.docx》由会员分享,可在线阅读,更多相关《低级错误案例集汇总.docx(72页珍藏版)》请在冰点文库上搜索。

低级错误案例集汇总.docx

低级错误案例集汇总

TOP1资源泄漏

资源泄漏(包括内存泄漏)是代码Review中最常见的错误之一,申请的每个资源必须明确由谁负责释放,何时释放,在何处释放;在异常/错误/返回处理中,保持清醒的头脑,清理战场。

此处的资源还包括信号量、定时器、文件句柄等系统资源。

案例1.1

【问题描述】

宏里面有return语句导致内存泄漏案例一。

【问题分析】

1)错误代码:

/*定义宏MODEL_ASSERT_RETFAIL*/

#defineMODEL_ASSERT_RETFAIL(X)\

{\

if(X不合法)\

return;\

}

….//dosomething

MDSTrafficMsg*pMsg=VOS_AllocMsg(PID_MD,usLength);

if(NULL_PTR==pMsg)

{

return;

}

MDSDataListenerMgr*pDataListener=MDSDataInitalListenerMgr();

MODEL_ASSERT_RETFAIL(pDataListener);

2)分析:

使用宏MODEL_ASSERT_RETFAIL检查pDataListener是否合法,如果不合法,则直接返回,一旦返回,将导致前面通过指针pMsg申请到的消息包资源泄漏。

【纠正方法】

在宏MODEL_ASSERT_RETFAIL分支判断return前加上VOS_FreeMsg(PID_MD,pMsg):

该方法代码不够清晰,当用户看宏定义时,对VOS_FreeMsg(PID_MD,pMsg)不清楚还要跳回来看前面的代码。

设定该宏有返回值(指针不为空返回VOS_True,否则为VOS_False),将宏的return语句写在宏使用后(判断指针pDataListener合法性),若宏返回VOS_False释放pMsg并返回主调函数:

该方法在遇到只判断一个指针的合法性时,浪费代码行、降低代码飞检效率且可能存在宏描述歧义等问题,简单的判断建议不使用宏。

【经验教训】

在XX版本的一个新模块的开发中,在发布之前进行大话务量测试验证时,发现系统内存资源不足,当时发布在即,经过协调多个技术专家封闭攻关,花了三天时间终于发现问题所在,人力成本高达3000元,对于内存使用,要确保释放闭环,所有异常退出点都需要释放内存。

案例1.2

【问题描述】

宏里面有return语句导致内存泄漏案例二。

【问题分析】

1)错误代码:

头文件中的宏定义如下:

#defineNODE_RETURN_ERROR(p)\

{\

if(NULL==p)\

{\

VOS_RECORD_ERROR(p);\

returnNULL;\

}\

}

文件中有个函数有如下代码段:

...//dosomething

pNode=(Node_Head_S*)malloc(sizeof(Node_Head_S));

NODE_RETURN_ERROR(pNode);//第一次使用宏

pBody=(Node_Body_S*)malloc(sizeof(Node_Body_S));

NODE_RETURN_ERROR(pBody);//第二次使用宏

...//dosomething

2)分析:

当通过指针pBody申请内存,然后通过宏NODE_RETURN_ERROR来判断是否申请成功,如果申请失败,则在宏NODE_RETURN_ERROR里面就直接返回了,这样导致通过指针pNode申请的内存泄漏了。

【纠正方法】

不使用宏,或将宏中的return语句写到宏调用后。

案例1.3

【问题描述】

异常出口没有释放应该释放的内存案例一。

【问题分析】

1)错误代码:

//GetBuff函数的作用是申请动态内存

pMsgDB_DEV=(PDBDevMsg)GetBuff(sizeof(DBDevMsg),__LINE__);

if(NULL==pMsgDB_DEV)

{

return;

//GetBuff函数的作用是申请动态内存

pMsgDBApp_To_Logic=(LPDBSelfMsg)GetBuff(sizeof(DBSelfMsg),__LINE__);

if(NULL==pMsgDBApp_To_Logic)

{

return;

}

2)分析:

在第2个return处,pMsgDB_DEV指向的内存丢失。

【纠正方法】

在第2个return处增加释放内存的操作。

【经验教训】

函数中有动态申请内存,要在函数范围内检查所有return语句是否释放该return语句前所有动态申请的内存。

案例1.4

【问题描述】

申请过的内存的指针没有释放,又申请新的内存给它。

【问题分析】

1)错误代码:

/*申请新的内存大小*/

pTmp=VOS_Malloc(pMacroEdit->ulMacroLen+1);

if(NULL==pTmp)

{

returnFAILURE;

}

VOS_MemSet(pTmp,'\0',pMacroEdit->ulMacroLen+1);

......

/*又申请新的内存*/

pTmp=VOS_Malloc(sizeof(TTTT_RPC_MSG_S));

if(NULL==pTmp)

{

returnFAILURE;

}

…….

VOS_Free(pTmp);

2)分析:

第一次申请的内存没有释放就使用同一个指针又申请了内存。

这样第一次申请的内存就永远没办法释放了,造成了内存泄漏。

【纠正方法】

第2次申请内存前,先释放掉第1次申请的内存。

同时我们应该注意到这个案例中对于申请的内存使用的指针变量是个临时变量,其命名没有十分明确的承载其所指向内存的含义,这样命名是不规范的,也许恰恰就是因为这点,才引发了后面继续直接使用.

案例1.5

【问题描述】

异常出口没有释放应该释放的资源。

【问题分析】

1)错误代码:

intr_lock();

/*填充消息*/

ulResult=DEV_MA_FillMsg(pMsg,ucPrimID,usBIndex,ucSerailID);

if(ulResult!

=MSP_RETURN_NO_ERR)

{

VOS_FreeMsg(PID_DEV,pMsg);

returnulResult;

}

intr_unlock();

……

2)分析:

return前没有调用intr_unlock()释放中断信号量。

【纠正方法】

return前释放中断信号量。

案例1.6

【问题描述】

分支考虑不全,导致某些分支中内存泄漏。

【问题分析】

1)错误代码:

/*创建消息,并放入消息队列中,假设处理成功*/

pMsg=CreateQueueMsg(j);

mu=SortOperation(pMsg);

if(mu<=0){

ret=0;

}

elseif(mu<=5){

ret=SendMsgToMu(pMsg,mu-1);

}

if(ret<=0){

/*从队列中删除消息,并释放*/

RemoveQueueMsg(j);

}

2)分析:

mu>5的分支,根本没有考虑,内存泄漏。

【纠正方法】

增加mu>5时对内存的释放处理。

案例1.7

【问题描述】

多个判断放在一起进行导致内存泄漏。

【问题分析】

1)错误代码:

char*pszInfoBuf1=VOS_NULLPTR;

char*pszInfoBuf2=VOS_NULLPTR;

pszInfoBuf1=(char*)VOS_Malloc(MID_BVLAN,ulBuffLen);

pszInfoBuf2=(char*)VOS_Malloc(MID_BVLAN,ulBuffLen);

if((pszInfoBuf1==NULL)||(pszInfoBuf2==NULL))

{

returnVOS_ERR;

}

2)分析:

当pszInfoBuf1申请成功,但pszInfoBuf2申请失败时,if语句被执行,pszInfoBuf1指向的内存泄漏了。

【纠正方法】

将两处申请内存后的有效性判断分开进行。

 

案例1.8

【问题描述】

内存重复释放可能产生不可预知的后果。

【问题分析】

1)错误代码:

voidNbvmConfirmBrdVer(NBOM_TRANS*pstTrans)

{

…………

if(NULL!

=pstTrans->pbDynMem)

{

pstSelfBoardBootRomInfo=(NBVM_SELF_BOARD_BOOTROM_INFO*)(void*)pstTrans->pbDynMem;

}

NBVM_MEM_FREE(pstSelfBoardBootRomInfo);

NBVM_MEM_FREE(pstBrdAllSwInfo);

NBVM_MEM_FREE(pstTrans->pbDynMem);

NBVM_MEM_FREE(pstTrans->pPrivatePtr);

}

2)分析:

上述红色代码造成了pstTrans->pbDynMem所指向的内存重复释放。

【纠正方法】

内存重复释放可能产生不可预知的后果:

假如任务A申请了内存块M,使用后释放M;系统可能把空闲的M分配给了任务B,当任务A重复释放M后,把本来属于任务B的该内存块误释放;此时系统认为空闲的内存块M又可能分配给任务C,C随后对这个内存块的写操作对于任务B来说就是非法操作,可能导致任务B运行异常。

 

案例1.9

【问题描述】

系统运行过程中,出现堆内存不足。

【问题分析】

1)错误代码

typedefstructtagWordStat{

char*pszWord;

ULONGulSum;

floatfrate;

structtagWordStat*psnext;

}WORDSTAT_S,*PWORDSTAT_S;

psWordName=(char*)malloc(ulCurWordLen+1);

if(NULL==psWordName)

{

returnVOS_ERR;

}

/*获取字符串*/

VOS_strncpy(psWordName,strName,ulCurWordLen);

...

/*建立新节点*/

pstWordStat=(PWORDSTAT_S)VOS_Malloc(sizeof(WORDSTAT_S));

if(NULL==pstWordStat)

{

VOS_Free(psWordName);

returnSTAT_ERR;

}

memset(pstWordStat,0,sizeof(WORDSTAT_S));

pstWordStat->pszWord=psWordName;

psWordName=NULL;

pstWordStat->ulSum=1;

pstWordStat->psnext=NULL;

ulTotalWordNum++;

...

/*释放节点*/

VOS_Free(pstWordStat);

...

2)分析

在释放节点时,只释放申请的部分内存。

在这段代码中,字符串存放申请了一段内存,建立链表的节点又申请了内存,最后只释放了链表节点内存,没有释放字符串存放时申请的内存。

【纠正方法】

先释放结构体内指针成员申请的内存,再释放结构体指针指向的内存。

释放结构体节点内存时,一定要搞清楚节点内部是否还有需要释放的内存,否则会导致这段内存永远得不到释放。

TOP2内存越界

所谓内存越界就是申请了内存,使用时超出了申请的范围。

发生内存越界的情况,往往出错的地方不是真正内存越界的地方,带来的影响滞后,而且难以定位,需要程序员养成良好编程习惯,对指针,内存拷贝,字符串操作等注意前后空间的变化,可以做一些必要保护。

 

案例2.1

【问题描述】

数组下标访问越界。

【问题分析】

1)错误代码:

/*初始化Q922的I帧链路索引地址表*/

ulSize=sizeof(INDEX_Q922IFRAME_MAPPING_STRU**)*DCOM_MAXSERVICEQ922LINK;

//g_ppstQ922IFrameIndex[]申请的长度是DCOM_MAXSERVICEQ922LINK

g_ppstQ922IFrameIndex=(INDEX_Q922IFRAME_MAPPING_STRU**)VOS_MemAlloc(VOS_PID_COMM,STATIC_DOPRA_MEM_PT,ulSize);

...

VOS_UINT32Q922_AddLink(......)

{

...

if(usLinkNo>DCOM_MAXSERVICEQ922LINK)

{

ulRet=VOS_ERRNO_Q922CFG_ADDLINK_LINKNO_INVALID;

returnulRet;

}

/*初始化Q922的I帧映射表的信息*/

ulSize=sizeof(INDEX_Q922IFRAME_MAPPING_STRU);

g_ppstQ922IFrameIndex[usLinkNo]=(INDEX_Q922IFRAME_MAPPING_STRU*)VOS_MemAlloc(VOS_PID_COMM,

DYNAMIC_DOPRA_MEM_PT,ulSize);

if(VOS_NULL_PTR==g_ppstQ922IFrameIndex[usLinkNo])

{

.....

ulRet=VOS_ERRNO_Q922CFG_INIT_ALLOC_IFRAMEMAP_FAILED;

returnulRet;

}

...

}

2)分析:

造成内存写越界,单板复位。

【纠正方法】

内存申请最大长度是DCOM_MAXSERVICEQ922LINK,最多访问到g_ppstQ922IFrameIndex[DCOM_MAXSERVICEQ922LINK-1],判断应改成if(usLinkNo>=DCOM_MAXSERVICEQ922LINK)

案例2.2

【问题描述】

版本倒换,主控板一起来就出现指令异常,单板复位

【问题分析】

1)错误代码:

CHARsLogInfo[1024];

UCHARszTmp[10];/*只分配了10个字节*/

char*pTemp=sLogInfo;

…….

while(*pTemp!

='-')

{

szTmp[i]=*pTemp;/*没有找到-,继续进行,导致堆栈被写坏*/

pTemp++;

i++;

}

szTmp[i]=0;

2)分析:

当数组下标i大于等于9时,不能再继续循环,否则越界访问。

【纠正方法】

增加判断:

i等于8时,跳出循环,对于while或者for循环里操作数组下标要做下标的保护,“小心驶得万年船”

案例2.3

【问题描述】

入参检测失败后不退出函数,仍继续执行后面逻辑处理,导致后面使用数组下标越界,在异常引用情况下导致死机。

【问题分析】

1)错误代码:

voidFARCheck_ImsDataTab_by_timer(CRims_data_tab_cr)

{

……

if((ims_data_tab_cr)>=MAX_IMS_DATA_CR)——A

{

CCB_stop_timer_by_ftr(ims_data_tab_cr,EN_CCB_FTR_ID_RF,EN_RF_CHECK_SINGLE_IMSDATA_TIMER);—>后面需要return,退出函数

}

if((MAX_SIPSL_CR==g_ims_data_table[ims_data_tab_cr].sip_cr)——B

&&(MAX_CCB(LOCAL_MODULE)==g_ims_data_table[ims_data_tab_cr].ccb_cr))

{

……

return;

}

……

}

2)分析:

当A处的ims_data_tab_cr入参检查失败后不退出而继续进行下面的逻辑处理,导致B处引用ims_data_tab_cr作为数组下标越界

【纠正方法】

在入参检测中失败应做退出函数处理,A处逻辑判断中增加return

案例2.4

【问题描述】

系统运行过程中突然复位。

【问题分析】

1)错误代码:

while(_isspace(*szString))

{

/*跳过所有空格字符*/

szString++;//szString为函数的输入参数

}

if('\0'==*szString)

{

returnFAILURE;

}

/*'='的左边变量赋值*/

szStr=VOS_Malloc(20);//申请内存大小为给20

if(NULL==szStr)

{

returnMACRO_MEM_SHORTAGE;

}

VOS_MemSet(szStr,'\0',20);

VOS_StrCpy(szStr,szString);

2)分析:

这种内存写越界问题的表面现象是不确定的。

该问题的原因就是没有检查szString字符串的长度,最后一代码中,字符串拷贝时发生写越界。

【纠正方法】

规避这种问题的办法是拷贝字符串是采用DOPRA平台提供的安全拷贝函数

CHAR*VOS_strncpy(CHAR*dst,constCHAR*src,ULONGn)。

 

案例2.5

【问题描述】

Sprintf使用不当导致内存访问越界

【问题分析】

1)错误代码:

charpszInfoBuf[250];

sprintf(pszInfoBuf,”***File:

%sLine:

%d****”,__FILE__,__LINE__);

2)分析:

“__FILE__”在预编译时,被编译时的目录名和源文件名代替,但目录和文件名的长度可变,很可能超出250个字节,导致内存越界

【纠正方法】

将sprintf替换成安全函数snprintf,指定缓冲区大小INFOBUF_SIZE,确保内存不会越界

snprintf(pszInfoBuf,INFOBUF_SIZE-1,”***File:

%sLine:

%d****”,__FILE__,__LINE__);

pszInfoBuf[INFOBUF_SIZE-1]=‘\0’;

【经验教训】

C语言提供的字符串库函数sprintf/vsprintf/strcpy/strcat/gets等非常危险,很容易导致内存越界,应该使用安全的字符串库函数snprintf/strncpy/strncat/fgets,指定操作的内存大小。

对C++语言,应该使用相应的类库如std:

:

string,std:

:

stringstream,boost:

:

lexical_cast操作字符串,而不要直接调用C语言的字符串函数。

案例2.6

【问题描述】

Strcpy使用不当导致内存访问越界。

【问题分析】

1)错误代码:

charpszInfoBuf[32];

strcpy(pszInfoBuf,pMsg);

2)分析:

定义的pszInfoBuf共32字节,pMsg是从网络上接收的数据包,可能超出32个字节,导致内存越界

【纠正方法】

将strcpy替换成安全函数strncpy,指定缓冲区大小INFOBUF_SIZE,确保内存不会越界

strncpy(pszInfoBuf,pMsg,INFOBUF_SIZE-1);

pszInfoBuf[INFOBUF_SIZE-1]=‘\0’;

案例2.7

【问题描述】

字符串拼接,忘记后面的\0.

【问题分析】

1)错误代码:

ulNewSize=VOS_strlen(“\r\n”)+VOS_strlen(pRevData)+VOS_strlen(pszVlanInfo)+VOS_strlen(pszQinQinfo);

pszDisInfo=VOS_Malloc(MID_BVLAN,ulNewSize);

......//拷贝一些内容给pszDisInfo

VOS_strcat(pszDisInfo,pszQinQinfo);//字符串连接

2)分析:

以ulNewSize为长度申请内存,但忘记字符串结尾必须有一个’\0’,调用strcat时拷贝了字符串本身和最后的’\0’,导致内存越界

【纠正方法】

计算ulNewSize时,增加1个字节,用于存放’\0’.

案例2.8

【问题描述】

数组下标越界。

【问题分析】

1)错误代码:

//pstPSCCfgInfo->strPara.ucNumOfCID超过了数组下标的最大值。

for(ulCount=0;ulCountstrPara.ucNumOfCID;ulCount++)

{

pPSCTable->strPara.stCidInfo[ulCount].bitCid=pstPSCCfgInfo->strPara.stCidInfo[ulCount].bitCid;

}

2)分析:

外部配入的pstPSCCfgInfo->strPara.ucNumOfCID值超过了定义的最大值SLP_MAX_PSC_CID_NUM。

由于代码未加保护,导致数组下标越界。

致BBI单板复位。

【纠正方法】

增加判断:

if(SLP_MAX_PSC_CID_NUMstrPara.ucNumOfCID)

{

pstPSCCfgInfo->strPara.ucNumOfCID=SLP_MAX_PSC_CID_NUM;

}

【经验教训】

对于外部输入的数组下标要作检查,避免内存越界

案例2.9

【问题描述】

整形转换成字符串时,没有注意到\0结尾。

【问题分析】

1)错误代码:

//使用itoa()将整型数转换为字符串时:

charszTempShold[10];

itoa(ulProcFrecy,szTempShold,10);

展开阅读全文
相关资源
猜你喜欢
相关搜索
资源标签

当前位置:首页 > 小学教育 > 语文

copyright@ 2008-2023 冰点文库 网站版权所有

经营许可证编号:鄂ICP备19020893号-2