- c - 在位数组中找到第一个零
- linux - Unix 显示有关匹配两种模式之一的文件的信息
- 正则表达式替换多个文件
- linux - 隐藏来自 xtrace 的命令
这个问题不是关于未对齐数据访问的定义,而是为什么 memcpy
沉默了 UBsan 的发现,而类型转换却没有,尽管生成了相同的汇编代码。
我有一些示例代码来解析发送字节数组的协议(protocol),该字节数组被分成六个字节的组。
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
,因为我不能依赖编译器对其进行足够好的优化。
最佳答案
UB sanitizer 用于检测代码不严格符合,实际上取决于无法保证的未定义行为。
实际上,C 标准指出,只要您将指针指向地址未适当对齐的类型,行为就是未定义的。 C11 (draft, n1570) 6.3.2.3p7 :
A pointer to an object type may be converted to a pointer to a different object type. If the resulting pointer is not correctly aligned 68) for the referenced type, the behavior is undefined.
即
u8 *p = ba;
u32 *a = (u32 *)p; // undefined behaviour if misaligned. No dereference required
this 转换的存在允许编译器假定 ba
对齐到 4 字节边界(在 u32
是需要因此对齐,许多编译器将在 x86 上执行此操作),之后它可以生成假定对齐的代码。
即使在 x86 平台上,也有一些指令会失败: innocent-looking code可以编译成机器代码,在运行时导致中止。 UBSan 应该在代码中捕获这个代码,否则在您运行它时看起来很正常并且表现“如预期”,但如果使用另一组选项或不同的选项编译则会失败优化级别。
编译器可以为 memcpy
生成正确的代码 - 而且经常会,但这只是因为编译器会知道未对齐的访问将在目标平台上运行并表现良好。
最后:
I don't want to use
memcpy
here because I can't rely on compilers doing a good enough job optimising it.
你在这里说的是:“我希望我的代码仅在被垃圾编译器或产生缓慢代码的二十年前的编译器编译时可靠地工作。绝对不是在编译时与可以优化它以快速运行的那些。”
关于c - 加载未对齐的地址和 UBsan 发现,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47619944/
我想使用 UBSAN(未定义行为 sanitizer ),但发现它完全没有值(value),因为它会报告许多误报。 例如。一个简单的std::make_shared(42);足以触发警告,如 memb
当启用未定义的 sanitizer 时,我在 GNU 科学库 (GSL) 中发现了一个运行时错误: deque.c:58:11: runtime error: member access within
使用 clang 的 ubsan 运行来自 boost 版本 1.64 的 gzip.hpp 代码会给出以下消息: path/to/boost/1_64_0/include/boost/iostrea
我的大部分 -fsanitize=unsigned-integer-overflow 错误都是错误,但有时我会按预期明确使用它,这会导致 UBSan 产生误报。 有没有办法为特定表达式关闭 UBSan
这个问题不是关于未对齐数据访问的定义,而是为什么 memcpy 沉默了 UBsan 的发现,而类型转换却没有,尽管生成了相同的汇编代码。 我有一些示例代码来解析发送字节数组的协议(protocol),
我想用 -fsanitize=address,undefined 运行我的单元测试套件并将所有 sanitizer 错误写入 report.txt文件。默认情况下,所有 sanitizer 错误都会写
我在这里有一个小的单元测试,它具有未定义的行为。 源代码: #include TEST(test, test) { int k = 0x7fffffff; k += 1; // ca
最新版本的 GCC 和 Clang 具有未定义行为 sanitizer (UBSan),它是一个编译标志 (-fsanitize=undefined),可添加运行时检测代码。出现错误时,会显示如下警告
我正在尝试通过一个函数指针表调用一些 C++ 函数,该函数指针表作为 C 符号从共享对象中导出。该代码实际上可以正常工作,但 Clang 的未定义行为 sanitizer (= UBSan)认为我进行
简单代码片段: #define FOO 7 int bar = -875; bar <<= FOO; UBSAN 将此事报告为 UB。 我的理解是-875 << 7只是 -(875<<7)并且没有溢出
我试图理解我们最近在使用 Clang 5.0 和未定义行为 sanitizer (UBsan) 时解决的问题。我们有在向前或向后方向处理缓冲区的代码。简化的大小写是 similar to the co
拿下面的测试程序(用clang 3.4编译,在gdb 7.6.1下运行): #include #include int main(void) { int a = INT_MAX + 1;
以下代码用clang UBSAN编译会崩溃 #include #include #include #include template inline std::string floatToStr
我们使用以下代码来确定是否在编译时为 clang 和 gcc 指定了 -fsanitize=address。我们如何确定是否指定了 -fsanitize=undefined? bool isS
我正在尝试为我的 R 包复制 CRAN sanitizer 故障,该包依赖于 rocker/r-devel-ubsan-clang docker 镜像上的 Rcpp。 当我尝试安装 Rcpp 时,我收
我正在为这个问题挠头。如何重现 CRAN's gcc ubsan tests of my package的结果在家里,在 ubuntu 上? (准备步骤说明来自here) 1) 我安装更新所有需要的包
我已经使用 -fsanitize=undefined 选项编译了我的应用程序。我现在如何测试我的应用程序是否存在未定义的行为? 另外,我该如何进行牙山检查?我用 -fsanitize=address
我是一名优秀的程序员,十分优秀!