由于缓冲区范围有限,使用-Os优化了memcpy代码

eeq64g8w  于 2023-06-21  发布在  其他
关注(0)|答案(2)|浏览(127)

我有以下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判断缓冲区不再在其范围内使用,并认为它是未使用的,因此优化了它。
是否可能从编译器获得警告?这是一个未定义的行为吗?

1zmg4dgp

1zmg4dgp1#

当执行循环的第一次迭代时,如果functionB为true,则将buff32的值赋给变量p
现在p指向buff32的开头,它是堆栈上的一个数组。当调用break并退出循环时,堆栈帧被释放,因此p指向不再使用的堆栈空间。
如果你把buff32的定义移出循环(就像你在问题中说的那样),这个空间在程序退出之前都是有效的,所以你不会遇到这个问题。
这就是为什么@Ted-Lyngmo评论说消毒剂报告了stack-use-after-scope

w7t8yxp5

w7t8yxp52#

buff 32的范围是问题所在。@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};  //<<--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;
}

相关问题