使用Clang而不是GCC构建(可疑)示例时内存损坏

时间:2016-04-20 14:11:53

标签: c++ macos c++11 gcc boost

我有一些C代码几年前被迅速“转换”为C ++代码,我现在维护它。我在不同的操作系统上运行它并使用不同的编译器进行构建时发现了一些特殊的行为,并且可以使用一些帮助来诊断我最近解决的一些问题。

代码在以下系统上运行时没有问题:

  • Ubuntu 14.04.2 LTS x64
  • GCC 4.8.4

将其移植到以下系统之后,事情就发生了变化:

  • OSX“El Capitan”
  • Apple LLVM版本7.3.0(clang-703.0.29)

违规代码围绕以下结构:

struct blk_data {
    int i;
    int s;
    boost::mutex protectionMutex;
};

有一段代码,其中通过malloc()创建了此POD的动态实例(普通旧数据,没有自定义方法或构造函数等):

struct blk_data* pData = (blk_data*)malloc(16 * sizeof(struct blk_data));
if ( pData )
//...

请忽略我投出malloc()结果的事实。如果不这样做,编译器会标记错误。

稍后在代码中,我打电话给:

boost::unique_lock<boost::mutex> tempLock(pData->protectionMutex);

对于使用GCC的Linux,没有问题。对于OSX和Clang,程序出错,注意到最终传递给pthread_mutex_lock()的互斥锁地址无效。最终,我能够通过以下方式解决这个问题:

  • 使用new代替malloc()
  • 设置${CXXFLAGS} += -std=c++11

弹出类似问题的第二种情况是使用new的一大块代码,然后是memset结构。据我所知,如果使用POD struct,这是安全的。

为什么这个代码在GCC / Linux上构建并运行良好,但它构建,但不运行;在Clang / OSX上?如果struct包含RAII样式的成员,或者我是否一直违反了部分C ++标准(即:未定义的行为),那么struct是否不再计为POD read()?或者这是对Clang vs GCC进行更严格检查的情况。

谢谢。

2 个答案:

答案 0 :(得分:3)

来自malloc的文档:

  

分配未初始化存储空间的大小字节

在初始化之前使用内存因此是未定义的行为。

由于运气 glibc的实现细节,它在GCC中工作,特别是glibc的malloc遵循调用nmap从系统分配新内存的事实。默认情况下,nmap会将内存清零,以防止信息从一个进程泄漏到另一个进程。

此处的文档: http://man7.org/linux/man-pages/man2/mmap.2.html

OSX的malloc是不同的(尽管文档没有说明是否初始化了新内存): https://developer.apple.com/library/mac/documentation/Darwin/Reference/ManPages/man3/malloc.3.html

答案 1 :(得分:3)

虽然我不确定boost::mutex是否为POD,malloc仅分配内存但不初始化对象,这使得protectionMutex未初始化。

虽然new确保调用boost::mutex的默认ctor,因此protectionMutex已初始化。

[更新]检查boost mutex的header file,它在内部使用指针:

#if defined(BOOST_HAS_WINTHREADS)
    typedef void* cv_state;
#elif defined(BOOST_HAS_PTHREADS)
    struct cv_state
    {
        pthread_mutex_t* pmutex;
    };
#elif defined(BOOST_HAS_MPTASKS)
    struct cv_state
    {
    };
#endif

所以malloc肯定不会初始化指针,而new会这样做。

但我真的不知道为什么海湾合作委员会有效......