2

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?

Community
  • 1
  • 1
jww
  • 97,681
  • 90
  • 411
  • 885
  • 1
    As an alternative solution, if you want to set `m_p` to zero with no concern about it being optimized away, you can use `SecureZeroMemory()` when Windows is the target. For other targets you can perhaps call some other API or an assembly function? – Michael Burr Aug 02 '15 at 04:19
  • @Michael - yes, agreed. If I could re-use the memory barrier code, then it tidies things up nicely by hiding the implementation specific details behaind the macro (and without the need for more macros and the `_Pragma`, and all the conditionals that accompany it). – jww Aug 02 '15 at 05:27

2 Answers2

2

Under GCC compiler you can turn off optimization for selected functions manually with compiler directives like in the example below.

#pragma GCC push_options
#pragma GCC optimize ("O0")
static inline void MEMORY_BARRIER() {
    // your code
}
#pragma GCC pop_options

Under VC compiler you can turn off optimization for selected functions manually with compiler directives like in the example below.

#pragma optimize( "", off )
static inline void MEMORY_BARRIER() {
    // your code
}
#pragma optimize( "", on ) 

Maybe you can use this tricks to get what you want?

Unfortunately I do not now how to do similar trick under clang/llvm or Intel Compiler.

Krystian Sakowski
  • 1,613
  • 14
  • 20
  • Yeah, I moved away from that exact code (but I forgot to tell you why...). Visual Studio lets you control optimizations for Professional and Enterprise editions, and not the Learning and Community editions (IIRC). – jww Aug 03 '15 at 16:05
0

ffmpeg (written in C, not C++) addresses this problem by having a wrapper for free, which zeroes the pointer.

In new code they prefer av_free(&ptr) over av_free(ptr).

If there is a use-after-free condition, the compiler won't be able to prove it's a dead store and eliminate it, I guess. This might not work in C++, if the compiler is allowed to assume that writes to member variables in a destructor are dead stores.

I know it wouldn't prove anything, but have you seen cases where the compiler optimizes away these pointer-zeroing stores?

Peter Cordes
  • 328,167
  • 45
  • 605
  • 847
  • 1
    *"... have you seen cases where the compiler optimizes away these pointer-zeroing stores?"* - yes. – jww Aug 03 '15 at 02:16
  • Does it still happen if you on-purpose include a use-after free? Maybe by having a member function return the address of a member variable to code that saves it. Or even just having the member variable public. – Peter Cordes Aug 03 '15 at 02:28