What are some reasons why the Release build will work differently than the Debug build

I have a Visual Studio 2005 C ++ program that works in Release mode differently than in Debug mode. In release mode, an (seemingly) intermittent accident occurs. In debug mode, it does not crash. What are some reasons why the Release build will work differently than the Debug build?

It is also worth mentioning that my program is quite complicated and uses several third-party libraries for processing XML, brokerage messages, etc.

Thanks in advance!

+54
c ++ visual-studio visual-studio-2005
Nov 23 '08 at 9:03
source share
11 answers

Survive version versions gives a good overview.

Things I encountered - most of them have already been mentioned

Variable initialization is by far the most common. In Visual Studio, debugging assemblies explicitly initialize allocated memory for given values, see, for example, Memory Values here. These values, as a rule, are easy to detect, cause an error outside the boundaries when used as an index, or access violation when used as a pointer. However, an uninitialized logical value is true and can cause uninitialized memory errors that have not been detected for many years.

In a release where memory is not initialized explicitly, it simply stores the contents that were previously. This leads to “ridiculous values” and “random” crashes, but often to deterministic crashes that require an explicitly unrelated command to be executed before the command that actually crashes. This is caused by the first command “setting” a memory location with specific values, and when the memory cells are recycled, the second command will see them as initialization. This is more common with uninitialized stack variables than heap, but the latter happened to me too.

The initial initialization of the source memory can also be different in the release build, regardless of whether you start with a visual studio (an attached debugger) and start with the explorer. This makes the "nicest" kind of build errors that never appear under the debugger.

Real optimization is the second place in my experience. The C ++ standard allows for many optimizations, which may be unexpected, but quite fair, for example. when two pointers have the same location in memory, the initialization order is not considered or several threads change the same memory cells, and you expect a certain order in which stream B sees the changes made by stream A. Often the compiler is blamed for these. Not so fast, young yedi! - see below

Timing Graduation builds are not just “faster” for various reasons (optimization, logging functions that provide a stream synchronization point, debugging code such as statements are not executed, etc.), as well as the relative time between operations changes dramatically. The most common problem that is found in this case is the race conditions, as well as deadlocks and the simple "different order" of the message / timer / event code execution. Despite the fact that these are problems with synchronization, they can be surprisingly stable between assemblies and platforms with reproductions that "always work, except for PC 23".

Protection byte Debug builds often put (more) protective bytes around selected instances and distributions to protect against index overflows and sometimes overflows. In rare cases, when the code uses offsets or sizes, for example. serializing untreated structures, they are different.

Other Code Differences Some instructions — for example, state — do not evaluate anything in release builds. Sometimes they have different side effects. This is common with macro trickery, as in classic (warning: few errors)

#ifdef DEBUG #define Log(x) cout << #x << x << "\n"; #else #define Log(x) #endif if (foo) Log(x) if (bar) Run(); 

What's in the release build is rated as if (foo & bar) This type of error is very rare with regular C / C ++ code and macros that are correctly written.

Compiler Errors This never happens. Well, that’s true, but most of your career you prefer, believing that it’s not. In ten years of working with VC6, I found one where I am still convinced that this is an error of an uncommitted compiler, compared to dozens of templates (maybe even hundreds of copies) with insufficient understanding of the Scriptures (aka standard).

+126
Nov 23 '08 at 10:01
source share

The debug version often uses assertions and / or debug symbols. This can lead to different memory locations. In the case of a bad pointer, an overflow of an array or similar memory you get access in one case with critical bad memory (for example, a pointer to a function), and in the other case there can only be some non-critical memory (for example, only a document line is unloaded)

+6
Nov 23 '08 at 9:12
source share

Variables that are not explicitly initialized will or will not be zeroed out in the Release assembly.

+5
Nov 23 '08 at 9:07
source share

Build release (hopefully) will be faster than debug build. If you use more than one thread, you can see more striping, or just one thread is faster than the others that you might not have noticed in the debug assembly.

+2
Nov 23 '08 at 9:15
source share

A release build is usually compiled with optimizations included in the compiler, while debug builds are usually missing.

In some languages ​​or when using many different libraries, this can lead to intermittent crashes - especially when the selected optimization level is very high.

I know this is the case with the gcc C ++ compiler, but I'm not sure about the Microsoft compiler.

+2
Nov 23 '08 at 9:17
source share

I had a similar problem not so long ago , which was ultimately caused by the fact that the stack is handled differently in release builds. Other things that may vary:

  • Memory allocation is handled differently using debugging compilations in the VS compiler (that is, writing 0xcc over cleared memory, etc.).
  • Loop deployment and other compiler optimizations
  • Pointer Selection
+2
Nov 23 '08 at 9:38
source share

This depends on both the compiler provider and the libraries that you compile with the DEBUG flags. Although DEBUG code should never affect the executable code (it should not have side effects), it sometimes does.

In particular, variables can only be initialized in DEBUG mode and left uninitialized in RELEASE mode. STL in Visual Studio compilers differs in DEBUG and RELEASE modes. The idea is that iterators are fully checked in DEBUG to detect possible errors (using invalid iterators, for example, an iterator in a vector is invalid if insertion occurs after receiving an iterator).

The same thing happens with third-party libraries, the first thing I can imagine is QT4, which will end your program with an assertion if a thread other than the one that created the graphic object performs drawing operations.

With all changes, your code and memory will differ in both modes. A pointer (reading a position passing through the end of the array) may not be detected if that position is readable.

The statements are intended to kill the application during DEBUG and disappear from the RELEASE assembly, so I will not think of the statements as your problem. My first suspect would be a rogue index or one-way access to it.

Some time ago there were problems with some compilers breaking code, but I have not read any complaints lately. There may be an optimization problem, but that will not be my first suspect.

+2
Nov 23 '08 at 9:47
source share

http://www.debuginfo.com/tips/userbpntdll.html

Due to the fact that security bytes are added to debug assemblies, you can "safely" access memory that is out of bounds for an array (especially dynamic arrays), but this will violate access to the release assembly. This error can go unnoticed, causing a damaged heap and, possibly, an access violation in a place unrelated to the original error.

Use PageHeap (or, if you have debugging tools installed, you can use gflags) to detect errors related to corrupted heaps.

http://support.microsoft.com/?id=286470

+1
May 11, '09 at 22:56
source share

In my experience, the most common reason is that configurations differ more than release / build settings. For example. different libraries are included, or the debug build has a different stack size than the release build.

To avoid this in our Visual Studio 2005 projects, we use property sheets extensively. Thus, release and debug configurations can have common settings.

0
May 09 '09 at 9:21 p.m.
source share

This post, along with the links provided, helps a lot in fixing the related error. Adding to the above list, differences in calling conventions can also lead to this behavior. This failed in the release builds, with only optimizations for me. i is declared as __stdcall and defined as __cdecl (by default). [strange this warning is not selected even at warning level 4 MSVC?]

0
May 17 '09 at 8:49
source share

Among the optimizations that can be performed in release mode (rather than debugging), copy resolution can produce different results. In particular, RVO (return value optimization), depending on how your constructors are designed.

What is copy and return value optimization?

0
Aug 23 '19 at 16:30
source share



All Articles