首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >如何在C程序中鼓励未定义的行为/无序执行?

如何在C程序中鼓励未定义的行为/无序执行?
EN

Stack Overflow用户
提问于 2019-03-17 14:56:42
回答 2查看 82关注 0票数 0

我正在阅读下面这篇关于C:https://www.geeksforgeeks.org/sequence-points-in-c-set-1/中序列点的文章

其中有几个未定义行为的示例,例如调用修改单个全局变量的两个函数的表达式,或者多次递增同一变量的单个表达式。

理论上,我理解这个概念。但是,无论我尝试运行多少次示例,行为都是相同的,并且从不“令人惊讶”。

为了获得对未定义行为的亲身体验,让示例变得“令人惊讶”的最简单方法是什么?

(如果重要的话,我使用的是MINGW64。)

EN

回答 2

Stack Overflow用户

发布于 2019-03-17 15:16:56

这是我能在短时间内想出的最好的方法:

源代码:

代码语言:javascript
复制
#include <stdio.h>

int undefined(int *a, short *b)
{
    *a = 1;
    b[0] = 0;
    b[1] = 0;
    return *a;
}

int main()
{
    int x;
    short *y = (short*) &x;
    int z = undefined(&x, y);
    printf("%d\n", z);
    return 0;
}

使用gcc 8.3 -O3生成的程序集

代码语言:javascript
复制
undefined(int*, short*):
    mov     DWORD PTR [rdi], 1
    mov     eax, 1
    mov     DWORD PTR [rsi], 0
    ret
.LC0:
    .string "%d\n"
main:
    sub     rsp, 8
    mov     esi, 1
    mov     edi, OFFSET FLAT:.LC0
    xor     eax, eax
    call    printf
    xor     eax, eax
    add     rsp, 8
    ret

将其付诸实践:https://godbolt.org/z/E0XDYt

特别是,它依赖于将int的地址转换为short*而导致的未定义行为,该操作违反了严格的别名规则,从而导致未定义的行为。

undefined()的组装开始。这假设由于ab是不同的类型,它们不能重叠,因此它将return *a;优化为mov eax,1,即使如果它从内存中获取值,它实际上将返回零。这是在关闭优化的情况下完成的,所以这是真正隐蔽的问题之一,只有在优化的发布版本中才会出现,而不是当您尝试使用非优化的调试版本对其进行调试时。

但是,请注意main()中的代码是如何尝试正确的:它内联,然后优化对undefined()的调用,当它在调用printf的上方执行xor eax,eax时,在z中假定是printf。所以它忽略了上面几行的返回值,而是使用了一个不同的值。

总而言之,这是一个非常糟糕的程序。这正是你在未定义的行为中所面临的风险。

票数 0
EN

Stack Overflow用户

发布于 2019-03-18 02:18:47

在测试gcc和clang时,一个有用的模式是使用下标访问数组,这些数组的值是有界的,但编译器不知道,并使用标准描述为等同于下标表示法的指针语法。用下面这样的东西测试gcc和当当:

代码语言:javascript
复制
struct S1 {int x;};
struct S2 {int x;};

union foo { struct S1 arr1[8]; struct S2 arr2[8]; } u;

uint32_t test1(int i, int j)
{
  if (sizeof u.arr1 != sizeof u.arr2)
    return -99;
  if (u.arr1[i].x)
    u.arr2[j].x = 2;
  return u.arr1[i].x;
}
uint32_t test2(int i, int j)
{
  if (sizeof u.arr1 != sizeof u.arr2)
    return -99;
  if ((u.arr1+i)->x)
    (u.arr2+j)->x = 2;
  return (u.arr1+i)->x;
}

将揭示,尽管标准将u.arr1[i].xu.arr2[j].x的行为分别定义为等同于(u.arr1+i)->x(u.arr2+j)->x,但在给予前者时,gcc和clang错失了允许的优化机会,而后者则被利用。这很可能是因为作者认识到,利用前一个机会是允许的,但不可否认的是,这将是如此愚蠢,以至于迫使人们认识到,该标准从未打算鼓励它允许的所有优化。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/55204581

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档