1 现象:问题描述
在S产品一期开发U模块时,利用几个WORD类型的index分流向U模块的几个消息处理线程发送消息,在发送消息时使用commonfiles中的INFOX_InterlockedIncrement函数加锁并使index自增(具体向几个线程分流发送消息的方法与本案例没有关系,就不再描述了,另外INFOX_InterlockedIncrement函数对传入的参数有++功能)。
但是,奇怪的是似乎系统并没有完全理解我们的意图,在每次对index进行加锁并使其++时总有意象不到的事情发生,要么是index并没有被修改,要么是被修改为一个莫名其妙的值。
2 关键过程:根本原因分析
首先了解到这种奇怪的现象时第一步就想到是内存访问越界,于是从数据类型、内存中长度、邻近数据成员等几个方面看代码,然后使用DBX单步跟踪调试,是用display命令将index之后的一个数据成员也显示出来。在单步执行到INFOX_InterlockedIncrement((LPLONG)&m_wIndex);
时发现Index没有被修改,反而Index之后的变量被修改,然后仔细看了一下代码发现Index为WORD类型,而INFOX_InterlockedIncrement的参数为(long *)。
再看看下面这份代码:
#include "iostream.h"
class CTest
{
public:
short int m_nTest1;
short int m_nTest2;
CTest()
{
m_nTest1 = 0;
m_nTest2 = 0;
};
void func(long *nValue)
{
*nValue = 0xffffffff;
};
void print()
{
cout<<"m_nTest1 = "< };
};
void main()
{
CTest cTest1;
cTest1.func((long *)&(cTest1.m_nTest1));
cTest1.print();
}
在cTest1.func函数执行时,奇怪的事情发生了,m_nTest1、m_nTest2均被修改了。由于func函数的入口参数是long型指针,而传入的参数*m_nTest1是一个short int类型的指针,被强制转换为long型指针后,导致越界访问,m_nTest2同时也被修改。
3 结论:解决方案及效果
像这种因为数据类型转换导致的地址越界是很隐蔽的,但是所有的地址越界都有一个共性,就是访问到了其它数据。危险点的就core了,而有些是修改了其它数据。在定位这些问题是需要细心,仔细观察每一个值得怀疑的地方。问题定位以后,解决方法非常简单,把Index的类型由WORD改成DWORD就可以了。
4 经验总结:预防措施和规范建议
在定位问题时,细心是很关键的(有上面的分析,就不再罗嗦了),在我们使用一个新的或者不太熟悉的函数、对象时,一定要仔细深入的了解函数、对象的使用说明,否则类似上面分析的问题可能还有隐藏很多,这种问题比较隐蔽,如果是在某个异常分支,可能很多年也不走到一次,但走到一次我们程序就乱了套了,定位的难度可想而知。另外对工具的使用也是很重要的,如果对DBX不熟,不知道display这个命令同样很难定位出这个问题。
5 备注
6 考核点
传入函数的参数类型要与函数原型一致。
7 试题
CMapStringToPtr SmcList;
short sIndex = 1;
short sTemp = 0;
char szSmcAddr[] = "8613800688500";
SmcList.SetAt(szSmcAddr, (void*&)sIndex);
DWORD dwIndex = 0;
SmcList.Lookup(szSmcAddr, (void*&)dwIndex);
以上SetAt和Lookup分别是map表的插入和查找函数。CMapStringToPtr::SetAt函数原型为void SetAt(LPCTSTR key, void* value),LookUp函数原型为BOOL Lookup(LPCTSTR key, void*& rValue),那么在AIX平台执行上述代码后,dwIndex的值是:
A. 0x00000000 B. 0x00000001
C. 0x00010000 D. 0xFFFFFFFF
阅读(478) | 评论(0) | 转发(0) |