我有以下C代码,它在没有优化(-O 0)的情况下工作正常,但在使用-Os时会出现意外行为:
#include <stdint.h>
#include <stdio.h>
#include <stdbool.h>
#include <string.h>
static bool functionA(uint8_t* ptr1)
{
for (int i = 0; i < 16; i++)
{
ptr1[i] = i;
}
printf("functionA\n");
return true;
}
static bool functionB(uint8_t* ptr1)
{
bool retVal = false;
uint8_t ptr2[16] = {0};
if (functionA(ptr2))
{
retVal = true;
memcpy(ptr1, ptr2, 16);
}
return retVal;
}
int main(void)
{
const uint8_t* p = NULL;
const uint8_t BUF[] = {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16};
for (int i = 1; i <= 2; i++)
{
if (i == 1)
{
uint8_t buff32[32] = {0x5};
if (functionB(buff32))
{
p = buff32;
break;
}
continue;
}
else
{
p = BUF;
}
}
for(int i = 0; i < 16; i++)
{
printf("%x ", p[i]);
}
printf("\n");
return 0;
}
当使用“-O 0”编译代码时,我得到的结果是:
functionA
0 1 2 3 4 5 6 7 8 9 a b c d e f
但是,使用“-Os”或“-O3”(不是“-O2”):
functionA
16 24 97 6b fc 7f 0 0 8d f2 b7 c ed 55 0 0
我在godbolt上尝试了不同的编译器,如ARM GCC 10.3.1,我看到“functionB”中的memcpy代码没有编译。在main
的开头更改buff32
的作用域似乎可以解决这个问题。看起来GCC判断缓冲区不再在其范围内使用,并认为它是未使用的,因此优化了它。
是否可能从编译器获得警告?这是一个未定义的行为吗?
2条答案
按热度按时间1zmg4dgp1#
当执行循环的第一次迭代时,如果
functionB
为true,则将buff32
的值赋给变量p
。现在
p
指向buff32
的开头,它是堆栈上的一个数组。当调用break
并退出循环时,堆栈帧被释放,因此p
指向不再使用的堆栈空间。如果你把
buff32
的定义移出循环(就像你在问题中说的那样),这个空间在程序退出之前都是有效的,所以你不会遇到这个问题。这就是为什么@Ted-Lyngmo评论说消毒剂报告了
stack-use-after-scope
。w7t8yxp52#
buff 32的范围是问题所在。@Ted Lyngmo
不知道你的问题,很难说,但你的代码可能应该读起来像这样: