我有以下C代码,它在没有优化(-O0)的情况下工作得很好,但在使用-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;
}

在使用"-O0"编译代码时,我得到的结果是:

functionA
0 1 2 3 4 5 6 7 8 9 a b c d e f

但是,使用"-Os"或"-03"(而不是"-O2"):

functionA
16 24 97 6b fc 7f 0 0 8d f2 b7 c ed 55 0 0

我用不同的编译器(如ARM GCC 10.3.1)在Godbolt上试了一下,我发现"函数B"中的Memcpy的代码没有编译.在main开头改变buff32的范围似乎就解决了这个问题.看起来GCC判断缓冲区在其作用域内不再使用,认为它未使用,因此对其进行了优化.

有没有可能从编译器那里得到警告? 这是一种未定义的行为吗?

推荐答案

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.

这就是为什么@Ted-Lyngmo的 comments 说消毒剂报告了stack-use-after-scope.

C++相关问答推荐

新的memaligning函数有什么用?

如何启用ss(另一个调查套接字的实用程序)来查看Linux主机上加入的多播组IP地址?

当main函数调用被重构时,C函数给出错误的结果

在struct中调用函数,但struct在void中 *

堆栈帧和值指针

无法用C++编译我的单元测试

在一个小型玩具项目中实现终端历史记录功能

如何在C中通过套接字自定义数据类型读取原始变量?

用C宏替换strncMP函数中的参数

如何在C中打印包含扫描字符和整数的语句?

为什么我可以在GCC的标签后声明变量,但不能声明Clang?

按长度对argv中的单词进行排序

For循环不会迭代所有字符串字符吗?(初学者问题)

我可以创建适用于不同endian的 colored颜色 struct 吗?

为什么Linux无法映射这个PT_LOAD ELF段?

I';我试着从.txt文件中读取文本,并用c计算其中的单词数量

Ubuntu编译:C中的文件格式无法识别错误

WSASocket在哪里定义?

为什么<到达*时不会转换为>?

我该如何处理这个 C 90 代码中的内存泄漏?