The program will only work as a build release - how to debug it?

I have a problem like "Schroedinger Cat" here - my program (actually a test suite for my program, but the program nonetheless) crashes, but only when building in release mode and only when starting from the command line. Through debugging the caveman (i.e. the nasty printf () messages everywhere) I defined a testing method where the code crashes, but unfortunately the actual crashes seem to happen in some destructor, since the last trace messages I see are are in other destructors that execute cleanly.

When I try to run this program inside Visual Studio, it does not crash. The same thing happens when starting from WinDbg.exe. A failure only occurs when starting from the command line. This happens under Windows Vista, by the way, unfortunately, I do not have access to the XP machine right now to test it.

It would be very nice if I could get Windows to print a stack trace or something other than just terminating the program, as if it came out cleanly. Does anyone have any tips on how I could get more relevant information here and hopefully fix this error?

Edit: The problem was really caused by the out-of-bounds array, which I describe more in this post . Thank you all for your help in finding this problem!

+72
c ++ debugging
Oct 09 '08 at 7:18
source share
25 answers

In 100% of cases that I saw or heard about, where the C or C ++ program works fine in the debugger, but does not work when launched from the outside, the reason was written at the end of the local function array. (The debugger pushes more on the stack, so you are unlikely to restart something important.)

+98
Oct 09 '08 at 7:41
source share
β€” -

When I ran into such problems before this happened due to an initialization variable. In debug mode, variables and pointers are initialized to zero automatically, but in release mode they do not. Therefore, if you have such code

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

In debug mode, the code in 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.

I would check your code for uninitialized variables. This may also apply to the contents of arrays.

+45
Oct 09 '08 at 7:24
source share

What to look for:

Array overflow - The visual studio debugger inserts padding that can stop the crash.

Race conditions - do you have several threads, if this race condition is a lot, only when the application is executed directly.

Linking - your release build pulls the right libraries.

What you need to try:

Minidump is really easy to use (just see it in msdn), it will give you a complete crash dump for each thread. You just load the output into a visual studio, and it's as if you were debugging during a crash.

+15
Oct 09 '08 at 8:15
source share

So far, no answer has tried to give a serious overview of the methods available for debugging release applications:

  • The release and debug builds behave differently for many reasons. Here is a great review. Each of these differences can result in an error in the Release assembly that does not exist in the Debug assembly.

  • Having a debugger can also change program behavior for both releases and debugging. See this answer. In short, at least the Visual Studio debugger automatically uses the debug heap when connecting to the program. You can disable the debug heap using the _NO_DEBUG_HEAP environment variable. You can specify this either in the properties of your computer, or in the project settings in Visual Studio. This can cause the alarm to sound when a debugger is connected.

    Read more about debugging heaps here.

  • If the previous solution does not work, you need to catch the unhandled exception and attach a posthumous debugger instance of the failure. You can use for example. WinDbg for this, detailed information about the available fenders and their installation on MSDN

  • You can improve the exception handling code, and if it is a production application, you should:

    but. Set your own completion handler using std::set_terminate

    If you want to debug this problem locally, you can run an endless loop inside the completion handler and print text to the console to notify you that std::terminate been called. Then attach the debugger and check the call stack. Or you print a stack trace as described in this answer.

    In a production application, you can send a bug report home, ideally with a small memory dump that will allow you to analyze the problem as described here.

    b. Use Microsoft's structured exception handling engine to detect both hardware and software exceptions. See MSDN . You can protect parts of your code with SEH and use the same approach as for a) to debug the problem. SEH provides more information about the exception that occurred that you might use when sending an error report from a production application.

+14
Aug 29 '13 at 14:01
source share

You can install WinDbg as a postmortem debugger. This will launch the debugger and attach it to the process when a failure occurs. To install WinDbg for postmortem debugging, use the / I switch (note: uppercase ):

 windbg /I 

More details here .

As for the reason, this is most likely a unified variable, as the other answers indicate.

+12
Oct 09 '08 at 7:33
source share

After many hours of debugging, I finally found the cause of the problem, which was really caused by a buffer overflow, causing a difference in one byte:

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

This is a fencepost error (one by one error) and has been fixed:

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

