【问题标题】:Does a memory barrier tame Microsoft's optimizer?内存屏障能驯服微软的优化器吗?
【发布时间】:2015-08-01 21:32:01
【问题描述】:

我正在开发一个多平台、多编译器库。该库具有以下宏:

#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

在 GCC 下,上面的代码可以用来驯服优化器。 尽管该函数称为MEMORY_BARRIER,但重要的部分是标记为volatile 的内联汇编。这就是在 GCC、Clang 和 Intel 下驯服优化器的部分。

编辑:内联程序集不会驯服 Clang 上的优化器,即使 Clang 通过定义 __GNUC__ 声称是 GCC。见LLVM Bug 15495 - dead store pass ignores memory clobbering asm statement

宏的使用是一个handle 类。 handle 提供了一个级别和间接性,我们正在尝试诱导一个 NULL 指针取消引用以帮助定位错误(一些手放弃)。为了实现我们的目标,我们需要确保优化器不会删除死存储(m_p = NULL;):

template <class T> handle<T>::~handle()
{
    delete m_p;
    m_p = NULL;

    MEMORY_BARRIER();
}

我不想使用 volatile 演员表,因为 (1) 我不相信它对限定符的正确使用(取自与 Clang 和 GCC 开发人员的交互),并且 (2) 它看起来volatile cast 是 C++ 中未定义的行为(参见 Approved way to avoid lvalue cast warnings and errors?)。

内存屏障是否会驯服 Microsoft 平台上的优化器?

【问题讨论】:

  • 作为替代解决方案,如果您想将m_p 设置为零而不担心它会被优化掉,您可以在Windows 为目标时使用SecureZeroMemory()。对于其他目标,您也许可以调用其他 API 或汇编函数?
  • @Michael - 是的,同意。如果我可以重新使用内存屏障代码,那么它可以通过将实现特定的细节隐藏在宏后面(并且不需要更多的宏和_Pragma,以及伴随它的所有条件)来很好地整理事情。

标签: c++ visual-studio optimization memory-management cl.exe


【解决方案1】:

在 GCC 编译器下,您可以使用编译器指令手动关闭所选函数的优化,如下例所示。

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

在 VC 编译器下,您可以使用编译器指令手动关闭所选函数的优化,如下例所示。

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

也许你可以使用这些技巧来得到你想要的?

不幸的是,我现在不知道如何在 clang/llvm 或 Intel 编译器下做类似的技巧。

【讨论】:

  • 是的,我离开了那个确切的代码(但我忘了告诉你为什么......)。 Visual Studio 允许您控制专业版和企业版的优化,而不是学习和社区版 (IIRC)。
【解决方案2】:

ffmpeg(用 C,而不是 C++ 编写)通过 a wrapper for free, which zeroes the pointer 解决了这个问题。

在新代码中,他们更喜欢 av_free(&amp;ptr) 而不是 av_free(ptr)

如果存在 use-after-free 条件,我猜编译器将无法证明它是一个死存储并消除它。如果允许编译器假定对析构函数中的成员变量的写入是死存储,这在 C++ 中可能不起作用。

我知道这并不能证明任何事情,但是您是否见过编译器优化掉这些指针归零存储的情况?

【讨论】:

  • "...你见过编译器优化掉这些指针归零存储的情况吗?" - 是的。
  • 如果您故意包含免费使用后是否仍然会发生这种情况?也许通过让成员函数将成员变量的地址返回给保存它的代码。甚至只是将成员变量设为 public。
猜你喜欢
  • 2016-11-10
  • 2015-07-08
  • 2017-01-05
  • 1970-01-01
  • 2011-09-28
  • 2018-10-02
  • 1970-01-01
  • 2014-02-04
  • 1970-01-01
相关资源
最近更新 更多