为什么我不能将动态函数指针传递给 atexit()?

Why can't I pass a dynamic function pointer to atexit()?

我可以将常规函数指针传递给 atexit():

void f1(void)
{
      printf("f1\n");
}

int main() {
  void (*fun_ptr)(void) = &f1;
  atexit(fun_ptr);
}

但是当我传递从另一个函数返回的函数指针时:

typedef void (*f22_t) (void);

f22_t f2(void) {
  void f22(void) {
  printf("f22\n");
  }

  return f22;
}


int main() {
  void (*fun_ptr2)(void) = f2();
  atexit(fun_ptr2);
}

结果是:

Illegal instruction (core dumped)

为什么第一个选项有效而第二个选项无效?

此外,我可能误读了 atexit() 上的文档 https://man7.org/linux/man-pages/man3/atexit.3.html 要么 https://pubs.opengroup.org/onlinepubs/007904875/functions/atexit.html 但在我看来,它没有提到为什么第二种情况不起作用的信息。

在另一个函数中定义一个函数是 GCC 扩展。根据 the GCC documentation,嵌套函数的生命周期在包含函数的执行结束时结束:

… If you try to call the nested function through its address after the containing function exits, all hell breaks loose…

因此,在 f2 退出后,它提供的指向 f22 的指针将不再支持任何进一步的使用,将其传递给 atexit 以供稍后调用会导致所有地狱挣脱束缚。

(实际上,GCC 通过在程序堆栈上创建一些可执行代码来实现嵌套函数,即使大部分函数代码像往常一样位于“文本”区域。嵌套函数的指针指向此堆栈上的代码。在包含函数退出后,其堆栈 space 通常会被重新用于其他目的,从而破坏在堆栈上创建的代码。因此尝试执行该代码失败,因为字节已更改。)

尝试在顶层而不是在 f2 内部定义 f22 函数。