程序调试有感

程序调试有感

Risun

2004-7-31

 

最近赶上回家和软件发布的冲突之中,最要命的是程序运行的过程中出现bug,最致命的内存访问异常错误,一旦出现立即中止,这,对于一个需要7*24运行的服务器来说是不可忍受的。

于是乎,和时间赛跑和冗长的代码比耐心,开始了痛苦而兴奋的程序调试历程……

 

由于是内存错误,开始时总是会随机的出现在一些地方,好像没有什么固定地点,但出的次数多了,终于发现了一个最多出现的部分,于是手工察看此部分代码,怀疑copy constructor有问题,单步跟踪后,竟然发现,一直以为很有用的copy constructor竟然根本从来就没有调用到。晕,真是奇怪前一个版本为什么在实际项目中用了这么久!

测试copy constructor的用法,(参见<关于copy constructor>一文)修改了整个类体系的copy constructor。意料之中的,引入了或者说暴露了一大堆新的bug。由于以前很多代码根本就没有执行到。再修改,测试,这部分的问题似乎得到解决。

 

怀着激动兴奋得心情再次运行修改后的服务器和测试程序,呵呵呵,没错了,要是不出错多好,可以回家了~~

卡擦~~,一个悬着的心终于掉到石头上,摔得粉碎,还是有内存访问异常。

 

Release下的调试堆栈看的人一头雾水,debug时它偏偏不出错,只好一次次的让他重复出现“随机的错误”。终于又抓住一个把柄,线程的问题,主线程创建了子线程,子线程delete之后,主线程还在访问字线程中的变量(出错代码见附录),修改之,运行之。

 

根据前面的出错记录,感觉还有错误,明显不是由刚刚修改的错误导致。

 

果然,程序还是出现错误了。

 

这时差不多整个服务器的代码都重看了一遍,在这种头晕脑胀两眼发花的状态下,能看出代码的错误?

 

再让程序重复出错,终于发现似乎有一套代码是祸源,就要抓住你,我看,我查,实在看不出问题,但有一种预感这里有问题,让别人帮我看,还是没有结果,心中凄凄然,吃饭没有精神,骑车无精打采,突然间似乎想起什么?对,呵呵,太兴奋了。

立马赶到公司,修改了此处的代码,ok

有一种感觉,终于解脱了。

 

再测试,再也没有出现问题,不能肯定没有了错误,只是心中有了一种踏实的感觉。

 

没有经历过程序调试,无法体会其中的失望、茫然、烦躁、希望、激动和兴奋。经过这段程序调试的历程,审视了以前的代码,前所未有的感受到很多以前写代码时未曾注意的地方。

无论写一个函数一个类或者一个库,一定要自我认为她是完美的,不会对外界造成破坏也不会被外界破坏。写完代码自己就要检查一遍,至少要自己放心,千万不可有侥幸心理,那必将埋下一个让你付出惨重代价的地雷。

 

在写程序时特别要注意 指针、copy constructor、多线程访问的部分

 

刚刚给老板打了一个电话,他听了也很开心,因而允许了我的放假半个月的请求,回家了,88

 

附录:出错代码(删节)

1 线程相关

void Thread::start()

{

   DWORD wt_id;

   thdl = ::CreateThread(NULL, 0, ThreadEntrance, this,0,(LPDWORD)&m_id);

   if(!thdl)

   {

      assert(0);

      return;

   }

   // to wait for the child thread to run

   start_lock.wait();

}

被主线程调用创建新的线程

int Thread::_run()

{

   int ret;

   start_lock.signal();

 

   ret = run();

  

delete this;

 

   return ret;

}

子线程的执行体,主线程创建子线程后等待字线程运行起来,但有时主线程还没有到start_lock.wait();子线程已经执行完,并且delete this

 

2 指针、 copy constructor相关

class ATB_FieldItem

{

public:

   virtual ~ATB_FieldItem() {}

};

 

class FieldItemImpl : public ATB_FieldItem

{

public:

   FieldItemImpl();

   virtual ~FieldItemImpl();

  

   FieldItemImpl( const ATB_FieldItem & item );

 

private:

   union {

      long vl;

      double vd;

      wchar_t * vs;

      int_64 vi64;

      byte_8 * vb;

   } m_val;

};

 

FieldItemImpl为模版构造FieldItemImpl对象时根本不会调用类中定义的copy constructor而是使用默认的copy constructor,会导致什么?m_val.vs不能被正确设定

修改:copy constructor 该为:

FieldItemImpl( const FieldItemImpl & item );

 

 

LockTarget::LockTarget(const LockTarget &model)

{

   //init();

   *this = model;

}

这里有错误吗?有!一般的在 A = BA是一个已经初始化好的对象,因此在

LockTarget & LockTarget::operator = (const LockTarget &right)

{

   if ( this == &right )

      return *this;

   clear();

//… set data

   return *this;

}

中首先清理A,如果在copy constructor直接调用*this = model;这时this还没有被初始化,有些成员变量可能是无效或者可能引起后面的clear()的错误,因此如果在copy constructor中用 = 来实现,则首先应该初始化对象, 如代码中的init();

posted on 2004-07-31 20:39  哲学 艺术 程序 人生  阅读(483)  评论(0)    收藏  举报

导航