为什么这不会在C语言中生成越界访问?

时间:2019-09-01 19:17:19

标签: c gcc enums c99

玩一些C代码在C99和Rust之间做一些比较,我写了以下内容,

typedef enum {
    NICKLE, DIME, QUARTER, DOLLAR,
} Denom;

static const int cents[] = {
    [NICKLE] = 5,
    [DIME] = 10,
    [QUARTER] = 25,
    [DOLLAR] = 100,
};

int main () {
    printf( "Result %d\n", cents[DIME] );
}

这可以按预期运行,现在我想显示访问权限以及访问权限

typedef enum {
    NICKLE, DIME, QUARTER, DOLLAR, ZOD = 20394
} Denom;

我期待着

printf( "Result %d\n", cents[ZOD] );

显示访问权限为cents + ZOD。但事实并非如此。

 mov eax, 0
 mov esi, eax
 lea rdi, str.Result__d        ; 0x5570bf1ed020 ; "Result %d\n"
 mov eax, 0
 call sym.imp.printf           ; int printf(const char *format)

为什么将esi设置为0,为什么打印

Result 0

-Wall -Wextra -Wpedantic也没有错误。 GCC是否提供管理此行为的标志?它是否知道这超出范围?如果是,它是否也不会发出警告(或可以发出警告)?

3 个答案:

答案 0 :(得分:1)

是的,GCC可以在特定情况下对此发出警告(请参阅@Acorn的答案)。

有一个运行时未定义行为检查器-fsanitize=undefined,如果您执行某些类型的未定义行为(例如,访问过去的数组边界),则会出现错误。

由于这是未定义的行为,因此编译器可以自由执行任何所需的操作。这意味着它可以将esi设置为零,密码的十六进制表示或其他任何形式。

答案 1 :(得分:1)

要补充@ JL2210的答案,请注意,其他编译器也会根据问题中给出的源发出警告。

例如Clang:

<source>:15:28: warning: array index 20394 is past the end of the array (which contains 4 elements) [-Warray-bounds]
    printf( "Result %d\n", cents[ZOD] );
                           ^     ~~~
<source>:7:1: note: array 'cents' declared here
static const int cents[] = {
^

以及icc:

<source>(15): warning #175: subscript out of range
      printf( "Result %d\n", cents[ZOD] );

对于GCC,您拥有-Warray-bounds的{​​{1}}。特别是,您需要-Wall -O2(这种优化方法可以删除不需要的不必要的范围检查,例如数组绑定检查)。

但是,由于某些原因,GCC仅针对非-ftree-vrpconst数组给出警告。如果您尝试:

static

您会看到它的警告:

#include <stdio.h>

typedef enum {
    NICKLE, DIME, QUARTER, DOLLAR, ZOD = 20394
} Denom;

int cents[] = {
    [NICKLE] = 5,
    [DIME] = 10,
    [QUARTER] = 25,
    [DOLLAR] = 100,
};

int main () {
    printf( "Result %d\n", cents[ZOD] );
}

我至少可以从GCC 4.4.7开始看到警告!

答案 2 :(得分:0)

C语言定义不要求对数组访问进行任何类型的边界检查-编译器或运行时环境都不需要以任何方式处理越界访问。行为是 undefined

如果在翻译过程中可以检测到越界访问,并且随着时间的推移,越来越多的人这样做(如其他发布者所说,gcc和clang可以,但不是),则单个编译器可以发出诊断信息默认情况下)。

如果直到运行时都无法检测到它-好的,C没有任何结构化的异常处理机制,因此即使运行时环境发出信号,也没有好的方法来处理该问题。