英文:
memcpy code optimized with -Os because of limited buffer scope
问题
使用"-O0"编译代码时,结果如下:
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判断在其范围内不再使用该缓冲区,并将其视为未使用,因此进行了优化。
是否可能从编译器获得警告?这是否是未定义行为?
未定义行为通常是在C语言中不明确规定的行为,编译器可以自由地进行优化,而不受任何限制。因此,编译器可能不会生成警告,因为它认为未使用的变量可以安全地被丢弃。
要解决此问题,您可以尝试明确告诉编译器不要优化掉"buff32"变量。您可以使用"attribute((used))"来标记该变量,以确保编译器不会将其视为未使用。例如:
uint8_t buff32[32] __attribute__((used)) = {0x5};
这将告诉编译器"buff32"是被使用的,从而避免不必要的优化。这样,在使用"-Os"或"-O3"编译时,您应该会得到预期的结果。
英文:
I have the following C code, which works fine without optimization (-O0) but has unexpected behavior when using -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;
}
When compiling the code with "-O0", I have the result:
functionA
0 1 2 3 4 5 6 7 8 9 a b c d e f
However, with "-Os" or "-O3" (not "-O2"):
functionA
16 24 97 6b fc 7f 0 0 8d f2 b7 c ed 55 0 0
I tried on godbolt with different compilers like ARM GCC 10.3.1 and I see that the code of the memcpy in "functionB" is not compiled. Changing the scope of the buff32
at the beginning of the main
seems to solve the issue. It seems that GCC judges that the buffer is no longer used in its scope and considers it as unused, hence optimizes it.
Is it possible to get a warning from the compiler?
Is it an undefined behavior?
答案1
得分: 3
在执行循环的第一次迭代时,如果 functionB
为真,那么将 buff32
的值赋给变量 p
。
现在,p
指向位于堆栈上的 buff32
的开头。当调用 break
并退出循环时,堆栈帧被释放,所以 p
指向不再使用的堆栈空间。
如果将 buff32
的定义移到循环之外(就像你在问题中提到的那样),那么该空间在程序退出之前是有效的,因此你就不会遇到这个问题。
这就是为什么 @Ted-Lyngmo 的评论中提到,检测工具报告了 stack-use-after-scope
。
英文:
When executing the first iteration of the loop if functionB
is true then you assign the value of buff32
to the variable p
.
Now p
points to the beginning of buff32
that is an array on the stack. When you call break
and exit the loop the stack frame is freed and so p
points to a stack space that is not in use anymore.
If you move the definition of buff32
out of the loop (like you said you did in the question) that space is valid until the program exits so you don't get that problem.
That is why the @Ted-Lyngmo comment says that the sanitizers report a stack-use-after-scope
.
答案2
得分: 0
buff32的作用是问题所在。
看到@Ted Lyngmo的评论
不知道您的问题是什么,很难说,但是
您的代码应该像这样读取:
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};
uint8_t buff32[32] = {0}; //<<--这里
for (int i = 1; i <= 2; i++)
{
if (i == 1)
{
memset(buff32, '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};
uint8_t buff32[32] = {0}; //<<--这里
for (int i = 1; i <= 2; i++)
{
if (i == 1)
{
memset(buff32, '\0', sizeof(buff32)); //<<---这里
buff32[0] = 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;
}
', sizeof(buff32)); //<<---这里
buff32[0] = 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;
}
英文:
The scope of buff32 is the issue.
See comment from @Ted Lyngmo
Not knowing your question it's difficult to say but
your code should probably read like this:
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};
uint8_t buff32[32] = {0}; //<<--HERE
for (int i = 1; i <= 2; i++)
{
if (i == 1)
{
memset(buff32, '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};
uint8_t buff32[32] = {0}; //<<--HERE
for (int i = 1; i <= 2; i++)
{
if (i == 1)
{
memset(buff32, '\0', sizeof(buff32)); //<<---HERE
buff32[0] = 0x5; //<<---HERE
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;
}
', sizeof(buff32)); //<<---HERE
buff32[0] = 0x5; //<<---HERE
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;
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论