Strange, I placed several calls to _CrtCheckMemory () around various parts of my code, and they always returned 1. I could find the source of the problem by setting "return false"; calls in the test case, and then, ultimately, determine by trial and error in which the error occurred.

Thanks to everyone for your comments - I learned a lot about windbg.exe today! :)

+8
Oct 09 '08 at 16:04
source share

Despite the fact that you created your exe as a release, you can still create PDB (Program database) files that allow you to trace the trace and perform a limited check of variables. In your build settings, it is possible to create PDB files. Turn it on and reconnect. Then try starting from the IDE to make sure you get a crash. If so, then great - you are all ready to look at things. If not, when you start from the command line, you can do one of two things:

  • Run the EXE and run the Attach To Process command (Tools menu in Visual Studio) before the crash.
  • After the failure, select the option to start the debugger.

When you are asked to specify the PDB files, find them. If the PDBs were placed in the same output folder as the EXE or DLL, they are likely to be automatically loaded.

The PDB provides a link to the source with enough character information so that you can see stack traces, variables, etc. You can check the values ​​as usual, but keep in mind that you can get false readings, because skipping optimization can mean things only appear in registers, or things happen in a different order than you expect.

NB: I assume the Windows / Visual Studio environment is here.

+7
09 Oct '08 at 7:51
source share

To have a crash dump that you can analyze:

  • Create pdb files for your code.
  • You are updating so that your exe and dll load at the same address.
  • Enable the post mortem debugger, for example, Dr. Watson
  • Check the address of the failure by using a tool such as troubleshooting .

You should also check the tools in Debugging Tools for Windows . You can track the application and view all first chance exceptions that came before your second exception.

Hope this helps ...

+3
Oct 09 '08 at 7:38
source share

Such failures are almost always caused due to the fact that the IDE usually sets the contents of an uninitialized variable to zeros, null, or some other such "reasonable" value, whereas when you start, you will initially receive any random garbage that the system takes up.

So your mistake almost certainly is that you use something like using a pointer before it was properly initialized, and you walk away from it in the IDE because it does not indicate that anywhere dangerous - or the value is handled by your error check, but in release mode it does something unpleasant.

+2
Oct 09 '08 at 7:29
source share

As soon as I had a problem when the application was like yours. This turned out to be an unpleasant buffer overflow in sprintf. Naturally, it worked at startup with a connected debugger. I installed an unhandled exception filter ( SetUnhandledExceptionFilter ), in which I simply blocked endlessly (using WaitForSingleObject on a dummy handle with a timeout value of INFINITE).

So you could be something like:

 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);

Then I applied the debugger after the error showed up (the gui program stopped responding).

Then you can take the dump and work with it later:

.dump / ma path_to_dump_file

Or debug it right now. The easiest way is to keep track of where the processor context was saved by the runtime exception handling mechanism:

sd esp range 1003f

The team will look for the address space of the stack for CONTEXT records (s) for the duration of the search. Usually I use something like 'l? 10000 ' . Please note: do not use non-standard large numbers as the entry that you usually find next to the raw exception filter frame. 1003f is a combination of flags (I believe that it matches CONTEXT_FULL) used to capture processor state. Your search will look something like this:

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

Once you get the results back, use the address in the cxr command:

.cxr 0012c160

This will lead you to this new CONTEXT, exactly at the time of the crash (you will get exactly the stack trace during the crash of the application). Also use:

.exr -1

to find out exactly what exception occurred.

Hope this helps.

+2
Oct 09 '08 at 8:25
source share

Regarding problems with obtaining diagnostic information, have you tried using adplus.vbs as an alternative to WinDbg.exe? To connect to the running process, use

 adplus.vbs -crash -p <process_id> 

Or launch the application in case the accident occurs quickly:

 adplus.vbs -crash -sc your_app.exe 

Full details of adplus.vbs can be found at: http://support.microsoft.com/kb/286350

+1
09 Oct '08 at 7:38
source share

Ntdll.dll with attached debugger

The small difference between starting the program from the IDE or WinDbg, rather than starting it from the command line / desktop, is that when starting with a connected debugger (i.e. IDE or WinDbg) ntdll.dll uses a different heap implementation, which performs some small check on memory allocation / deallocation.

