GCC Undefined Behavior Sanitizer 似乎认为 inf/inf 不是未定义的行为。为什么?

GCC Undefined Behavior Sanitizer seems to think inf/inf is not undefined behavior. Why?

我认为 inf/inf 被认为是未定义的,如下例所示:

#include <math.h>
#include <stdio.h>
double square(double x){return x*x;}

int main(){
  double x = 2.9e200;
  printf ("x*x=%g\n", square(x)/square(x));
  return 0;
}

但是,未定义行为消毒程序不会将此视为未定义行为。我哪里理解错了?

 % gcc -fsanitize=undefined hello.c && ./a.out
x*x=nan

I thought inf/inf is considered undefined

您正在使用 gcc 很可能是在一个健全的平台上 - 您的编译器遵循 IEEE 754 the de-facto-standard floating point number format (also see C11 Annex F). From this pdf of that standard 我们可以在第 37 页阅读:

7.2 Invalid operation

For operations producing results in floating-point format, the default result of an operation that signals the invalid operation exception shall be a quiet NaN that should provide some diagnostic information (see 6.2). These operations are:

[....]

e) division: division(0, 0) or division(∞, ∞)

行为是 定义的 - 它应该是安静的 NaN

-fsanitize=undefined不检查这种情况,我想documentation lists检测到什么。

当标准的一部分将某些东西描述为未定义行为时,这意味着就标准而言,实现通常可以自由定义或不定义它们认为合适的行为,大概选择最适合的行动方案他们的客户。然而,在浮点数学的情况下,该标准增加了一个额外的要求:所有未能按照定义处理某些浮点运算的实现必须避免预定义宏 __STDC_IEC_559__。如果一个实现预定义了那个宏,那么它必须将不需要在没有预定义那个宏的实现上定义的各种操作视为已定义。

可以说,未定义行为清理器应该检查一段代码是否只会在定义 __STDC_IEC_559__ 的实现上执行,并且只有在上述浮点运算不会发生时才将其视为已定义在未定义该宏的实现上。然而,唯一可行的方法是构建程序两次——一次定义了宏,一次没有定义——并分别验证两个机器代码程序的行为。