LD_PRELOAD无法按预期工作 [英] LD_PRELOAD does not work as expected
问题描述
考虑以下可在任何程序执行之前预加载的库:
Consider the following library which can be preloaded before any program execution:
// 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
:
The problem is that, while the constructor of the global variable goodbye
is always called, the destructor is not called for some programs, like ls
:
$ LD_PRELOAD=./preload.so ls
Hello
对于其他一些程序,析构函数将按预期方式调用:
For some other programs, the destructor is called as expected:
$ LD_PRELOAD=./preload.so man
Hello
What manual page do you want?
Goodbye!
您能解释一下为什么在第一种情况下不调用析构函数吗? 上面的问题已得到解答,即程序可能会使用_exit(),abort()退出.
Can you explain why the destructor is not called in the first case? the above question has been already answered, that is a program might well use _exit(), abort() to exit.
但是:
有没有办法在预加载的程序退出时强制调用给定功能?
推荐答案
ls
以atexit (close_stdout);
作为其初始化代码.完成后,它将关闭标准输出(即close(1)
),因此您的cout
,printf
或write(1, ...
操作将不会打印任何内容.这并不意味着不调用析构函数.您可以通过例如在析构函数中创建一个新文件.
ls
has atexit (close_stdout);
as its initialisation code. When it finishes, it closes stdout (i.e. close(1)
), so your cout
, printf
or write(1, ...
operations will not print anything. It doesn't mean destructor isn't called. You can verify this by e.g. creating a new file in your destructor.
http://git.savannah. gnu.org/cgit/coreutils.git/tree/src/ls.c#n1285 这是GNU coreutils ls中的这一行.
http://git.savannah.gnu.org/cgit/coreutils.git/tree/src/ls.c#n1285 here is the line in GNU coreutils ls.
不仅仅是ls
,大多数coreutils都这样做.不幸的是,我不知道他们为什么宁愿为什么关闭它的确切原因.
It is not just ls
, most of coreutils do that. Unfortunately, I don't know exact reason why they prefer to close it.
关于如何找到(或至少我所做的)的旁注-下次或使用无源代码访问的程序时可能会有所帮助:
Side note on how this could be found (or at least what I did) - may help next time or with program with no source code access:
析构函数消息是用/bin/true
(我想到的最简单的程序)打印的,而不是用ls
或df
打印的.我从strace /bin/true
和strace /bin/ls
开始,比较了最新的系统调用.对于ls
,它显示close(1)
和close(2)
,对于true
,则没有显示.之后事情开始变得有意义,我只需要验证是否调用了析构函数即可.
Destructor message is printed with /bin/true
(simplest program I could think of), but isn't printed with ls
or df
. I started with strace /bin/true
and strace /bin/ls
and compared latest system calls. It shown close(1)
and close(2)
for ls
, but none for true
. After that things started to make sense and I just had to verify that destructor is called.
这篇关于LD_PRELOAD无法按预期工作的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!