You can read some relevant information at an unexpected user interrupt point in the ntdll.dll file . One tool that can help you identify the problem is PageHeap.exe .

Crash analysis

You did not write what an β€œaccident” you are experiencing. Once the program crashes and prompts you to send error information to Microsoft, you will have to click on the technical information and at least check the exception code, and with some effort you can even perform a post-mortem analysis (see Heisenbug: WinApi program crash on some computers) for instructions)

+1
09 Oct '08 at 9:39
source share

Vista SP1 really has a really beautiful crash dump generator built into the system. Unfortunately, it is not enabled by default!

See article: http://msdn.microsoft.com/en-us/library/bb787181(VS.85).aspx

The advantage of this approach is that additional software should not be installed on the affected system. Take it and tear it up baby!

+1
Aug 19 '09 at 16:16
source share

Sometimes this happens because you wrapped up an important operation inside the "assert" macro. As you know, "assert" evaluates expressions only in debug mode.

+1
May 28 '14 at 9:28
source share

As my experience, this is most of all a memory corruption issue.

For example:

 char a[8]; memset(&a[0], 0, 16); : /*use array a doing some thing */ 

in debug mode, when you execute the code, it is quite possible to be normal.

But in the release it may / may be a failure.

For me, to rummage where memory is not connected is too tiring.

Use some tools like Visual Leak Detector (windows) or valgrind (linux) - a wiser choice.

+1
Mar 28 '15 at 20:15
source share

Something similar happened to me once with the GCC. This turned out to be too aggressive optimization, which was included only when creating the final version, and not during development.

Well, to be honest, it was my fault, not gcc, because I did not notice that my code relied on the fact that this particular optimization would not be done.

It took me a long time to trace it, and I only came to him because I asked in the news group and someone made me think. So, let me regain favor only in case this happens to you.

0
Oct 09 '08 at 7:26
source share

I found this article useful for your scenario. ISTR compiler options were a bit outdated. Check out your Visual Studio project options to learn how to create pdb files for your release build, etc.

0
09 Oct '08 at 7:34
source share

It is suspicious that this will happen outside the debugger, and not inside; working in the debugger usually does not change the behavior of the application. I would check the differences in the environment between the console and the IDE. Also, obviously, compile the release without optimization and with debugging information and see if this affects the behavior. Finally, check out the post-mortem debugging tools suggested by other people, usually you can get some sort of hint from them.

0
09 Oct '08 at 7:46
source share

Debugging release versions can be a pain because of the optimization that changes the order in which the lines of your code look executable. This can really be confusing!

One way to at least reduce the problem is to use MessageBox () to display quick instructions indicating in which part of the program your code is ("Run Foo ()", "Run Foo2 ()"); start placing them at the top of the functions in the area of ​​your code that you suspect (what did you do when it crashed?). When you can determine which function, change the message fields to blocks of code or even single lines inside this function, until you reduce it to a few lines. Then you can start printing out the value of the variables to see what state they are in at the time of the failure.

0
Oct 09 '08 at 8:24
source share

Try using _CrtCheckMemory () to find out what state the allocated memory is in. If everything goes well, _CrtCheckMemory returns TRUE , else FALSE .

0
Oct 09 '08 at 10:14
source share

You can run your software with global flags enabled (see "Debugging Tools for Windows"). This very often will help fix the problem.

0
09 Oct '08 at 11:48
source share

Make your program a generated mini-dump when an exception occurs, then open it in the debugger (for example, in WinDbg). Main Functions: MiniDumpWriteDump, SetUnhandledExceptionFilter

0
Dec 10 '08 at 14:33
source share

A great way to debug such an error is to enable optimization for your debug build.

0
Feb 06 '17 at 19:07
source share

I had this mistake and crashed even when I tried! my project. So I deleted the obj files manually from the Release directory, and after that it built just fine.

-2
Oct 09 '14 at 11:12
source share

I agree with Rolf. Since reproducibility is so important, you should not have a mode without debugging. All your builds must be debugable. Having two goals for debugging more than doubles your debugging load. Just send the version "debug mode" if it is not used. In this case, make it possible.

-6
Oct 9 '08 at 7:52
source share



All Articles