我正在开发一个个人项目,我需要拦截Linux API,如
open()
、read()
等,我想对它们进行一些数据分析。我需要在库中保留一个 C++ 数据结构 std::map
,它将以线程安全的方式更新。
因为我想使用 C++ 的
std::map
,所以我正在考虑编写库 (.so
) 来使用 C++ 进行预加载,并且要拦截的函数将在前面加上 extern "C"
,以防止 C++ 编译器进行名称修改。
但是,这是正确的做法吗?我应该纯粹用 C 编写共享库,并从头开始实现
map
数据结构吗?
这是正确的做法吗?
这种方法没有什么特别错误的地方,但它可能会变得复杂(见下文)。
我应该纯粹用C编写共享库,并从头开始实现地图数据结构吗?
这将消除许多潜在的并发症。
那么有哪些并发症呢?
为了使用
std::map
,您必须将预加载.so
链接到libstdc++.so.6
,它将尝试在您的库之前初始化自身。
而且
libstdc++
又大又复杂。如果它的初始化调用 open()
、read()
等,我不会感到惊讶。
这意味着您的图书馆必须准备好处理这些调用,然后才能预期
libstdc++.so
正常工作。
以下序列可能发生并导致您的库崩溃:
libstdc++.so
调用 open
,这是由您的图书馆插入的std::map
实例中,该实例再次调用 libstdc++.so
,open
的调用返回到 libstdc++
。上述的许多变体都是可能的,您获得的变体可能取决于您插入的确切函数集、您对
libstdc++
进行的调用集以及 libstdc++
的版本。
也就是说,它可能工作正常,直到您在不同的系统上尝试它,或者直到您更新您的
g++
,或者直到您添加新的插入器。或者它可能根本不起作用。
它当然不是设计可以工作,所以你会玩俄罗斯轮盘赌。