error: dereferencing pointer ‘dst.6’ does break strict-aliasing rules
qgymib opened this issue · 5 comments
qgymib commented
测试用例编译过程中出现告警:
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)
heiher commented
是需要开启什么特殊的编译选项吗?较新的GCC或CLANG没有这种错误或警告。
不安全的原因大概是怎样的?
qgymib commented
不需要开启,老版本的GCC会有此告警,新版本的GCC更加智能,对这种场景有处理。
产生此告警的原因在于:
- 依照C标准,如果两个类型不兼容的指针指向同一个对象,那么程序的行为是未定义的
- void*类型本身不完整,与任何其他类型均不兼容。
要消除此告警有两种方式:
- 使用memcpy
- 将赋值过程拆成三步
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)
heiher commented
OK,那没什么问题,对于字长以内的数据不使用memcpy也是为了性能考虑,原本只需要两个访存指令要变成函数调用(如果没有对memcpy内联优化的话)。
qgymib commented
测试通过(๑→ܫ←)