c - 为什么堆栈中定义的这个C函数指针在传递时无效?
问题描述
我试图将父块范围内定义的函数指针传递给另一个函数。我在不同的环境中都遇到了工作和段错误。(我不是 C 专家)
编码:
#include <stdio.h>
#include <stdbool.h>
void test_function(bool (*function_pointer) (int x)) {
printf("addr passed function_pointer %p\n", function_pointer);
if (function_pointer(100)) {
printf(" run: true\n");
} else {
printf(" run: false\n");
}
}
bool function_outside_main(int x) {
return x < 0;
}
int main(void) {
// run with function defined globally
printf("addr function_outside_main %p\n", function_outside_main);
test_function(function_outside_main);
// run with function defined in this stack block
bool function_inside_main(int x) {
return x > 0;
}
printf("addr function_inside_main %p\n", function_inside_main);
test_function(function_inside_main); // shouldn't the address be valid?
}
在带有 GCC 版本(在 Amazon EC2 上)的 Ubuntu 16.04.45.4.0
上,它适用于输出:
addr function_outside_main 0x400620
addr passed function_pointer 0x400620
run: false
addr function_inside_main 0x7ffc018d5690
addr passed function_pointer 0x7ffc018d5690
run: true
9.3.0
在带有 GCC 版本(在 Windows WSL 下)的Ubuntu 20.04.1 上,它因段错误而失败:
addr function_outside_main 0x7ff19c8631dd
addr passed function_pointer 0x7ff19c8631dd
run: false
addr function_inside_main 0x7ffffc033b20
addr passed function_pointer 0x7ffffc033b20
zsh: segmentation fault (core dumped) ./a.out
解决方案
像这样的嵌套函数是 gcc 扩展,而不是 C 标准的一部分。
gcc 为此使用的实现通常1涉及为嵌套函数创建一个堆栈上的 thunk,因此调用它需要可执行堆栈支持。较新版本的 Linux(和 Windows)默认为不可执行堆栈,因此会崩溃。
为了使这个工作,您可以使用-z execstack
gcc 的选项,或者您可以使用该execstack
工具修改二进制文件以在创建后指定可执行堆栈。
1在某些带有 -O 的 gcc 版本中,它可以确定嵌套函数何时实际上不需要嵌套(它们从不引用包含范围),并且在这些情况下不使用 thunk
推荐阅读
- javascript - React Router-Uncaught TypeError:无法读取未定义的属性'func'
- c# - 攀爬系统的网格边缘检测
- sql - ETL 包最初加载所有数据然后下次运行以仅加载更改或新项目的最佳方法
- docker - Docker Windows 10 - 如何运行 Jenkins,在 d 驱动器上绑定卷而不会出现权限错误
- python - raise HTTPError(req.full_url, code, msg, hdrs, fp) urllib.error.HTTPError: HTTP Error 403: Forbidden
- botframework - Bot Framework:使用 LUIS 处理较长电子邮件的方法(超过 500 个字符)
- excel - 替换 for 循环,以便计算非空行
- mysql - 是否可以仅通过 cpanel/phpmyadmin 访问“复制”数据库?
- apache-spark - 使用 SQL 语法过滤和在 Pyspark 中显式调用列之间的区别?
- python - 如何在 ATOM 编辑器中为每个项目设置 PYTHONPATH