C++ Can Undefined Behavior cause Debug and Release Builds to behave differently?
-
13-07-2021 - |
Question
This question has many great answers explaining why a bug might only manifest itself in a Release build.
Common reasons for bugs in release version not present in debug mode
I have a more specific question regarding undefined behavior.
If a program always appears to work correctly in a Debug build, but behaves differently in a release build (always behaves in the same incorrect way, however), can the problem be due to undefined behavior?
Solution
Can be due to undefined behavior? Sure. Is it always because of undefined behavior? Certainly not.
Imagine this:
assert(scanf("%d", &n) == 1);
This line will simply get removed in release mode. It is not undefined behavior, but it most certainly will make your program behave in a different way.
assert
may be the obvious example here, but think of this more complicated situation:
#ifndef NDEBUG
# define DBG(fmt, ...) fprintf(stderr, fmt, ##__VA_ARGS__)
#else
# define DBG(fmt, ...) ((void)0)
#endif
int shared_var;
static inline void do_something_fast(void)
{
DBG("doing something fast\n");
shared_var = something_fast();
}
and have thread 1:
...
mutex_unlock();
local_var = shared_var;
...
and thread 2:
...
mutex_lock();
do_something_fast();
...
Now this example is totally absurd, but something along these lines are quite common in multi-threaded environments. In this example, this is what happens:
- thread 1: calls mutex_unlock, waking up thread 2 and going to sleep
- thread 2: calls do_something_fast()
- in release: fprintf is called, causing thread 2 to sleep
- now thread 1 copies the old value of
shared_var
intolocal_var
- now thread 1 copies the old value of
- in debug: thread one overwrites
shared_var
- now thread 1 copies the new value of
shared_var
intolocal_Var
- now thread 1 copies the new value of
- in release: fprintf is called, causing thread 2 to sleep
As you can see, in this example blocking I/O forced a certain behavior between threads, which was itself enabled only in debug mode. This also means that a program working in debug may behave differently than when compiled for release.