gcc 未检测到内联函数的数组越界

问题描述 投票:0回答:2
extern void myprint(unsigned char *);

static inline void
myfunc(unsigned char *buf)
{
    for (unsigned int i = 0; i < 20; i++) {
        buf[i] = i;
    }
}

int
main(void)
{
    unsigned char buf[10];
    myfunc(buf);
    myprint(buf);

    return 0;
}
$ gcc.exe -O2 -pedantic -Wextra -Wall -Wstringop-overflow -Wuninitialized -Wunused -Warray-bounds=2 -Wformat-overflow -Wstringop-overread -g  -c C:\temp\cb\main.c -o build\mingw\obj\main.o
$ gcc.exe  -o build\mingw\test.exe build\mingw\obj\main.o build\mingw\obj\mod.o  -O2
$ gcc --version
gcc (i686-posix-sjlj-rev1, Built by MinGW-W64 project) 11.2.0
Copyright (C) 2021 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

如果内联函数直接写在 main() 中,gcc 会发出数组越界警告,但为什么它不能用静态内联函数检测到相同的警告?

我不太了解输出汇编器,但在我看来,生成的循环确实是20次,所以在执行过程中,溢出是真实的。

c gcc gcc-warning
2个回答
2
投票

inline
只是对编译器的(大部分已过时)建议,它不会 enforce 内联。碰巧的是,您确实会在
-O3
下收到警告,但在
-O2
下却没有收到警告。一些注意事项:

  • -O2
    /
    -O3
    选项确实会内联该函数(在 x86_64 gcc 13.3 上),但方式不同,并且
    -O3
    的一种方式恰好是呈现诊断消息的方式。
  • 在这种情况下,存在/不存在
    inline
    关键字不会改变生成的程序集,也不会改变内联的决定。
  • __attribute__((always_inline))
    对于您是否收到警告也没有影响。

这里的最佳实践是不要依赖 gcc 发出此警告 - C 中的越界访问错误很少伴随着编译器警告。相反,您可以以类型安全的方式设计该函数:

static inline void myfunc(unsigned char buf[20])

static inline void myfunc(size_t size, unsigned char buf[size])

或者如果采取极端(非常安全但麻烦的API):

static inline void myfunc(unsigned char (*buf)[20])

0
投票

如果您使用选项

-fsanitize=address
编译程序,您将在运行时进行数组边界检查。然而,Windows 上的 gcc 不支持此选项,但 clang 支持。有关安装说明,请参阅此答案:How to install MSYS2 clang with address and UB sanitizers

© www.soinside.com 2019 - 2024. All rights reserved.