heiher/hev-task-system

error: dereferencing pointer ‘dst.6’ does break strict-aliasing rules

qgymib opened this issue · 5 comments

测试用例编译过程中出现告警:

src/lib/utils/hev-compiler.h:41: error: dereferencing pointer ‘dst.6’ does break strict-aliasing rules

GCC版本:4.4.7

此告警的原因在于进行小内存拷贝时,使用了强制类型转换:

static inline void
__copy_once_size (void *dst, const volatile void *src, int size)
{
    switch (size) {
    case sizeof (char):
        *(char *)dst = *(volatile char *)src;
        break;
    case sizeof (short):
        *(short *)dst = *(volatile short *)src;
        break;
    case sizeof (int):
        *(int *)dst = *(volatile int *)src;
        break;
    case sizeof (long long):
        *(long long *)dst = *(volatile long long *)src;
        break;
    default:
        barrier ();
        __builtin_memcpy ((void *)dst, (const void *)src, size);
        barrier ();
    }
}

依照manual的建议,这种拷贝方式并不安全。使用原生memcpy操作则是安全可靠的。

#define __copy_once_size(dst, src, size) memcpy(dst, src, size)

是需要开启什么特殊的编译选项吗?较新的GCC或CLANG没有这种错误或警告。

不安全的原因大概是怎样的?

不需要开启,老版本的GCC会有此告警,新版本的GCC更加智能,对这种场景有处理。

产生此告警的原因在于:

  1. 依照C标准,如果两个类型不兼容的指针指向同一个对象,那么程序的行为是未定义的
  2. void*类型本身不完整,与任何其他类型均不兼容。

要消除此告警有两种方式:

  1. 使用memcpy
  2. 将赋值过程拆成三步
long long* tmp_dst = dst;
volatile long long * tmp_src = src;
*tmp_dst = *tmp_src;

之所以新版本的GCC或Clang不会产生此告警,是因为对strict-aliasing的场景有所识别,当出现类似的场景时,会自动优化为合适的代码。

然而在很多生产环境中,由于GCC的版本较老,因此对于跨平台的代码,可以选择使用memcpy方式,或声明编译器的支持版本(例如require gcc >= 4.8)

参考链接

OK,那没什么问题,对于字长以内的数据不使用memcpy也是为了性能考虑,原本只需要两个访存指令要变成函数调用(如果没有对memcpy内联优化的话)。

Fixed: 5d1dbde

测试通过(๑→ܫ←)