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
into local_var
- in debug: thread one overwrites
shared_var
- now thread 1 copies the new value of
shared_var
into local_Var
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.