【发布时间】:2014-07-14 01:49:50
【问题描述】:
考虑以下可以在任何程序执行之前预加载的库:
// g++ -std=c++11 -shared -fPIC preload.cpp -o preload.so
// LD_PRELOAD=./preload.so <command>
#include <iostream>
struct Goodbye {
Goodbye() {std::cout << "Hello\n";}
~Goodbye() {std::cout << "Goodbye!\n";}
} goodbye;
问题是,虽然全局变量goodbye的构造函数总是被调用,但有些程序没有调用析构函数,比如ls:
$ LD_PRELOAD=./preload.so ls
Hello
对于其他一些程序,析构函数按预期调用:
$ LD_PRELOAD=./preload.so man
Hello
What manual page do you want?
Goodbye!
你能解释一下为什么在第一种情况下不调用析构函数吗? 编辑:上面的问题已经回答了,那就是一个程序很可能使用_exit(), abort() 来退出。
但是:
有没有办法在预加载的程序退出时强制调用给定的函数?
【问题讨论】:
-
This question 似乎表明应该总是调用析构函数。你能做更多的研究来缩小哪些类型的程序最终会调用析构函数,哪些不会?
-
“类型”是什么意思?我似乎找不到区分“好”程序和“坏”程序的方法。请注意,当返回码为 0(无错误,无 abort())时也会出现问题
-
尝试用 C 语言编写一个预加载模块,使用 GCC 的
__attribute__((constructor))在启动时运行一个函数;让该函数使用atexit注册一个函数以在拆卸时运行。这有什么不同吗? (它不应该,但它可能。) -
R.. 已回答您的第二个问题,但不是您的第一个问题。由于
_exit和abort以及其他各种“异常程序终止”机制,其合同中包含它们不',因此不可能强制调用函数t 执行任何析构函数、atexit函数等。但是,我发现/bin/ls通常会以这种方式退出是不可信的,所以为什么你的预加载模块的析构函数没有运行仍然是个谜. -
请注意,您在这里使用了相当高级的功能:
std::cout是一个与 stdio 流同步的缓冲流。ls很可能在退出时做了一些破坏这种机制的事情。如果你改用::write(2, "Goodbye\n", 8);会发生什么?
标签: c++ linux gcc ld ld-preload