【问题标题】:C code with undefined results, compiler generates invalid code (with -O3)未定义结果的 C 代码,编译器生成无效代码(使用 -O3)
【发布时间】:2014-12-06 04:57:18
【问题描述】:

我知道当你在 C 程序中做某些事情时,结果是不确定的。但是,编译器不应该生成 invalid(机器)代码,对吧?如果代码做错了,或者代码产生了段错误或其他什么,这将是合理的......

这应该根据编译器规范发生,还是编译器中的错误?

这是我正在使用的(简单)程序:

int main() {
    char *ptr = 0;
    *(ptr) = 0;
}

我正在使用-O3 进行编译。但这不应该产生无效的硬件指令,对吧?使用-O0,我在运行代码时会遇到段错误。这似乎更加理智。

编辑:它正在生成ud2 指令...

【问题讨论】:

  • UB 意味着所有的赌注都结束了,理智早就被抛弃了,没有理由抱怨了!
  • 在编译器知道存在未定义行为的情况下,生成一条只会让你的应用程序崩溃的指令绝对没问题,并且可以说是最安全的做法。跨度>
  • 它没有生成无效指令。它正在生成一条有效指令,其作用是触发无效的操作码异常。这会给您带来什么问题吗?
  • 正如我在回答中所说,这是有效的指令,编译器在某些方面很有帮助,因为如果一个严重的问题长时间被忽视可能会更糟。

标签: c gcc undefined-behavior


【解决方案1】:

ud2 指令是一个“有效指令”,它代表未定义指令,并产生一个无效操作码异常clang显然gcc 可以在程序调用未定义的行为时生成此代码。

从上面的clang链接解释如下:

存储为 null 并通过空指针调用被转换为 __builtin_trap() 调用(在 x86 上变成类似“ud2”的陷阱指令)。这些总是在优化代码中发生(如 其他转换的结果,如内联和常量 传播),我们过去只删除包含它们的块 因为它们“显然无法访问”。

虽然(从迂腐的语言律师的角度来看)这是严格的 确实,我们很快了解到人们偶尔会取消引用 null 指针,并让代码执行落入顶部 next 函数使问题很难理解。从 表演角度,暴露这些最重要的方面是 压缩下游代码。正因为如此,clang 把这些变成了 运行时陷阱:如果实际动态达到其中之一,则 程序立即停止,可以调试。这样做的缺点 这是因为我们通过这些操作稍微膨胀了代码 具有控制其谓词的条件。

在一天结束时,一旦您调用未定义的行为,您的程序的行为将是不可预测的。这里的理念是,与生成看似正常但实际上已损坏的程序相比,可能更好地使严重崩溃并给开发人员一个严重错误的指示并允许他们从正确的点进行调试。

正如 Ruslan 所说,它是“有效的”,因为它保证引发一个无效的操作码异常,而不是其他可能在未来变得有效的未使用序列。

【讨论】:

  • 好吧,ud2dw 0xffff 一样有效。使其“有效”的唯一原因是它保证始终无效,而其他无效字节序列可以被认为是保留的,并且可能在未来的 CPU 实现中变得有效。
猜你喜欢
  • 2023-03-18
  • 2017-06-06
  • 2011-11-08
  • 1970-01-01
  • 1970-01-01
  • 2011-02-19
  • 1970-01-01
  • 1970-01-01
  • 2019-04-04
相关资源
最近更新 更多