Visual Studio: 在 main() 函数调用之前调试
Visual Studio: Debug before main() function call
我遇到了一个问题,我的应用程序在执行任何操作之前就无法通过调试断言 (_CrtIsValidHeapPointer)。我知道这一点是因为我在 main 函数的第一条语句上添加了一个断点,并且在到达断点之前断言失败。
有没有办法以某种方式 "step through" 在调用主函数之前发生的所有事情?静态成员初始化等
我应该注意到我的程序是用 C++/CLI 编写的。我最近升级到 VS2015,目标是 v140 工具集。我正在使用的 C++ 库(ImageMagick、libsquish 和我自己的 C++ 库之一)已经过单独测试,我没有收到这些库的断言失败,所以它必须是我的主要应用程序。
自从我从 VS2013 升级后,我没有更改任何代码,所以我对发生的事情有点困惑。
编辑:
这是调用堆栈。这是我点击"Retry"后断言失败window。然后我会抛出许多其他异常,但每次我 运行 程序时它们都不一样。
> ucrtbased.dll!527a6853()
[Frames below may be incorrect and/or missing, no symbols loaded for ucrtbased.dll]
ucrtbased.dll!527a7130()
ucrtbased.dll!527a69cb()
ucrtbased.dll!527c8116()
ucrtbased.dll!527c7eb3()
ucrtbased.dll!527c7fb3()
ucrtbased.dll!527c84b0()
PathCreator.exe!_onexit(int (void)* const function) Line 268 + 0xe bytes C++
PathCreator.exe!atexit(void (void)* const function) Line 276 + 0x9 bytes C++
PathCreator.exe!std::`dynamic initializer for '_Fac_tidy_reg''() Line 65 + 0xd bytes C++
[External Code]
mscoreei.dll!7401cd87()
mscoree.dll!741fdd05()
kernel32.dll!76c33744()
ntdll.dll!7720a064()
ntdll.dll!7720a02f()
您必须调试 C 运行时初始化代码。这样做并不直观,因为调试器会努力避免它并让您进入 main() 入口点。但仍有可能,请使用调试 > 新断点 > 函数断点。
为函数名称输入 _initterm
,语言 = C。
按F5,断点就会命中。您应该看到 C 运行时源代码。您现在可以一个接一个地单步执行程序的初始化函数,每次调用 (**it)()
都会执行一个。
这正是您所要求的。但不太可能是你真正想要的。 您的 代码产生此错误的几率非常低。更有可能是这些库之一导致了这个问题。它们很可能是针对 C 运行时库的 另一个 版本构建的。因此有自己的 _initterm() 函数。
在一个进程中拥有多个 C 运行时库副本通常是非常不健康的。并且极有可能产生堆损坏。如果您无法从堆栈跟踪中找到它(请务必将调试器类型从自动更改为混合,始终 post SO 问题中的堆栈跟踪)那么接下来您应该 强烈 考虑使用您使用的 VS 版本重建这些库。
我遇到了一个问题,我的应用程序在执行任何操作之前就无法通过调试断言 (_CrtIsValidHeapPointer)。我知道这一点是因为我在 main 函数的第一条语句上添加了一个断点,并且在到达断点之前断言失败。
有没有办法以某种方式 "step through" 在调用主函数之前发生的所有事情?静态成员初始化等
我应该注意到我的程序是用 C++/CLI 编写的。我最近升级到 VS2015,目标是 v140 工具集。我正在使用的 C++ 库(ImageMagick、libsquish 和我自己的 C++ 库之一)已经过单独测试,我没有收到这些库的断言失败,所以它必须是我的主要应用程序。
自从我从 VS2013 升级后,我没有更改任何代码,所以我对发生的事情有点困惑。
编辑: 这是调用堆栈。这是我点击"Retry"后断言失败window。然后我会抛出许多其他异常,但每次我 运行 程序时它们都不一样。
> ucrtbased.dll!527a6853()
[Frames below may be incorrect and/or missing, no symbols loaded for ucrtbased.dll]
ucrtbased.dll!527a7130()
ucrtbased.dll!527a69cb()
ucrtbased.dll!527c8116()
ucrtbased.dll!527c7eb3()
ucrtbased.dll!527c7fb3()
ucrtbased.dll!527c84b0()
PathCreator.exe!_onexit(int (void)* const function) Line 268 + 0xe bytes C++
PathCreator.exe!atexit(void (void)* const function) Line 276 + 0x9 bytes C++
PathCreator.exe!std::`dynamic initializer for '_Fac_tidy_reg''() Line 65 + 0xd bytes C++
[External Code]
mscoreei.dll!7401cd87()
mscoree.dll!741fdd05()
kernel32.dll!76c33744()
ntdll.dll!7720a064()
ntdll.dll!7720a02f()
您必须调试 C 运行时初始化代码。这样做并不直观,因为调试器会努力避免它并让您进入 main() 入口点。但仍有可能,请使用调试 > 新断点 > 函数断点。
为函数名称输入 _initterm
,语言 = C。
按F5,断点就会命中。您应该看到 C 运行时源代码。您现在可以一个接一个地单步执行程序的初始化函数,每次调用 (**it)()
都会执行一个。
这正是您所要求的。但不太可能是你真正想要的。 您的 代码产生此错误的几率非常低。更有可能是这些库之一导致了这个问题。它们很可能是针对 C 运行时库的 另一个 版本构建的。因此有自己的 _initterm() 函数。
在一个进程中拥有多个 C 运行时库副本通常是非常不健康的。并且极有可能产生堆损坏。如果您无法从堆栈跟踪中找到它(请务必将调试器类型从自动更改为混合,始终 post SO 问题中的堆栈跟踪)那么接下来您应该 强烈 考虑使用您使用的 VS 版本重建这些库。