简体   繁体   English

程序仅在发布版本时崩溃——如何调试?

[英]Program only crashes as release build — how to debug?

I've got a "Schroedinger's Cat" type of problem here -- my program (actually the test suite for my program, but a program nonetheless) is crashing, but only when built in release mode, and only when launched from the command line.我在这里遇到了“薛定谔的猫”类型的问题——我的程序(实际上是我的程序的测试套件,但仍然是一个程序)崩溃了,但只有在发布模式下构建时,并且只有从命令行启动时. Through caveman debugging (ie, nasty printf() messages all over the place), I have determined the test method where the code is crashing, though unfortunately the actual crash seems to happen in some destructor, since the last trace messages I see are in other destructors which execute cleanly.通过穴居人调试(即到处都是讨厌的 printf() 消息),我确定了代码崩溃的测试方法,尽管不幸的是,实际崩溃似乎发生在某些析构函数中,因为我看到的最后一条跟踪消息在其他执行干净的析构函数。

When I attempt to run this program inside of Visual Studio, it doesn't crash.当我尝试在 Visual Studio 中运行此程序时,它不会崩溃。 Same goes when launching from WinDbg.exe.从 WinDbg.exe 启动时也是如此。 The crash only occurs when launching from the command line.只有从命令行启动时才会发生崩溃。 This is happening under Windows Vista, btw, and unfortunately I don't have access to an XP machine right now to test on.这发生在 Windows Vista 下,顺便说一句,不幸的是我现在无法访问 XP 机器进行测试。

It would be really nice if I could get Windows to print out a stack trace, or something other than simply terminating the program as if it had exited cleanly.这将是非常好的,如果我能得到的Windows打印出堆栈跟踪,或其他的东西比简单地结束,如果它已经退出干净方案。 Does anyone have any advice as to how I could get some more meaningful information here and hopefully fix this bug?有没有人对我如何在这里获得更有意义的信息并希望修复此错误有任何建议?

Edit: The problem was indeed caused by an out-of-bounds array, which I describe more in this post .编辑:问题确实是由越界数组引起的, 我在这篇文章中对此进行了更多描述 Thanks everybody for your help in finding this problem!感谢大家帮助找到这个问题!

In 100% of the cases I've seen or heard of, where a C or C++ program runs fine in the debugger but fails when run outside, the cause has been writing past the end of a function local array.在我见过或听说过的 100% 的情况下,C 或 C++ 程序在调试器中运行良好但在外部运行时失败,原因是写入函数本地数组的末尾。 (The debugger puts more on the stack, so you're less likely to overwrite something important.) (调试器会在堆栈上放置更多内容,因此您不太可能覆盖重要的内容。)

When I have encountered problems like this before it has generally been due to variable initialization.当我之前遇到这样的问题时,通常是由于变量初始化。 In debug mode, variables and pointers get initialized to zero automatically but in release mode they do not.在调试模式下,变量和指针会自动初始化为零,但在发布模式下不会。 Therefore, if you have code like this因此,如果你有这样的代码

