VC++ 在调试器中运行时出现 6.0 访问冲突

发布于 2024-07-10 15:56:36 字数 2999 浏览 7 评论 0原文

我正在尝试为已有 4 年历史的 VC++ 6.0 程序添加增强功能。 调试版本从命令行运行,但不在调试器中运行:它会因 printf() 内部的访问冲突而崩溃。 如果我跳过 printf,那么它会在 malloc() 中崩溃(从 fopen() 内部调用),并且我无法跳过它。

这意味着我无法在调试器中运行,并且必须依赖旧的 printf 语句来查看发生了什么。 这显然让事情变得更加困难。

知道为什么 printf() 和 malloc() 在 VC++ 调试器下运行时会失败吗? 我不擅长这种低级的东西!

这是访问冲突后的调用堆栈:

_heap_alloc_dbg(unsigned int 24, int 2, const char * 0x0046b3d8 `string', int 225) line 394 + 8 bytes
_nh_malloc_dbg(unsigned int 24, int 0, int 2, const char * 0x0046b3d8 `string', int 225) line 242 + 21 bytes
_malloc_dbg(unsigned int 24, int 2, const char * 0x0046b3d8 `string', int 225) line 163 + 27 bytes
_lock(int 2) line 225 + 19 bytes
_getstream() line 55 + 7 bytes
_fsopen(const char * 0x00468000 `string', const char * 0x00466280 `string', int 64) line 61 + 5 bytes
fopen(const char * 0x00468000 `string', const char * 0x00466280 `string') line 104 + 15 bytes
open_new_log(const char * 0x00468000 `string') line 66 + 14 bytes
log_open(const char * 0x00468000 `string', int 0) line 106 + 9 bytes
Xlog_open(const char * 0x00468000 `string', int 0) line 51 + 13 bytes
service_start(unsigned long 1, char * * 0x009a0e50) line 3152 + 12 bytes
service_init2(char * 0x00471fcc char * NTPROGRAM, char * 0x004723c4 char * NTSERVICE, char * 0x00466540 `string', unsigned long 1, char * * 0x009a0e50) line 508 + 13 bytes
service_init(char * 0x00471fcc char * NTPROGRAM, char * 0x004723c4 char * NTSERVICE, unsigned long 2, char * * 0x009a0e50) line 548
main(unsigned long 2, char * * 0x009a0e50) line 3131
mainCRTStartup() line 206 + 25 bytes
KERNEL32! 7c817067()

这是直到失败的操作为止的调试反汇编:

0041EA7E   jmp         _heap_alloc_dbg+2B3h (0041eb23)
0041EA83   mov         edx,dword ptr [_lTotalAlloc (004b4294)]
0041EA89   add         edx,dword ptr [nSize]
0041EA8C   mov         dword ptr [_lTotalAlloc (004b4294)],edx
0041EA92   mov         eax,[_lCurAlloc (004b429c)]
0041EA97   add         eax,dword ptr [nSize]
0041EA9A   mov         [_lCurAlloc (004b429c)],eax
0041EA9F   mov         ecx,dword ptr [_lCurAlloc (004b429c)]
0041EAA5   cmp         ecx,dword ptr [_lMaxAlloc (004b42a0)]
0041EAAB   jbe         _heap_alloc_dbg+249h (0041eab9)
0041EAAD   mov         edx,dword ptr [_lCurAlloc (004b429c)]
0041EAB3   mov         dword ptr [_lMaxAlloc (004b42a0)],edx
0041EAB9   cmp         dword ptr [_pFirstBlock (004b4298)],0
0041EAC0   je          _heap_alloc_dbg+25Fh (0041eacf)
0041EAC2   mov         eax,[_pFirstBlock (004b4298)]
0041EAC7   mov         ecx,dword ptr [pHead]
0041EACA   mov         dword ptr [eax+4],ecx

这是我们调用 fopen() 并在 malloc() 中失败的源代码

FILE *open_new_log( const char *logfile )
{
    FILE *fp;
    int retry = 0;

    while( ( fp = fopen( logfile, "w" ) ) == NULL && ++retry < 300 )
        Sleep( 1000 );

    return( fp );
}

我得到的错误是

Unhandled exception inPISCOOP.exe: 0xC00000005: Access Violation

问候,

--- Alistair。

I am trying to add enhancements to a 4 year old VC++ 6.0 program. The debug build runs from the command line but not in the debugger: it crashes with an access violation inside printf(). If I skip the printf, then it crashes in malloc() (called from within fopen()) and I can't skip over that.

This means I cannot run in the debugger and have to rely on the old printf statements to see what's going on. This obviously makes it a lot harder.

Any idea why printf() and malloc() would fail when running under the VC++ debugger? I am no good at this low level stuff!

Here is the call stack after the access violation:

_heap_alloc_dbg(unsigned int 24, int 2, const char * 0x0046b3d8 `string', int 225) line 394 + 8 bytes
_nh_malloc_dbg(unsigned int 24, int 0, int 2, const char * 0x0046b3d8 `string', int 225) line 242 + 21 bytes
_malloc_dbg(unsigned int 24, int 2, const char * 0x0046b3d8 `string', int 225) line 163 + 27 bytes
_lock(int 2) line 225 + 19 bytes
_getstream() line 55 + 7 bytes
_fsopen(const char * 0x00468000 `string', const char * 0x00466280 `string', int 64) line 61 + 5 bytes
fopen(const char * 0x00468000 `string', const char * 0x00466280 `string') line 104 + 15 bytes
open_new_log(const char * 0x00468000 `string') line 66 + 14 bytes
log_open(const char * 0x00468000 `string', int 0) line 106 + 9 bytes
Xlog_open(const char * 0x00468000 `string', int 0) line 51 + 13 bytes
service_start(unsigned long 1, char * * 0x009a0e50) line 3152 + 12 bytes
service_init2(char * 0x00471fcc char * NTPROGRAM, char * 0x004723c4 char * NTSERVICE, char * 0x00466540 `string', unsigned long 1, char * * 0x009a0e50) line 508 + 13 bytes
service_init(char * 0x00471fcc char * NTPROGRAM, char * 0x004723c4 char * NTSERVICE, unsigned long 2, char * * 0x009a0e50) line 548
main(unsigned long 2, char * * 0x009a0e50) line 3131
mainCRTStartup() line 206 + 25 bytes
KERNEL32! 7c817067()

Here is the debug dissassembly up to the operation that fails:

0041EA7E   jmp         _heap_alloc_dbg+2B3h (0041eb23)
0041EA83   mov         edx,dword ptr [_lTotalAlloc (004b4294)]
0041EA89   add         edx,dword ptr [nSize]
0041EA8C   mov         dword ptr [_lTotalAlloc (004b4294)],edx
0041EA92   mov         eax,[_lCurAlloc (004b429c)]
0041EA97   add         eax,dword ptr [nSize]
0041EA9A   mov         [_lCurAlloc (004b429c)],eax
0041EA9F   mov         ecx,dword ptr [_lCurAlloc (004b429c)]
0041EAA5   cmp         ecx,dword ptr [_lMaxAlloc (004b42a0)]
0041EAAB   jbe         _heap_alloc_dbg+249h (0041eab9)
0041EAAD   mov         edx,dword ptr [_lCurAlloc (004b429c)]
0041EAB3   mov         dword ptr [_lMaxAlloc (004b42a0)],edx
0041EAB9   cmp         dword ptr [_pFirstBlock (004b4298)],0
0041EAC0   je          _heap_alloc_dbg+25Fh (0041eacf)
0041EAC2   mov         eax,[_pFirstBlock (004b4298)]
0041EAC7   mov         ecx,dword ptr [pHead]
0041EACA   mov         dword ptr [eax+4],ecx

Here is our source for that calls fopen() and fails in malloc()

FILE *open_new_log( const char *logfile )
{
    FILE *fp;
    int retry = 0;

    while( ( fp = fopen( logfile, "w" ) ) == NULL && ++retry < 300 )
        Sleep( 1000 );

    return( fp );
}

The error I get is

Unhandled exception inPISCOOP.exe: 0xC00000005: Access Violation

Regards,

--- Alistair.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

俏︾媚 2024-07-17 15:56:36

您可以使用 _CrtSetDbgFlag() 启用一系列有用的堆调试技术。 还有许多其他可用的 CRT 调试功能这应该可以帮助您找出问题所在。

You can use _CrtSetDbgFlag() to enable a bunch of useful heap debugging techniques. There's a host of other CRT debugging functions available that should help you track down where your problem is.

岁月打碎记忆 2024-07-17 15:56:36

当从调试器运行时,使用不同的堆; 这称为调试堆。 这与调试器外部使用的堆的行为不同,可以帮助您捕获此类问题。

请注意,Win32“调试堆”与 VC++“调试堆”不同; 然而,两者的目的或多或少是相同的。 请参阅本文,其中介绍了运行应用时的行为差异在调试器下。

在这种情况下,您可能在调用此函数之前通过注销堆块的结尾或开头而损坏了堆。

When run from the debugger, a different heap is used; this is referred to as the debug heap. This has different behaviour from the heap used outside the debugger, and is there to help you catch problems like this one.

Note that the Win32 "debug heap" is distinct from the VC++ "debug heap"; both are intended to do more or less the same thing, however. See this article which describes the difference in behaviour when you run the app under the debugger.

In this case, you have probably corrupted the heap before calling this function, either by writing off the end or off the start of a heap block.

绝對不後悔。 2024-07-17 15:56:36

最简单的方法(假设您的应用程序没有过度使用内存)是启用全页堆检查(这将在提供分配的内存页之后放置所谓的保护页,反过来,这将查明确切的内存页)代码中发生损坏的地方)。

鉴于您有Windows 调试工具,请运行以下 gflags 命令配置整页堆:

<代码>
gflags[.exe] /p /enable yourapp.exe /full

注意,您应该单独提供可执行文件名称(即没有路径前缀!)

然后只需在调试器下运行它 - 第一次尝试损坏堆时它将中断。 这里的区别在于,堆损坏大多是延迟缺陷,当(可能)有效的堆操作生效时,这些缺陷会在稍后显现出来。

另请注意:

<代码>
gflags[.exe] /p /enable yourapp.exe /full /backwards

将在分配之前另外放置一个保护页面。

单独使用 /p 开关运行将显示当前有效的堆页面选项。

The easiest of approaches (provided that your application is not using memory too extensively) is to enable full page heap check (which will place so called guard page after the memory page your allocation is provided from, which, in turn, will pinpoint the exact place in your code where corruption takes place).

Given that you have Windows debugging tools handy, run the following gflags command to configure full page heap:


gflags[.exe] /p /enable yourapp.exe /full

Note, you should provide executable name alone (i.e. without path prefix!)

Then just run it under the debugger - it will break with the first attempt to corrupt the heap. The difference here is that heap corruptions are mostly delayed defects which manifest themselves later, when a (possibly) valid heap operation is in effect.

Note, also:


gflags[.exe] /p /enable yourapp.exe /full /backwards

will additionally place a guard page prior to your allocation.

Running with /p switch alone will display heap page options currently in effect.

七色彩虹 2024-07-17 15:56:36

您可能有堆损坏错误。 您的应用程序可能在调用 open_new_log() 之前损坏了堆。

You may have a heap corruption bug. Your application may have corrupted the heap before open_new_log() is called.

不离久伴 2024-07-17 15:56:36

我怀疑 jmattias 是对的。 问题的根本原因可能不在崩溃的地方。

很多事情都会导致堆损坏。

  • 写入超过分配的内存块的末尾(或开头)。
  • 释放指针两次,或释放未分配的指针。
  • 对程序进行多线程处理并与单线程(非线程安全)RTL 链接。
  • 从一个堆分配内存并在另一堆上释放它。
  • 等等,

由于您使用的是 Visual C++,因此您可以使用调试堆的 _CrtSetDbgFlag() 功能来打开错误检查。 您可以将其设置为在每次调用 malloc 或 free 时检查堆的完整性。 这将运行得非常慢,但它应该可以为您查明错误所在。

在编译器文档中搜索 _CrtSetDbgFlag。

I suspect jmattias is right. The root cause of the problem is likely somewhere else than where it is crashing.

A lot of things can cause heap corruption.

  • writing past the end (or beginning) of the memory block that was allocated.
  • freeing a pointer twice, or freeing a pointer that wasn't allocated.
  • multithreading your program and linking with the single-threaded (not thread safe) RTL.
  • allocating memory from one heap and freeing it on another heap.
  • etc., etc.,

Since you're using Visual C++, you can use the _CrtSetDbgFlag() feature of the debug heap to turn on error checking. You can set it to check the integrity of the heap on each call to malloc or free. That will run very slowly, but it should pinpoint where the bug is for you.

Search for _CrtSetDbgFlag in the compiler docs.

惟欲睡 2024-07-17 15:56:36

我怀疑有一个 DLL 使用与应用程序的其余部分不同版本的 C++ 运行时编译。 这通常会导致“地址 XXX 处的内存无法‘读’/‘写’”违规。

I have a suspicion that there is a DLL compiled with a different version of the C++ runtime than the rest of the application. This will often result in "memory at address XXX could not be 'read'/'written'" violations.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文