繁体   English   中英

构造一个指向alloca的函数指针会导致链接器错误?

[英]Constructing a function pointer to alloca causes linker errors?

我试图写一个函数,传递一个函数用于分配作为其参数; 它应该接受任何类型为void *(*)(size_t)有效分配器。 但是,当我尝试使用alloca作为分配器时,我遇到了奇怪的行为 - 构建一个指向alloca函数的函数指针编译得很好,但会导致链接器错误:

#include <stdlib.h>
#include <alloca.h>

int main() {
  void *(*foo)(size_t) = alloca;
}

结果是

/tmp/cc8F67yC.o: In function `main':
test15.c:(.text+0x8): undefined reference to `alloca'
collect2: error: ld returned 1 exit status

这与内联的alloca有关吗? 但是,当函数不需要具有地址时,不会仅作为优化进行内联。 事实上,使用GCC,我甚至可以编写我自己的版本,它在上面的代码中按预期工作:

static inline void *alloca(size_t n) {
  return __builtin_alloca(n);
}

有没有理由说标准版本的行为方式不一样?

谁说你的功能

static inline void *alloca(size_t n) {
    return __builtin_alloca(n);
}

作品? __builtin_alloca分配的对象在函数结束时符合它的生命周期,所以一旦你返回它,你就已经有了一个悬空指针!

这里引用手册页:

代码内联的事实意味着无法获取此函数的地址,或通过链接到不同的库来更改其行为。

该页面还提到:

如果有一个这个功能的私人版本,会产生混乱的后果

你不能做你的建议。 alloca是一个非常特殊的野兽,它只能在函数体内显式调用,而不能在函数调用的参数表达式中调用。

请注意,没有标准版本alloca C标准和POSIX都没有描述这个功能。

您公开的替代方案,将alloca重新定义为调用__builtin_alloca的内联函数不起作用:除其他问题外, __builtin_alloca()返回的指针仅在调用者返回时才有效,无论是否内联。

linux手册页非常明确:

[...]

描述

alloca()函数在调用者的堆栈帧中分配空间的大小字节。 当调用alloca()的函数返回其调用者时,将自动释放此临时空间。

返回值

alloca()函数返回指向已分配空间开头的指针。 如果分配导致堆栈溢出,则程序行为未定义。

[...]

符合

此功能不在POSIX.1中。

有证据表明alloca()函数出现在32V,PWB,PWB.2,3BSD和4BSD中。 在4.3BSD中有一个手册页。 Linux使用GNU版本。

笔记

alloca()函数依赖于机器和编译器。 对于某些应用,与使用malloc(3)free(3)相比,它的使用可以提高效率。 在某些情况下,它还可以简化使用longjmp(3)siglongjmp(3)应用程序中的内存释放。 否则,不鼓励使用它。

因为alloca()分配的空间是在堆栈帧中分配的,所以如果通过调用longjmp(3)siglongjmp(3)跳过函数返回,则会自动释放该空间。

如果引用它的指针超出范围,则alloca()分配的空间不会自动释放。

不要试图free(3) alloca()分配的空间!

关于GNU版本的注释

通常,gcc(1 alloca()使用内联代码转换对alloca()调用。 如果给出-ansi-std=c89-std=c99-std=c11选项并且未包含标头<alloca.h>则不会执行此操作。 否则,(没有-ansi-std=c*选项)glibc版本的<stdlib.h>包含<alloca.h>并且包含以下行:

  #ifdef __GNUC__ #define alloca(size) __builtin_alloca (size) #endif 

如果有这个功能的私人版本,会产生混乱的后果。

代码内联的事实意味着无法获取此函数的地址,或通过链接到不同的库来更改其行为。

内联代码通常由调整堆栈指针的单个指令组成,并且不检查堆栈溢出。 因此,没有返回NULL错误。

BUGS

如果无法扩展堆栈帧,则没有错误指示。 (但是,在分配失败后,如果程序尝试访问未分配的空间,程序可能会收到SIGSEGV信号。)

在许多系统中, alloca()不能在函数调用的参数列表中使用,因为alloca()保留的堆栈空间将出现在函数参数的空间中间的堆栈中。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM