1 现象:问题描述
进行某版本的AIX移植工作。在功能测试时,使用的是server的DEBUG版本,即在编译时使用了-g选项,目的是在出现问题时方便调试。进入性能测试后,为了提高系统的性能,编译了release版本,去掉了-g选项,添加了-O选项。可是,当代码运行起来以后,却发现server模块经常发生core。
2 关键过程:根本原因分析
从栈顶可以看出,代码在执行strlen时发生了错误,应该是传给strlen的参数有问题。由于是release版本,无法看出参数的值,因此,只好继续向下观察堆栈。通过红色部分可以看出,是日志打印的代码调用了strlen,而该日志打印发生在EnableFRSession函数中。
观察EnableFRSession函数,找到所有的日志打印代码。好在不是很多,总共只有10处,可以挨个的进行检查。在检查中,发现了下面的可疑代码:
SENDLOG_NEW((LVL_FINER, LOG_TYPE_SYSTEM, LOG_ACTION_VOID, FL,
DEF_SRV_MODULE_MANAGER, "One session is recoved!",
"SessionType [%d],SessionID[%s],MessageID[%s],MainState[%s],SubState[%s].",
rSrvSessWrapper->GetSessionType(),
rSrvSessWrapper->GetSessionID(),
rSrvSessWrapper->GetXMmsMessageID(),
g_pstrStateText[sessionMainState],
g_pstrSubstateText[sessionSubState]));
红色部分的代码将两个函数的返回值当作了参数,可是这两个函数的返回值都是string类型,而不是char *或者const char *。系统将临时的string对象当成了字符指针来处理,很可能会越界发生core。
3 结论:解决方案及效果
修改红色部分的代码,将string类型的指针传给SENDLOG:
SENDLOG_NEW((LVL_FINER, LOG_TYPE_SYSTEM, LOG_ACTION_VOID, FL,
DEF_SRV_MODULE_MANAGER, "One session is recoved!",
"SessionType [%d],SessionID[%s],MessageID[%s],MainState[%s],SubState[%s].",
rSrvSessWrapper->GetSessionType(),
rSrvSessWrapper->GetSessionID().c_str(),
rSrvSessWrapper->GetXMmsMessageID().c_str(),
g_pstrStateText[sessionMainState],
g_pstrSubstateText[sessionSubState]));
经过测试,故障消失。
4 经验总结:预防措施和规范建议
1. 调用使用了可变参数的函数,一定要仔细检查传入的实参类型是否正确。
2. 注意string类型和char *的区别。
5 备注
这个问题很简单,解决起来也不费什么事。但还是有一点疑问:为什么编译器没有能够察觉上述的类型不匹配呢?C++可是一个强类型语言啊。
仔细观察sendlog的定义:
阅读(373) | 评论(0) | 转发(0) |