1 现象:问题描述
××后台程序修改配置后,程序启动就会core,但重新安装后直接配置就没有问题。
2 关键过程:根本原因分析
根据core文件分析,定位到引起core的代码部分为访问vector数组越界。由于程序启动后,为了处理上次的执行遗留的任务,在文件中记录了上次处理的任务:
bool CCollectEntity::DeleteDuplicate(std::string & strFileName)
{
…
std::string strNewName;
//定义配置组ID
int nConfigID = 0,nTypeID = 0;
//取得原文件名和配置组ID
if (!SplitFileName(strOldFileName,
FLAG_UNDELDUP,
strName,
strNewName,
nConfigID,
nTypeID))
{
//根据上次运行的任务记录文件反算出对应的配置项ID。
…
}
std::string sFileName = DownInfo.szFileName;
//获取序号起始位置
int nIdxSerial = m_pEntityInfo->CollectDirInfo[nConfigID]->CollectFileType[nTypeID].nFileSerialPos;
//获取序号长度
int nSerialLen = m_pEntityInfo->CollectDirInfo[nConfigID]->CollectFileType[nTypeID].nFileSerialLen;
//获取序号字符串
…
}
其中CollectDirInfo 定义为 std::vector CollectDirInfo。由于程序中下标nConfigID为修改配置前任务对应的配置项下标,而m_pEntityInfo->CollectDirInfo vector数组记录的却是修改后的配置,如果修改后的配置项少于修改前则会出现vector下标越界。vector 越界导致不可预知的结果。
3 结论:解决方案及效果
该函数功能为通过历史记录信息,判断当前配置采集文件的正确性,如果历史信息对应的配置已经不存在,也就没有必要处理。
增加对下标合法性的判断,对于越界的遗留任务文件不处理。
//如果文件中的配置项id和typeid大于当前配置,将越界 V6.0D40 XXX add below
if ( (nConfigID < 0) || (nConfigID >= m_pEntityInfo->CollectDirInfo.size()))
{
// 配置项id不合法,那么不添加到列表中,不进行下一步处理
continue;
}
else
{
int iTotalTypes = m_pEntityInfo->CollectDirInfo[nConfigID]->CollectFileType.size();
// 如果类型id非法
if ( (nTypeID < 0) || nTypeID >= iTotalTypes) )
{
continue;
}
}
// 解决缺陷 V6.0D40 XXXX add above
4 经验总结:预防措施和规范建议
使用数组时我们总会关注下标越界的问题,但使用标准库的类似vector的函数时,我们总是会认为标准库已经为我们封装得很完善了,从而淡化数组越界的关注。在使用标准库时,一定要熟悉使用规则、异常处理等。
5 备注
6 考核点
vector的使用。
7 试题
1、 对标准库vector数组变量进行[] 操作时,如果下标超过了vector范围,那么 :A
A) []操作不进行越界检查导致访问非法内存,从而导致不可预知的结果。
B) []操作进行越界检查,如果越界将会自动扩大数组空间,不会越界。
C) []操作越界时,将会抛出访问越界异常。
D) 以上都不正确
阅读(904) | 评论(0) | 转发(0) |