Smile_Tiger 2014年12月21日
关于一个默认拷贝函数、互斥引发的堆错误的bug(散分贴)
前不久某个项目经常出问题,错误的地方总是出现在互斥的那个地方,而且提示有堆错误。分析了好几天都没解决,只好到客户现场来解决问题。

1. 首先我实现了一个很简单的互斥类


#pragma once

#include "windows.h"

class csClass
{
public:
csClass() : m_bEnable(true)
{
::InitializeCriticalSection(&m_cs);
}
~csClass()
{
::DeleteCriticalSection(&m_cs);
}

void Enable(bool b)
{
m_bEnable = b;
}

void Lock()
{
if(m_bEnable)
::EnterCriticalSection(&m_cs);
}

void Unlock()
{
if(m_bEnable)
::LeaveCriticalSection(&m_cs);
}

public:
CRITICAL_SECTION m_cs;
bool m_bEnable;
};

class csScope
{
public:
csScope(csClass* cs):m_cs(cs)
{
if(m_cs)
m_cs->Lock();
}

~csScope()
{
if(m_cs)
m_cs->Unlock();
}
protected:
csClass* m_cs;
};


具体的用法大家应该知道,定义一个互斥变量 csClass mycs; 然后在需要互斥的地方写 csScope Scope(&mycs);

2. 可是我有个地方写错了,写成了 csClass Scope(mycs);
csClass有个默认的构造拷贝函数 csClass(const csClass& obj); 它将mycs对象复制给了Scope

3. 我又专门写了一个测试小例子:


// testaaa.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include "csDef.h"

int _tmain(int argc, _TCHAR* argv[])
{
csClass g_cs;

for(int i=0;i<100;i++)
{
csClass Scope(g_cs);
}

int debug = 1;

return 0;
}



4. 经过运行测试,程序会在循环到i=11的时候,在csClass的析构函数中的::DeleteCriticalSection()那里出错(这也是这个bug很难用某种重复操作的手段来再现错误,你操作的次数少于11就不会出错)
5.经过分析,循环体中的 csClass Scope(g_cs); 这句话,不会进入构造函数中(因为进入的是构造拷贝函数),也就是说不会调用::InitializeCriticalSection(),却调用了10次::DeleteCriticalSection()而没有出错,调用第11次出错了。这个11应该和CRITICAL_SECTION的系统设计有关系.

6.把循环次数改为10,那么程序运行到退出main()函数时,g_cs将要析构,此时引发了g_cs的堆错误


--------------------------
对此问题的初步分析已经完毕,更深层次的研究我没有进行,期待大神来说一说

有一个经验上的问题困扰我:如何迅速地发现这类堆错误的bug在哪儿?这次的bug算我运气好,发现那里些错误,如果我没发现那里写错,该怎么发现错误的地方呢?
...全文
65 点赞 收藏 3
写回复
3 条回复

还没有回复,快来抢沙发~

发动态
发帖子
C++ 语言
创建于2007-09-28

3.1w+

社区成员

24.8w+

社区内容

C++ 语言相关问题讨论,技术干货分享
社区公告
暂无公告