int* p;
....
if (p == 0) { // do stuff }

In debug mode the code in the if is not executed but in release mode p contains an undefined value, which is unlikely to be 0, so the code is executed often causing a crash.在调试模式下,if 中的代码没有执行,但在发布模式下 p 包含一个未定义的值,该值不太可能为 0,因此代码执行时经常会导致崩溃。

I would check your code for uninitialized variables.我会检查您的代码是否有未初始化的变量。 This can also apply to the contents of arrays.这也适用于数组的内容。

No answer so far has tried to give a serious overview about the available techniques for debugging release applications:到目前为止,没有答案试图对调试发布应用程序的可用技术进行认真的概述:

  1. Release and Debug builds behave differently for many reasons.由于多种原因,发布和调试版本的行为不同。 Here is an excellent overview. 这是一个很好的概述。 Each of these differences might cause a bug in the Release build that doesn't exist in the Debug build.这些差异中的每一个都可能导致发布版本中存在调试版本中不存在的错误。

  2. The presence of a debugger may change the behavior of a program too , both for release and debug builds.调试器的存在也可能改变程序的行为,无论是发布版本还是调试版本。 See this answer.看到这个答案。 In short, at least the Visual Studio Debugger uses the Debug Heap automatically when attached to a program.简而言之,至少 Visual Studio 调试器在附加到程序时会自动使用调试堆。 You can turn the debug heap off by using environment variable _NO_DEBUG_HEAP .您可以使用环境变量 _NO_DEBUG_HEAP 关闭调试堆。 You can specify this either in your computer properties, or in the Project Settings in Visual Studio.您可以在计算机属性或 Visual Studio 的项目设置中指定此项。 That might make the crash reproducible with the debugger attached.这可能会使连接调试器的崩溃重现。

    More on debugging heap corruption here. 更多关于在此处调试堆损坏的信息。

  3. If the previous solution doesn't work, you need to catch the unhandled exception and attach a post-mortem debugger the instance the crash occurs.如果之前的解决方案不起作用,您需要捕获未处理的异常并在发生崩溃的实例上附加一个事后调试器 You can use eg WinDbg for this, details about the avaiable post-mortem debuggers and their installation at MSDN您可以为此使用例如 WinDbg, 有关 MSDN 上可用的事后调试器及其安装的详细信息

  4. You can improve your exception handling code and if this is a production application, you should:您可以改进您的异常处理代码,如果这是一个生产应用程序,您应该:

    a.一种。 Install a custom termination handler using std::set_terminate使用std::set_terminate安装自定义终止处理程序

    If you want to debug this problem locally, you could run an endless loop inside the termination handler and output some text to the console to notify you that std::terminate has been called.如果你想在本地调试这个问题,你可以在终止处理程序中运行一个无限循环并向控制台输出一些文本来通知你std::terminate已被调用。 Then attach the debugger and check the call stack.然后附加调试器并检查调用堆栈。 Or you print the stack trace as described in this answer. 或者您按照本答案中的描述打印堆栈跟踪。

    In a production application you might want to send an error report back home, ideally together with a small memory dump that allows you to analyze the problem as described here.在生产应用程序中,您可能希望将错误报告发送回家,最好连同一个小型内存转储一起发送,以便您按此处所述分析问题。

    b.Use Microsoft's structured exception handling mechanism that allows you to catch both hardware and software exceptions.使用 Microsoft 的结构化异常处理机制,该机制允许您捕获硬件和软件异常。 See MSDN . 请参阅 MSDN You could guard parts of your code using SEH and use the same approach as in a) to debug the problem.您可以使用 SEH 保护部分代码并使用与 a) 中相同的方法来调试问题。 SEH gives more information about the exception that occurred that you could use when sending an error report from a production app. SEH 提供了有关发生的异常的更多信息,您可以在从生产应用程序发送错误报告时使用这些信息。

Things to look out for:需要注意的事项:

Array overruns - the visual studio debugger inserts padding which may stop crashes.数组溢出 - Visual Studio 调试器插入可能会阻止崩溃的填充。

Race conditions - do you have multiple threads involved if so a race condition many only show up when an application is executed directly.竞争条件 - 如果这样,竞争条件很多只在直接执行应用程序时出现,您是否涉及多个线程。

Linking - is your release build pulling in the correct libraries.链接 - 您的发布版本是否包含了正确的库。

Things to try:尝试的事情:

Minidump - really easy to use (just look it up in msdn) will give you a full crash dump for each thread. Minidump - 非常易于使用(只需在 msdn 中查找)将为您提供每个线程的完整崩溃转储。 You just load the output into visual studio and it is as if you were debugging at the time of the crash.您只需将输出加载到 Visual Studio 中,就好像您在崩溃时正在调试一样。

You can set WinDbg as your postmortem debugger.您可以将 WinDbg 设置为事后调试器。 This will launch the debugger and attach it to the process when the crash occurs.这将启动调试器并将其附加到发生崩溃时的进程。 To install WinDbg for postmortem debugging, use the /I option (note it is capitalized ):要安装 WinDbg 进行事后调试,请使用 /I 选项(注意它是大写的):

windbg /I

More details here .更多细节在这里

As to the cause, it's most probably an unitialized variable as the other answers suggest.至于原因,正如其他答案所暗示的那样,它很可能是一个未初始化的变量。

After many hours of debugging, I finally found the cause of the problem, which was indeed caused by a buffer overflow, caused a single byte difference:经过几个小时的调试,终于找到了问题的原因,确实是缓冲区溢出导致了单字节差异:

char *end = static_cast<char*>(attr->data) + attr->dataSize;

This is a fencepost error (off-by-one error) and was fixed by:这是一个围栏错误(一对一错误)并通过以下方式修复:

char *end = static_cast<char*>(attr->data) + attr->dataSize - 1;

The weird thing was, I put several calls to _CrtCheckMemory() around various parts of my code, and they always returned 1. I was able to find the source of the problem by placing "return false;"奇怪的是,我在代码的各个部分多次调用 _CrtCheckMemory(),它们总是返回 1。我能够通过放置“return false;”找到问题的根源。 calls in the test case, and then eventually determining through trial-and-error where the fault was.调用测试用例,然后最终通过反复试验确定错误所在。

Thanks everybody for your comments -- I learned a lot about windbg.exe today!谢谢大家的评论——今天我学到了很多关于windbg.exe的知识! :) :)

