简体   繁体   中英

Does a memory barrier tame Microsoft's optimizer?

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?

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.

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?

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM