1. 数组下标访问越界
2. 使用野指针(指针未初始化就直接使用、delele完后继续使用、NEW申请不作NULL判断/托管后自己又手动DELETE)
3. 字符串结尾标志’\0’
4. 变量没有初始化
5. 变量名、枚举名、常量名字面意思、注释含义与使用时相反
6. 所有的可能抛异常的地方都要有try catch
7. 没有处理返回值
8. 函数局部变量或参数过大,堆栈溢出
9. 数据类型不一致,变量或参数赋值出错
10. 分支流程未释放动态申请的内存
代码案例:
1. 数组下标访问越界
Typedef TOCTET TEncodedSmsContent[MaxEncodedSmsContentLength + 1];//200
TEncodedSmsContent featureStr;
#define MAX_MSG_LEN 255 //采用统一的扩展长度
char sMsgContent[MAX_MSG_LEN + 1];
memcpy(m_ismgAuthPriceReq.featureStr, pMessage->deliverReq->msgBody.getMsgContent(),
pMessage->deliverReq->msgBody.getMsgLen());
2. 使用野指针
(1)使用未分配空间的指针、new操作不做null判断、delete后继续使用
CMessage* pMsg;
pMsg->decode(code);//未分配空间
-------------------------
CMessage* pMsg;
NEW(pMsg, CVACUserOrderServiceReq);
TCode code
pMsg->decode(code)
DELETE(pSession);
If(pSession-> isSessionOver())//未作null判断
{
m_pSessionControl->removesession(pSession);
}
(2)指针托管后被误delete
NEW(pSession, CSubscribeSessionInfo);
CSessionProcessMgr::instance()->event(pSession->getSessionType(), pSession, code);
m_pSessionControl->addSession(pSession)
//上面event处理完了有可能会话已结束
if (pSession->isSessionOver())
{
DELETE(pSession);//此时delete,那么托管的指针指向内存就被误释放了
return;
}
3. 字符串结尾标志’\0’
typedef TOCTET RecordSequenceID[MaxVacSequenceIDLength];
RecordSequenceID VacSequenceID
sprintf(VacSequenceID, MaxVacSequenceIDLength, "%04d%02d%02d%02d%02d%02d%04d",
(1900 + ts->tm_year),
(1 + ts->tm_mon),
ts->tm_mday,
ts->tm_hour,
ts->tm_min,
ts->tm_sec,
curSquenceId);
//缺少\0,后面在使用VacSequenceID就会出现内存越界访问
字符串结束符相关有许多安全函数可供调用:snprintf,strncpy,strncat,safecopy等等,不允许使用非安全函数
4. 变量没有初始化
class CMsgConvert_SMAPLike : public CMsgConvert
{
public:
CMsgConvert_SMAPLike(){}
virtual ~CMsgConvert_SMAPLike(){}
protected:
RecordNo m_recordNo;//变量没有初始化(所有变量都必须初始化)
};
5. 变量名、枚举名、常量名字面意思、注释含义与使用时相反
CVACSubScirbeReq中字段:
CMsgFieldInt m_isNeedNotifySP; //CRM侧订购的是否需要通知SP
该字段本意是个枚举值(ENUM),取值有2个:
enum isNotifySP
{
Notify_SP_NO = 1, //不通知
Notify_SP_YES = 2 //通知SP
};
//下面的逻辑是需要通知sp才处理的,枚举含义和实际意义完全颠倒
if (From_CRM == pSessionInfo->m_reqInfo.m_CRMOrderFlag.asInt()
&& Notify_SP_NO == pSessionInfo->m_reqInfo.m_isNeedNotifySP.asInt())
6. 所有的可能抛异常的地方都要有try catch
const char *sql = "select msisdn, serviceid, spid, billmonth, amount, account, rewardAmount, rewardAccount,realaccount from historyrecord where msisdn = :v1 and serviceid = :v2 and spid = :v3";
TINT nCommandIndex = m_pDbAgent->excute(sql, msisdn, pa, paCount);
if (nCommandIndex == Failed)
{
return SearchResult_DBError;
}
CRecordSet rs;
rs.setSACommand(&CDBAgent::getInstance()->s_commandSet[nCommandIndex]);
//完全没有try和catch保护,一旦数据库出错就是一个core
7. 没有处理返回值
char* genMsgBuf(int iBufSize)
{
char* pBuff = NULL;
NEW_S(pBuff, char, iBufSize);
return genMsgBuf;
}
//诸如此类内部动态分配内存并返回的函数,外部调用时一定要对返回值进行处理,否则就会出现内存泄露,一般来说哪里申请哪里释放,尽量避免内部申请外部释放的情况
8. 函数局部变量或参数过大,堆栈溢出
CCMMainCtrl_Impl cmMainctrl;//栈溢出
TVersionInfo versionInfo( "HUAWEI MDSP R005C09L10303", "HUAWEI MDSP R005C09L10303 inner");
cmMainctrl.setVersionInfo();
//CCMMainCtrl_Impl继承了会话管理类,会话类中会话数组初始化为100万,这个对象太大了,导致启动时就直接栈溢出了
9. 数据类型不一致,变量或参数赋值出错
ULONG useqId = authRsp.msgBody.nSequenceID;
snprintf(tmpSeqId, MaxTableNameLen, "%s%d", pszIp, seqId);
pSession = dynamic_cast<TCManagerSession*>(TMainCtrl::instance()->getSession(tmpSeqId));
if (NULL == pSession)
{
RUNLOG(TLogLevel_Debug, TLogID_PrintInfo, "pSession is NULL!");
}
//由于ULONG->int,数值越界,导致tmpSeqId有负值,进而getsession失败,一段时间内导致会话堆积,内存暴增
10. 分支流程未释放动态申请的内存
CMessage* pMsg;
NEW(pMsg, CVACUserOrderServiceReq);
TCode code
pMsg->decode(code)
if (False == sendToAplauncher(code))
{
RUNLOG(TLogLevel_Error, TLogID_SocketSendFail,
"Failed to send message to aplauncher.errno is %d", errno);
return False;//此处没有释放pMSG,导致内存泄漏
}
DELETE(pMsg);
return True;