Even though you have built your exe as a release one, you can still generate PDB (Program database) files that will allow you to stack trace, and do a limited amount of variable inspection.即使您已将 exe 构建为发行版,您仍然可以生成 PDB(程序数据库)文件,这些文件将允许您进行堆栈跟踪,并进行有限数量的变量检查。 In your build settings there is an option to create the PDB files.在您的构建设置中,有一个选项可以创建 PDB 文件。 Turn this on and relink.打开它并重新链接。 Then try running from the IDE first to see if you get the crash.然后首先尝试从 IDE 运行以查看是否发生崩溃。 If so, then great - you're all set to look at things.如果是这样,那就太好了——你们都准备好看看事情了。 If not, then when running from the command line you can do one of two things:如果没有,那么从命令行运行时,您可以执行以下两项操作之一:

  1. Run EXE, and before the crash do an Attach To Process (Tools menu on Visual Studio).运行 EXE,并在崩溃之前执行附加到进程(Visual Studio 上的工具菜单)。
  2. After the crash, select the option to launch debugger.崩溃后,选择启动调试器的选项。

When asked to point to PDB files, browse to find them.当要求指向 PDB 文件时,浏览以找到它们。 If the PDB's were put in the same output folder as your EXE or DLL's they will probably be picked up automatically.如果 PDB 与 EXE 或 DLL 放在相同的输出文件夹中,它们可能会被自动提取。

The PDB's provide a link to the source with enough symbol information to make it possible to see stack traces, variables etc. You can inspect the values as normal, but do be aware that you can get false readings as the optimisation pass may mean things only appear in registers, or things happen in a different order than you expect. PDB 提供了一个带有足够符号信息的源链接,可以查看堆栈跟踪、变量等。您可以照常检查这些值,但请注意,您可能会得到错误读数,因为优化传递可能仅意味着某些事情出现在寄存器中,或者事情发生的顺序与您预期的不同。

NB: I'm assuming a Windows/Visual Studio environment here.注意:我在这里假设一个 Windows/Visual Studio 环境。

Crashes like this are almost always caused because an IDE will usually set the contents of uninitialized variable to zeros, null or some other such 'sensible' value, whereas when running natively you'll get whatever random rubbish that the system picks up.像这样的崩溃几乎总是引起的,因为 IDE 通常会将未初始化的变量的内容设置为零、空或其他一些此类“合理”值,而在本机运行时,您将获得系统拾取的任何随机垃圾。

Your error is therefore almost certainly that you are using something like you are using a pointer before it has been properly initialized and you're getting away with it in the IDE because it doesn't point anywhere dangerous - or the value is handled by your error checking - but in release mode it does something nasty.因此,您的错误几乎可以肯定是您正在使用类似在正确初始化之前使用指针的东西,并且您在 IDE 中逃脱了它,因为它没有指向任何危险的地方 - 或者该值由您的错误检查 - 但在发布模式下它会做一些令人讨厌的事情。

In order to have a crash dump that you can analyze:为了获得可以分析的故障转储:

  1. Generate pdb files for your code.为您的代码生成 pdb 文件。
  2. You rebase to have your exe and dlls loaded in the same address.你变基让你的 exe 和 dll 加载到相同的地址。
  3. Enable post mortem debugger such as Dr. Watson启用事后调试器,例如Dr. Watson
  4. Check the crash failures address using a tool such as crash finder .使用诸如crash finder 之类的工具检查崩溃失败地址。

You should also check out the tools in Debugging tools for windows .您还应该查看Debugging tools for windows中的 工具 You can monitor the application and see all the first chance exceptions that were prior to your second chance exception.您可以监视应用程序并查看第二次机会异常之前的所有第一次机会异常。

Hope it helps...希望能帮助到你...

