I'm working on a multi-platform, multi-compiler library. The library has the following macro:
#if defined(_MSC_VER) && (_MSC_VER >= 1400)
# pragma intrinsic(_ReadWriteBarrier)
# define MEMORY_BARRIER() _ReadWriteBarrier()
#elif ...
#elif defined(__GNUC__)
# define MEMORY_BARRIER() __asm__ __volatile__ ("" ::: "memory")
#else
# define MEMORY_BARRIER()
#endif
Under GCC, the code above can be used to tame the optimizer.
Though the function is called MEMORY_BARRIER
, the important part is the inline assembly marked volatile
. That's the part that tames the optimizer under GCC, Clang and Intel.
EDIT: The inline assembly does not tame the optimizer on Clang, even though Clang claims to be GCC by defining __GNUC__
. See LLVM Bug 15495 - dead store pass ignores memory clobbering asm statement.
The use of the macro is a handle
class. The handle
provides one level and indirection, and we are trying to induce a NULL pointer dereference to help locate bugs (some hand waiving). To achieve our goal, we need to ensure the optimizer does not remove the dead store (m_p = NULL;
):
template <class T> handle<T>::~handle()
{
delete m_p;
m_p = NULL;
MEMORY_BARRIER();
}
I don't want to use a volatile
cast because (1) I don't believe its the correct use of the qualifier (taken from interactions with the Clang and GCC devs), and (2) it appears the volatile
cast is undefined behavior in C++ (see Approved way to avoid lvalue cast warnings and errors?).
Does a memory barrier tame the optimizer on Microsoft platforms?