【问题标题】:Why does gcc return 0 instead of the address of a stack allocated variable?为什么 gcc 返回 0 而不是堆栈分配变量的地址?
【发布时间】:2016-10-27 16:41:28
【问题描述】:

作为使用自定义堆栈的实验的一部分,我想要一个函数来返回堆栈分配的字符缓冲区的地址。

// return pointer to stack variable
void *foo(void)
{
    char sz[10] = "hello";
    return sz;
}

我知道在 C 中这样做是违法的,而且 gcc 也会发出警告。

gcc -Wall -Wextra -pedantic -std=gnu99 -fomit-frame-pointer -O0 -c foo.c 

foo.c:8:12: warning: function returns address of local variable [-Wreturn-local-addr]
     return sz;

不过,由于这是实验的一部分,我希望代码保持原样。有趣的是,生成的代码返回的是 0 而不是 sz 的栈地址:

boa@localhost:~/tmp$ objdump -dMintel foo.o
0000000000000000 <foo>:
   0:   48 b8 68 65 6c 6c 6f    movabs rax,0x6f6c6c6568
   7:   00 00 00 
   a:   48 89 44 24 f0          mov    QWORD PTR [rsp-0x10],rax
   f:   66 c7 44 24 f8 00 00    mov    WORD PTR [rsp-0x8],0x0
  16:   b8 00 00 00 00          mov    eax,0x0
  1b:   c3                      ret    

可以看到,0x0 被移到了 eax,这让我很困惑。为什么 gcc 会这样做?

这是一个完整的源文件,其中包含另一个函数 bar() 以及一个 main 函数。 bar() 按预期返回地址。

#include <stdint.h>
#include <stdio.h>

// return pointer to stack variable
void *foo(void)
{
    char sz[10] = "hello";
    return sz;
}

void *bar(void)
{
    char sz[10] = "hello";
    intptr_t i = (intptr_t)sz;
    return (void*)i;
}

int main(void)
{
    printf("foo: %p\n", foo());
    printf("bar: %p\n", bar());
    return 0;
}

boa@localhost:~/tmp$ make foo && ./foo
cc   foo.o   -o foo
foo: (nil)
bar: 0x7ffce518a268

这对我来说是个谜。 gcc的选择背后的逻辑可能是什么?

【问题讨论】:

  • 因为优化出来了。
  • 你使用的是什么版本的 gcc?在 gcc 4.9.2 下,我得到 lea rax, [rsp-0x10] 作为第四条指令,而不是您看到的 mov。
  • 我在某处看到了 cmets,它返回了 NULL,因此取消引用指针会以可预见的方式失败,而不是无规律地失败。
  • 假设行为是故意的(可能不是),您需要询问 gcc 的开发人员为什么选择它。关于未定义行为的事情是允许 any 结果,并且结果不必是一致的。
  • 是的,我也看到了这个问题。最后我看到,OP 已经确信他/她的提议是一个坏主意。关键是中断。任何线程都可能发生中断。

标签: c gcc


【解决方案1】:

GCC 在这种情况下故意返回NULL,从code 可以看出:

tree zero = build_zero_cst (TREE_TYPE (val));
gimple_return_set_retval (return_stmt, zero);
update_stmt (stmt);

较新版本的 GCC 和 Clang 更积极地利用未定义的行为,因此这种检查并不令人惊讶。它还使代码快速失败,这在大多数情况下是一件好事(显然不是你的)。

【讨论】:

    猜你喜欢
    • 2020-09-23
    • 1970-01-01
    • 2013-11-07
    • 2014-10-30
    • 2019-03-02
    • 2016-12-11
    • 1970-01-01
    • 1970-01-01
    • 2011-02-02
    相关资源
    最近更新 更多