调试此类错误的一个好方法是为您的调试版本启用优化。

Once i had a problem when app behaved similarily to yours.有一次,当应用程序的行为与您的相似时,我遇到了问题。 It turned out to be a nasty buffer overrun in sprintf.结果证明是 sprintf 中令人讨厌的缓冲区溢出。 Naturally, it worked when run with a debugger attached.自然地,它在带有调试器的情况下运行时有效。 What i did, was to install an unhandled exception filter ( SetUnhandledExceptionFilter ) in which i simply blocked infinitely (using WaitForSingleObject on a bogus handle with a timeout value of INFINITE).我所做的是安装一个未处理的异常过滤器( SetUnhandledExceptionFilter ),在其中我只是无限地阻止(在超时值为 INFINITE 的虚假句柄上使用 WaitForSingleObject )。

So you could something along the lines of:所以你可以按照以下方式进行操作:

long __stdcall MyFilter(EXCEPTION_POINTERS *)
{
    HANDLE hEvt=::CreateEventW(0,1,0,0);
    if(hEvt)
    {
        if(WAIT_FAILED==::WaitForSingleObject(hEvt, INFINITE))
        {
            //log failure
        }
    }

}
// somewhere in your wmain/WinMain:
SetUnhandledExceptionFilter(MyFilter);

I then attached the debugger after the bug had manifested itself (gui program stopped responding).然后我在错误出现后附加了调试器(gui 程序停止响应)。

Then you can either take a dump and work with it later:然后,您可以进行转储并稍后使用它:

.dump /ma path_to_dump_file .dump /ma path_to_dump_file

Or debug it right away.或者直接调试。 The simplest way is to track where processor context has been saved by the runtime exception handling machinery:最简单的方法是跟踪运行时异常处理机制保存处理器上下文的位置:

sd esp Range 1003f sd esp范围1003f

Command will search stack address space for CONTEXT record(s) provided the length of search.命令将为 CONTEXT 记录搜索堆栈地址空间,提供搜索长度。 I usually use something like 'l?10000' .我通常使用类似'l?10000' 的东西。 Note, do not use unsually large numbers as the record you're after usually near to the unhanded exception filter frame.请注意,不要使用异常大的数字作为通常靠近未处理异常过滤器帧的记录。 1003f is the combination of flags (i believe it corresponds to CONTEXT_FULL) used to capture the processor state. 1003f 是用于捕获处理器状态的标志组合(我相信它对应于 CONTEXT_FULL)。 Your search would look similar to this:您的搜索将类似于以下内容:

0:000> sd esp l1000 1003f 0:000> sd esp l1000 1003f
0012c160 0001003f 00000000 00000000 00000000 ?............... 0012c160 0001003f 00000000 00000000 00000000 ......................

Once you get results back, use the address in the cxr command:得到结果后,使用 cxr 命令中的地址:

.cxr 0012c160 .cxr 0012c160

This will take you to this new CONTEXT, exactly at the time of crash (you will get exactly the stack trace at the time your app crashed).这将带您进入这个新的 CONTEXT,恰好在崩溃时(您将准确地获得应用程序崩溃时的堆栈跟踪)。 Additionally, use:此外,使用:

.exr -1 .exr -1

to find out exactly which exception had occurred.以准确找出发生了哪个异常。

Hope it helps.希望能帮助到你。

Sometimes this happens because you have wrapped important operation inside "assert" macro.有时发生这种情况是因为您在“assert”宏中包含了重要的操作。 As you may know, "assert" evaluates expressions only on debug mode.您可能知道,“assert”仅在调试模式下评估表达式。

Vista SP1 actually has a really nice crash dump generator built into the system. Vista SP1 实际上在系统中内置了一个非常好的故障转储生成器。 Unfortunately, it isn't turned on by default!不幸的是,默认情况下它没有打开!

See this article: http://msdn.microsoft.com/en-us/library/bb787181(VS.85).aspx请参阅这篇文章: http : //msdn.microsoft.com/en-us/library/bb787181(VS.85).aspx

The benefit of this approach is that no extra software needs to be installed on the affected system.这种方法的好处是不需要在受影响的系统上安装额外的软件。 Grip it and rip it, baby!抓住它,撕开它,宝贝!

