首页 > 解决方案 > 静态对象的析构函数不(总是)用 LD_PRELOAD 调用

问题描述

我想使用 LD_PRELOAD 机制 GNU 的动态加载器将代码注入其他二进制文件。在我的代码中,我使用静态对象在增强程序(稍后称为 Prog)的开始和结束时执行代码。我不应该关心静态初始化程序的执行顺序,因为我不访问 Prog 的任何数据,我也不关心我的代码何时运行,只要它“足够接近”Prog 的“main”的开始/结束。

问题在于,对于某些二进制文件,这种方法可以正常工作,而对于其他二进制文件,则根本不调用静态对象的析构函数。

#include <iostream>

namespace {
struct Stat {
        Stat()  { std::cerr << "Ctor" << std::endl; }
        ~Stat() { std::cerr << "Dtor" << std::endl; }
};
}

Stat s;

汇编: $ g++ -shared -fpic -o ~/preload.so preload.cc

用法:

$ LD_PRELOAD=~/preload.so /bin/true
Ctor
Dtor
$ LD_PRELOAD=~/preload.so /bin/sleep 1
Ctor

在第一种情况下,true一切都按预期工作,但在第二种情况下(以及大多数/所有其他情况),析构函数永远不会被调用。我排除了标准流“过早”破坏的问题,方法是将字符串输出替换为sleep…适用于true,失败为sleep(编辑:忽略最后一部分。我搞砸了编译并sleep再次运行版本。sleep实际上有效,所以@dms是正确的。它没有解释gdb中双重打印的“Ctor”,但我不在乎关于那个神器的东西太多了。

更奇怪的是。当我尝试在 gdb 中运行示例时(使用set env LD_PRELOAD ...),“Ctor”被打印两次。如果我在它处设置断点,Stat则仅在第一次输出“Ctor”后触发。断点~Stat确实触发但仍然没有输出。

有一个关于 DLL 中的静态对象 dtors的类似问题。那里的答案要么是特定于 Windows 的,要么暗示永远不会为动态加载的库调用静态 dtor,这在我的情况下显然不是真的。

标签: c++staticdestructorld-preload

解决方案


推荐阅读