您好,欢迎来到汇智旅游网。
搜索
您的当前位置:首页Win32 C++ 服务器的堆内存被破坏的一次调试经历

Win32 C++ 服务器的堆内存被破坏的一次调试经历

来源:汇智旅游网

昨天公司项目做小规模的测试,测试功能以及真实环境中的服务器稳定性,开服半小时后,战场服务器崩溃。崩溃的时候没有任何日志留下,按正常情况,我们服务器的每一个线程都有异常捕获机制,并能将现场dump出来,保存为dmp文件,并将调用堆栈打印出来,保存为log文件。但任何日志都没有被留下。

碰到这个情况让我非常的头疼,因为毫无疑问,导致这种问题的原因肯定是和堆被破坏有关,堆被破坏后,任何有内存分配的行为都将失败。

我不得不在服务器上装好vs的社区版,只安装调试工具,大概1.9个g的空间需求对服务器60g的硬盘也是不小的压力。

我再次启动战场服务器,然后用vs attach到进程,等待下一次崩溃,看能不能抓到现场。不出所料,大约20分钟之后,服务器又崩溃了,这次没有任何异常被捕获到,只是在vs的输出最下方输出了一个错误 0xC0000374。

查了一下这个错误代码的含义,果然不出我所料,就是堆内存被破坏导致,这种情况一般是越界写内存导致的。这种bug无疑是最难调试的几种bug之一。

想了一下,还是决定把服务器的page heap选项打开,虽然会消耗更多内存,但可以在服务器写越界的时候直接抛异常。这样就可以准确的定位故障点。

把 Enable page heap, Enable heap tail checking, Enable heap free checking, Enable heap paramater checking, Enable heap validation on call 这几个全部勾选上。

然后关闭gflags,把战场服务器重新启动,如果设置成功了,最明显的标志就是内存消耗,战场服务器之前的提交大小是400多mb,现在的内存提交大小是2.9G。明显增加了几倍。这是为了调试堆的额外开销。

然后再用vs attach到服务器,静待出错的异常。

大约半小时后,战场服务器抛出了异常,被vs捕获到了,vs提示我将代码定位好,定位好代码之后,发现了出现这次bug的地方。

这一段代码看的我哭笑不得,这种应该属于灯下黑吧,反复检查了几次的代码都看不到问题所在。

                CMemory data;
                U32 length = message -> ReadU32();

                if( length ) {
                    data.Alloc( data );  // 出错的地方。
                }

                if( data )
                {
                    if( length == 
                        message -> ReadBytes(data, length) )
                    {
                        data.SetLength( length );
                    }
                }

data可以被造型为指针,空的data返回的是NULL,被理解为0,如果输入0,则data会缺省的分配4096字节,大部分情况下,这个部分的代码不会出问题,如果超过4096字节,就会导致越界,从而导致堆内存被破坏。于是用Alloc做关键字查询了整个项目,又发现了几处这种写法。显然是复制粘贴导致的结果。

把这些地方全部修正之后,再将服务器启动,运行了一下午,服务器稳定了,没再崩溃了。看来可以享受一个安静的周末了。:)

因篇幅问题不能全部显示,请点此查看更多更全内容

Copyright © 2019- hzar.cn 版权所有 赣ICP备2024042791号-5

违法及侵权请联系:TEL:199 1889 7713 E-MAIL:2724546146@qq.com

本站由北京市万商天勤律师事务所王兴未律师提供法律服务