With regard to your problems getting diagnostic information, have you tried using adplus.vbs as an alternative to WinDbg.exe?关于获取诊断信息的问题,您是否尝试过使用 adplus.vbs 作为 WinDbg.exe 的替代方案? To attach to a running process, use要附加到正在运行的进程,请使用

adplus.vbs -crash -p <process_id>

Or to start the application in the event that the crash happens quickly:或者在崩溃很快发生的情况下启动应用程序:

adplus.vbs -crash -sc your_app.exe

Full info on adplus.vbs can be found at: http://support.microsoft.com/kb/286350有关 adplus.vbs 的完整信息,请访问: http : //support.microsoft.com/kb/286350

Ntdll.dll with debugger attached带有调试器的 Ntdll.dll

One little know difference between launching a program from the IDE or WinDbg as opposed to launching it from command line / desktop is that when launching with a debugger attached (ie IDE or WinDbg) ntdll.dll uses a different heap implementation which performs some little validation on the memory allocation/freeing.从 IDE 或 WinDbg 启动程序与从命令行/桌面启动程序之间的一个小区别是,当使用附加的调试器(即 IDE 或 WinDbg)启动时,ntdll.dll 使用不同的堆实现,它执行一些小的验证关于内存分配/释放。

You may read some relevant information in unexpected user breakpoint in ntdll.dll .您可能会在 ntdll.dll中的意外用户断点中阅读一些相关信息。 One tool which might be able to help you identifying the problem is PageHeap.exe .一种可能可以帮助您识别问题的工具是PageHeap.exe

Crash analysis崩溃分析

You did not write what is the "crash" you are experiencing.您没有写下您正在经历的“崩溃”是什么。 Once the program crashes and offers you to send the error information to the Microsoft, you should be able to click on the technical information and to check at least the exception code, and with some effort you can even perform post-mortem analysis (see Heisenbug: WinApi program crashes on some computers) for instructions)一旦程序崩溃并让您将错误信息发送给 Microsoft,您应该能够单击技术信息并至少检查异常代码,并且通过一些努力您甚至可以执行事后分析(请参阅Heisenbug : WinApi 程序在某些计算机上崩溃)以获取说明)

As my experience, that are most being memory corruption issues.根据我的经验,这主要是内存损坏问题。

For example :例如 :

char a[8];
memset(&a[0], 0, 16);

: /*use array a doing some thing */

it is very possible to be normal in debug mode when one runs the code.很可能在调试模式下运行代码时是正常的。

But in release, that would/might be crash.但是在发布时,这会/可能会崩溃。

For me, to rummage where the memory is out of bound is too toilsome.对我来说,翻找记忆出界的地方太费劲了。

Use some tools like Visual Leak Detector (windows) or valgrind (linux) are more wise choise.使用一些工具,如Visual Leak Detector (windows) 或valgrind (linux) 是更明智的选择。

I've seen a lot of right answers.我看过很多正确的答案。 However, there is none that helped me.然而,没有一个能帮助我。 In my case, there was a wrong usage of the SSE instructions with the unaligned memory .就我而言, SSE 指令未对齐内存的使用错误。 Take a look at your math library (if you use one), and try to disable SIMD support, recompile and reproduce the crash.查看您的数学库(如果您使用),并尝试禁用 SIMD 支持,重新编译并重现崩溃。

Example:例子:

A project includes mathfu , and uses the classes with STL vector: std::vector< mathfu::vec2 > .一个项目包括mathfu ,并使用带有 STL 向量的类: std::vector< mathfu::vec2 > Such usage will probably cause a crash at the time of the construction of mathfu::vec2 item since the STL default allocator does not guarantee required 16-byte alignment.这种用法可能会在构建mathfu::vec2项时导致崩溃,因为 STL 默认分配器不保证所需的 16 字节对齐。 In this case to prove the idea, one can define #define MATHFU_COMPILE_WITHOUT_SIMD_SUPPORT 1 before each include of the mathfu , recompile in Release configuration and check again.在这种情况下,以证明这个想法,一个可以定义#define MATHFU_COMPILE_WITHOUT_SIMD_SUPPORT 1之前,每个包括的mathfu ,重新编译Release配置,并再次检查。

The Debug and RelWithDebInfo configurations worked well for my project, but not the Release one. DebugRelWithDebInfo配置适用于我的项目,但不适用于Release 1。 The reason behind this behavior is probably because debugger processes allocation/deallocation requests and does some memory bookkeeping to check and verify the accesses to the memory.这种行为背后的原因可能是因为调试器处理分配/解除分配请求并执行一些内存簿记以检查和验证对内存的访问。

