【发布时间】:2017-12-03 15:31:51
【问题描述】:
这个问题不是关于未对齐数据访问的定义,而是为什么memcpy 会沉默 UBsan 的发现而类型转换却不会,尽管生成了相同的汇编代码。
我有一些示例代码来解析一个协议,该协议发送一个字节数组,分成六字节组。
void f(u8 *ba) {
// I know this array's length is a multiple of 6
u8 *p = ba;
u32 a = *(u32 *)p;
printf("a = %d\n", a);
p += 4;
u16 b = *(u16 *)p;
printf("b = %d\n", b);
p += 2;
a = *(u32 *)p;
printf("a = %d\n", a);
p += 4;
b = *(u16 *)p;
printf("b = %d\n", b);
}
在将指针增加 6 并进行另一次 32 位读取后,UBSan 报告有关未对齐负载的错误。我使用memcpy 而不是类型双关语来抑制此错误,但我不太了解原因。需要明确的是,这里是没有 UBSan 错误的相同例程,
void f(u8 *ba) {
// I know this array's length is a multiple of 6 (
u8 *p = ba;
u32 a;
memcpy(&a, p, 4);
printf("a = %d\n", a);
p += 4;
memcpy(&b, p, 2);
printf("b = %d\n", b);
p += 2;
memcpy(&a, p, 4);
printf("a = %d\n", a);
p += 4;
memcpy(&b, p, 2);
printf("b = %d\n", b);
}
两个例程都编译为相同的汇编代码(使用movl 进行32 位读取,使用movzwl 进行16 位读取),那么为什么一个未定义行为是另一个未定义行为? memcpy 是否有一些特殊的属性可以保证某些东西?
我不想在这里使用memcpy,因为我不能依赖编译器在优化它方面做得足够好。
【问题讨论】:
-
memcpy是正确的,并且强制取消引用版本是未定义的行为。 UB 表示任何事情都可能发生,包括生成与正确代码相同的程序集 -
...我不确定您的第二个代码 sn-p 是否会编译,因为在使用之前未声明
b。
标签: c clang undefined-behavior memcpy ubsan