2

我在这里、MSDN 以及通过谷歌通过其他一些论坛进行了一些搜索,试图找到任何类型的解决方案,但到目前为止我被卡住了。

我一直在寻找一个星期,试图追踪我的 C++ 程序中的访问冲突错误。我不能在这里发布代码,因为它受到一些 IP 限制,但基本上,它是一个循环,大约每 100 毫秒运行一次,从 TCP 连接读取字节并将它们放在 std::queue 的后面。

在我注意到一个特定的字节序列通过后,我从队列中删除 x 个字节并将它们作为内部协议中定义的消息处理。

发生的事情是,在我的应用程序内部的某个地方,队列正在损坏并使应用程序崩溃。因此,将它与它是访问冲突的事实结合起来,它一定是某个地方的一个狡猾的指针。

我曾尝试使用 VS2005 调试器和 Windbg 来找到它,我有调用堆栈要查看,但它没有多大帮助。我可以从中得出的结论是,原因是我的内部队列损坏了。它崩溃的原因是因为消息的标头被发送以进行解析,但是因为它已损坏,所以一切都失败了。

然后我尝试了 Intel Thread Checker,但在这个应用程序中使用太慢了,因为我的程序是同步多线程系统的一部分。

有时它会运行 300 次读取……有时它可以读取 5000 次……有时它可以在崩溃之前读取 10000 次。

我可以尝试哪些其他诊断途径?我是否在这里遗漏了一些我应该已经检查过的简单内容?据我所知,任何新的东西都有一个匹配的删除,我正在使用 Boost Librarys for Shared Pointers 和长寿命对象上的自动指针。

4

2 回答 2

3

使用 SEH(结构化异常处理)找出哪个部分引发了 AV。

来自 MSDN 的 C++ 示例代码中的 SEH。

#include <stdio.h>
#include <windows.h>
#include <eh.h>
void SEFunc();
void trans_func( unsigned int, EXCEPTION_POINTERS* );
class SE_Exception
{
private:
    unsigned int nSE;
public:
    SE_Exception() {}
    SE_Exception( unsigned int n ) : nSE( n ) {}
    ~SE_Exception() {}
    unsigned int getSeNumber() { return nSE; }
};
int main( void )
{
    try
    {
        _set_se_translator( trans_func );
        SEFunc();
    }
    catch( SE_Exception e )
    {
        printf( "Caught a __try exception with SE_Exception.\n" );
    }
}
void SEFunc()
{
    __try
    {
        int x, y=0;
        x = 5 / y;
    }
    __finally
    {
        printf( "In finally\n" );
    }
}
void trans_func( unsigned int u, EXCEPTION_POINTERS* pExp )
{
    printf( "In trans_func.\n" );
    throw SE_Exception();
}
于 2012-11-19T03:34:14.430 回答
1

随机崩溃通常是由堆损坏引起的,很难找到。过去几年我处理过几个堆损坏问题,我记得,其中一个问题花了我整个周末的时间才找到。这里有一些建议:

  1. 首先尝试应用验证程序。详细信息在:http: //msdn.microsoft.com/en-us/library/windows/desktop/dd371695 (v=vs.85).aspx 。
  2. Gflags: http: //msdn.microsoft.com/en-us/library/windows/hardware/ff549557 (v=vs.85).aspx 。使用它来启用页面堆验证。
  3. 解决方案 1 和 2 都对您的整个程序使用堆验证,因此您可能会遇到很多异常并减慢您的程序,但其中一些与您的问题无关。如果您知道代码的哪一部分有错误,您可以使用窗口 API _CrtSetDbgFlag 来启用堆验证,如下所示:

    `int tmpFlag = _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG);

    tmpFlag |= _CRTDBG_CHECK_ALWAYS_DF;

    _CrtSetDbgFlag(tmpFlag); // 在 alloc 和 dealloc 时验证堆

    //你在这里编码,如果堆损坏,下次分配时会抛出异常。

    tmpFlag |= ~_CRTDBG_CHECK_ALWAYS_DF;

    _CrtSetDbgFlag(tmpFlag)// 不验证堆`

于 2012-11-19T04:08:31.183 回答