I experienced the situation in Visual Studio 2015 and 2017 environments.我在 Visual Studio 2015 和 2017 环境中经历过这种情况。

Something similar happend to me once with GCC.我曾经在 GCC 上发生过类似的事情。 It turned out to be a too aggressive optimization that was enabled only when creating the final release and not during the development process.结果证明这是一个过于激进的优化,仅在创建最终版本时启用,而不是在开发过程中启用。

Well, to tell the truth it was my fault, not gcc's, as I didn't noticed that my code was relying on the fact that that particular optimization wouldn't have been done.好吧,说实话,这是我的错,而不是 gcc 的错,因为我没有注意到我的代码依赖于没有完成特定优化的事实。

It took me a lot of time to trace it and I only came to it because I asked on a newsgroup and somebody made me think about it.我花了很多时间去追踪它,我之所以找到它,是因为我在一个新闻组上提问,有人让我思考它。 So, let me return the favour just in case this is happening to you as well.所以,让我回报一下,以防万一这也发生在你身上。

I've found this this article useful for your scenario.我发现这篇文章对您的场景很有用。 ISTR the compiler options were a little out of date. ISTR 编译器选项有点过时了。 Look around your Visual Studio project options to see how to generate pdb files for your release build, etc.环顾您的 Visual Studio 项目选项,了解如何为您的发布版本等生成 pdb 文件。

It's suspicious that it would happen outside the debugger and not inside;可疑的是它会发生在调试器之外而不是内部。 running in the debugger does not normally change the application behavior.在调试器中运行通常不会改变应用程序的行为。 I would check the environment differences between the console and the IDE.我会检查控制台和 IDE 之间的环境差异。 Also, obviously, compile release without optimizations and with debug information, and see if that affects the behavior.此外,显然,编译没有优化和调试信息的版本,看看是否会影响行为。 Finally, check out the post-mortem debugging tools other people have suggested here, usually you can get some clue from them.最后,看看其他人在这里推荐的事后调试工具,通常你可以从他们那里得到一些线索。

Debugging release builds can be a pain due to optimizations changing the order in which lines of your code appear to be executed.由于优化更改了代码行的执行顺序,因此调试发布版本可能会很痛苦。 It can really get confusing!它真的会让人困惑!

One technique to at least narrow down the problem is to use MessageBox() to display quick statements stating what part of the program your code has got to ("Starting Foo()", "Starting Foo2()");至少缩小问题范围的一种技术是使用 MessageBox() 显示快速语句,说明您的代码已到达程序的哪个部分(“启动 Foo()”、“启动 Foo2()”); start putting them at the top of functions in the area of your code that you suspect (what were you doing at the time when it crashed?).开始将它们放在您怀疑的代码区域中的函数顶部(当它崩溃时您在做什么?)。 When you can tell which function, change the message boxes to blocks of code or even individual lines within that function until you narrow it down to a few lines.当您可以分辨出哪个函数时,将消息框更改为代码块,甚至是该函数中的单个行,直到将其缩小到几行。 Then you can start printing out the value of variables to see what state they are in at the point of crashing.然后你可以开始打印变量的值,看看它们在崩溃时处于什么状态。

Try using _CrtCheckMemory() to see what state the allocated memory is in .尝试使用_CrtCheckMemory()查看分配的内存处于什么状态。 If everything goes well , _CrtCheckMemory returns TRUE , else FALSE .如果一切顺利, _CrtCheckMemory返回TRUE ,否则返回FALSE

You might run your software with Global Flags enabled (Look in Debugging Tools for Windows).您可能会在启用全局标志的情况下运行您的软件(查看 Windows 调试工具)。 It will very often help to nail the problem.它通常有助于解决问题。

Make your program generate a mini dump when the exception occurs, then open it up in a debugger (for example, in WinDbg).当异常发生时,让你的程序生成一个小型转储,然后在调试器中打开它(例如,在 WinDbg 中)。 The key functions to look at: MiniDumpWriteDump, SetUnhandledExceptionFilter要查看的关键函数:MiniDumpWriteDump、SetUnhandledExceptionFilter

