1 现象:问题描述
产品A在测试中偶然发现XXX模块在处理性能告警上报时core,提供core文件和操作日志。产品A运行环境是solaris平台。
2 关键过程:根本原因分析
dbx 分析;core在如下函数红色语句处。
int CPADevMOItem::ParseAlarmCurExplain(char* ExprAlarmVal, const BackAlarmPara AlarmCurVal,
char* Expr, char* szValueDescSen, char* szAlarmUnit)
{
。。。
if(FLOAT_TYPE == AlarmCurVal.AlarmCurValList[nlength].Type)
{
bool bIfPosNumber = TRUE; //是否是正数
char szTmpVal[100] = {0};
char * pPos = NULL;
int nValTmp;
char szDecimal[5] = {0};
char szInteger[50] = {0};
char szResultVal[50] = {0};
if(AlarmCurVal.AlarmCurValList[nlength].Value.FloatVal() < 0)
{
bIfPosNumber = FALSE; //负数
}
ACE_OS::sprintf(szTmpVal,"%f",AlarmCurVal.AlarmCurValList[nlength].Value.FloatVal());
pPos = ACE_OS::strstr(szTmpVal,".");
//整数部分
ACE_OS::strncpy(szInteger, szTmpVal, (pPos - szTmpVal) < 50 ? (pPos - szTmpVal) : 50);
szInteger[49] = '\0';
//小数部分
ACE_OS::strncpy(szDecimal, ++pPos, 4);
szDecimal[3] = '\0';
int nDecimal = ACE_OS::atoi(szDecimal)
。。。
}
查看变量值:
。。。
pPos= OXO1
szTmpVal= Inf
。。。
core的原因已经找到:szTmpVal= "Inf", 没有包含小数点".",导致pPos = ACE_OS::strstr(szTmpVal,".")执行后,pPos=0;执行ACE_OS::strncpy(szDecimal, ++pPos, 4);pPos指向0x01(先进行++pPos运算),是一个非法地址,导致core。
但为什么szTmpVal的值为"Inf",异常纳闷,szTmpVal表示一个浮点数值的字符串啊?为什么浮点变成 "Inf" 呢?查询浮点数表示相关资料(参见后面备注),获知:如上"Inf"(Infinity)在浮点数表示中代表正无穷大(浮点数正溢出);
即传进函数的AlarmCurVal.AlarmCurValList[nlength].Value的值由于其他原因(如浮点数相乘等)已经是浮点数正溢出。用ACE_OS::sprintf(szTmpVal,"%f",AlarmCurVal.AlarmCurValList[nlength].Value.FloatVal()) 进行浮点数到字符串的转换,由于浮点数正溢出,所以转换后szTmpVal变为"Inf"。
3 结论:解决方案及效果
解决方案:
增加浮点数溢出保护处理逻辑。关键代码如下所示:
。。。
pPos = ACE_OS::strstr(szTmpVal,".");
if( NULL != pPos )
{
//整数部分
ACE_OS::strncpy(szInteger, szTmpVal, (pPos - szTmpVal) < 50 ? (pPos - szTmpVal) : 50);
szInteger[49] = '\0';
//小数部分
ACE_OS::strncpy(szDecimal, ++pPos, 4);
szDecimal[3] = '\0';
int nDecimal = ACE_OS::atoi(szDecimal);
}
else
{
ACE_OS::strcpy(szResultVal,(const char*)"INF");
szResultVal[99] = '\0';
}
。。。
效果:
按照上面方案修改后,core问题没有重现。问题得到解决。
阅读(384) | 评论(0) | 转发(0) |