共享库-fini函数可调用哪些函数?LD_PRELOAD下printf调用失败问题
LD_PRELOAD共享库的-fini函数中printf调用失败的原因及可用函数说明
问题原因
程序进入退出流程时,glibc的执行顺序决定了共享库的-fini函数是在C标准库核心组件清理之后才执行。具体流程大致为:
- 执行
atexit/on_exit注册的回调函数 - 刷新并关闭所有stdio流(包括stdout)
- 调用各个共享库的
fini函数 - 最终调用
_exit系统调用终止进程
你的示例中,fini函数执行时,stdout已经被关闭,printf依赖的stdio流结构已被销毁,因此调用失败返回-1,触发了后续的sleep(2)。而sleep是直接封装内核系统调用的函数,不依赖C标准库的全局状态,所以能正常执行。
-fini函数中可安全调用的函数范围
在fini函数中,只能调用不依赖C标准库已销毁资源的函数,主要包括:
- 直接映射系统调用的函数:比如
write、read、sleep、_exit、getpid等(注意使用write时要直接操作文件描述符,如STDOUT_FILENO,而非依赖stdio流) - 纯逻辑计算类函数:不涉及内存分配、IO操作的自实现函数或标准库函数(如
strlen这类无状态函数) - 不依赖全局初始化状态的函数:避免使用任何需要C标准库全局结构支持的功能,比如
printf/fprintf等stdio家族函数、malloc/free堆操作函数、线程相关函数(线程库可能已完成清理)
修复示例
将fini函数中的printf替换为直接调用write,即可正常输出内容:
#include <stdio.h> #include <unistd.h> #include <string.h> void init() { printf("%s\n", __func__); fflush(stdout); } void fini() { const char msg[] = "fini\n"; write(STDOUT_FILENO, msg, strlen(msg)); sleep(2); }
执行修改后的代码,会正常输出init、mark和fini,同时保留2秒停顿。
内容的提问来源于stack exchange,提问作者Mark Galeck
相关产品推荐
相关产品推荐