Here's a case I had that somebody might find instructive.这是我遇到的一个案例,有人可能会觉得很有启发性。 It only crashed in release in Qt Creator - not in debug.它只在 Qt Creator 的发布中崩溃 - 而不是在调试中。 I was using .ini files (as I prefer apps that can be copied to other drives, vs. ones that lose their settings if the Registry gets corrupted).我使用的是 .ini 文件(因为我更喜欢可以复制到其他驱动器的应用程序,而不是那些在注册表损坏时丢失设置的应用程序)。 This applies to any apps that store their settings under the apps' directory tree.这适用于将其设置存储在应用程序目录树下的任何应用程序。 If the debug and release builds are under different directories, you can have a setting that's different between them, too.如果调试和发布版本位于不同的目录下,您也可以在它们之间使用不同的设置。 I had preference checked in one that wasn't checked in the other.我有偏好签入一个没有签入另一个。 It turned out to be the source of my crash.原来它是我崩溃的根源。 Good thing I found it.还好我找到了。

I hate to say it, but I only diagnosed the crash in MS Visual Studio Community Edition;我不想这么说,但我只是在 MS Visual Studio Community Edition 中诊断出崩溃; after having VS installed, letting my app crash in Qt Creator, and choosing to open it in Visual Studio's debugger.安装 VS 后,让我的应用程序在 Qt Creator 中崩溃,并选择在Visual Studio 的调试器中打开它。 While my Qt app had no symbol info, it turns out that the Qt libraries had some.虽然我的 Qt 应用程序没有符号信息,但事实证明 Qt 库有一些。 It led me to the offending line;它把我引向了违规行; since I could see what method was being called.因为我可以看到正在调用什么方法。 (Still, I think Qt is a convenient, powerful, & cross-platform LGPL framework.) (不过,我认为 Qt 是一个方便、强大且跨平台的 LGPL 框架。)

I had this problem too.我也有这个问题。 In my case, the RELEASE mode was having msvscrtd.dll in the linker definition.就我而言,RELEASE 模式在链接器定义中包含 msvscrtd.dll。 We removed it and the issue resolved.我们删除了它并解决了问题。

Alternatively, adding /NODEFAULTLIB to the linker command line arguments also resolved the issue.或者,将 /NODEFAULTLIB 添加到链接器命令行参数也解决了该问题。

I'll add another possibility for future readers: Check if you're logging to stderr or stdout from an application with no console window (ie you linked with /SUBSYSTEM:WINDOWS).我将为未来的读者添加另一种可能性:检查您是否从没有控制台窗口的应用程序登录到 stderr 或 stdout(即您与 /SUBSYSTEM:WINDOWS 链接)。 This can crash.这可能会崩溃。

I had a GUI application where I logged to both stderr and a file in both debug and release, so logging was always enabled.我有一个 GUI 应用程序,我在调试和发布中都登录到 stderr 和一个文件,因此始终启用日志记录。 I created a console window in debug for easy viewing of the logs, but not in release.我在调试中创建了一个控制台窗口,以便于查看日志,但不在发布中创建。 However, if the VS debugger is attached to the release build, it'll automatically pipe stderr to the VS output window.但是,如果 VS 调试器附加到发布版本,它会自动通过管道将 stderr 传送到 VS 输出窗口。 So only in release with no debugger did it actually crash when I wrote to stderr.所以只有在没有调试器的版本中,当我写到 stderr 时它才真正崩溃。

To make things worse, printf debugging obviously didn't work, which I didn't understand why until I'd tracked down the root cause (by painfully bisecting the codebase by inserting an infinite loop in various spots).更糟糕的是, printf 调试显然不起作用,我不明白为什么直到我找到了根本原因(通过在各个位置插入一个无限循环来痛苦地平分代码库)。

I had this error and vs crashed even when trying to !clean!我遇到了这个错误,即使在尝试 !clean 时 vs 崩溃了! my project.我的项目。 So I deleted the obj files manually from the Release directory, and after that it built just fine.所以我从 Release 目录中手动删除了 obj 文件,之后它构建得很好。

I agree with Rolf.我同意罗尔夫的观点。 Because reproducibility is so important, you shouldn't have a non-debug mode.因为可重现性非常重要,所以您不应该使用非调试模式。 All your builds should be debuggable.您的所有构建都应该是可调试的。 Having two targets to debug more than doubles your debugging load.有两个目标进行调试会使您的调试负载增加一倍以上。 Just ship the "debug mode" version, unless it is unusable.只需发布“调试模式”版本,除非它不可用。 In which case, make it usable.在这种情况下,使其可用。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM