【问题标题】:malloc function interposition in the standard C and C++ libraries标准 C 和 C++ 库中的 malloc 函数插入
【发布时间】:2016-05-06 11:29:18
【问题描述】:

我想编写一个共享库,以便可以将它的内存使用与它所链接的应用程序隔离开来。也就是说,如果共享库,我们称之为libmemory.so,调用malloc,我想将该内存保留在一个单独的堆中,该堆用于为应用程序中对malloc的调用提供服务。这个问题不是关于编写内存分配器,而是关于将库和应用程序链接和加载在一起。

到目前为止,我一直在试验函数插入、符号可见性和链接技巧的组合。到目前为止,由于一件事,我无法做到这一点:标准库。我无法找到一种方法来区分对内部使用malloc 的标准库的调用(发生在libmemory.so 和应用程序中)。这会导致一个问题,因为在libmemory.so 中使用任何标准库都会污染应用程序堆。

我目前的策略是在共享库中插入malloc 的定义作为隐藏符号。这工作得很好,所有库代码都按预期工作,当然,在运行时动态加载的标准库除外。自然地,我一直在尝试找到一种静态嵌入标准库用法的方法,以便它在编译时使用libmemory.so 中插入的malloc。我试过-static-libgcc-static-libstdc++ 都没有成功(无论如何,这似乎是不鼓励的)。 this 是正确答案吗?

做什么?

P.s.,进一步阅读总是值得赞赏的,在问题标记方面的帮助会很好。

【问题讨论】:

  • 与 Windows 不同,Unix 用户空间非常倾向于使用相同分配器的进程中的所有内容。仅仅在同一进程中拥有两个 malloc 的实现很容易导致灾难性的故障,因为没有人担心将 A_malloc 与 A_free 以及 B_malloc 与 B_free 匹配,这些实现可能会为它们中的哪一个发生争执允许使用非零参数调用sbrk,等等等等。
  • 因此,为了提供任何有用的答案,我们需要更多地了解您为什么认为您首先需要做这件事。你试图解决的更大的问题是什么?为什么这似乎是阻力最小的路径?大致了解libmemory.so 做了什么以及它使用了哪些 C 和 C++ 库函数也很有用。
  • 感谢@zwol 的回复。我正在构建一个分布式共享内存分配器作为共享对象,并希望找到一种方法来分离共享对象与应用程序使用的内存。共享对象很复杂:它有一个分配器,有一个嵌入式 HTTP 服务器等。它充分利用了内存本身(尽管我在编写的所有库代码中都使用了一个特殊分配器的内存)。作为状态,问题是标准库使用的内存......例如,下降到fopengmtime_r 可能会在内部调用malloc,从而使用要使用的应用程序的堆分配器。
  • 首先想到的是:也许共享库的大部分功能应该被提取到一个单独的守护进程中。
  • 这是一个重大的设计更改,但肯定是可能的。在我改变路线之前,我可以用我当前的设置调查任何其他方法吗?

标签: c unix malloc shared-libraries function-interposition


【解决方案1】:

我试过 -static-libgcc 和 -static-libstdc++ 都没有成功

当然这不会成功:malloc 不在libgcclibstdc++;它住在libc

你想要做的是静态链接libmemory.so与一些替代的malloc实现,例如tcmallocjemalloc,并且隐藏所有@ 987654329@ 符号。那么你的库和你的应用程序将拥有绝对独立的堆。

不用说,您必须从不在您的库中分配某些东西并在应用程序中释放它,反之亦然。

理论上您也可以将系统libc.amalloc 部分链接到您的库中,但实际上GLIBC(和大多数其他UNIX C 库)不支持部分静态链接(如果您链接libc.a,你不能链接libc.so)。

更新:

如果 libmemory.so 使用标准库函数,例如 gmtime_r,它是动态链接的,从而在运行时解析 malloc,那么 libmemory.so 错误地使用了运行时提供的 malloc(显然来自 glibc 的那个

没有错了。由于您已将 malloc 隐藏在库中,因此 没有 其他 malloc gmtime_r 可以使用。

另外,gmtime_r 不分配内存,除非 GLIBC 本身内部使用,而这样的内存可以被 __libc_freeres 清理,所以分配这块内存是错误除了使用 GLIBC 的 malloc 之外的任何地方。

现在,fopen 是您使用的另一个示例,fopen 使用 malloc 内存。显然,您希望fopen 在您的库调用时调用您的malloc(即使fopen 不可见),但在应用程序调用时调用系统malloc。但是fopen怎么知道是谁打来的呢?您肯定不是建议 fopen 遍历堆栈以确定它是由您的库还是由其他东西调用的?

所以,如果你真的想让你的库调用系统malloc,那么你必须静态链接所有你使用的其他libc函数和可能会调用malloc(并将它们也隐藏在您的库中)。

您可以使用 uclibcdietlibc 之类的东西来实现这一点。

【讨论】:

  • 感谢您的回复。我将libmemory.so 与我自己的malloc 符号链接,并且我还将这些符号隐藏在libmemory.so 中。 libmemory.so 对 malloc 的使用处理得非常好。根据原始问题,问题与标准库有关。如果libmemory.so 使用了一个标准库函数,例如gmtime_r,它是动态链接的,从而在运行时解析malloc,那么libmemory.so 错误地使用了运行时提供的malloc(显然来自@ 987654362@ -- 谢谢你)。这是否澄清,或者我错过了什么?
  • 谢谢,这与我对这个问题的看法一致。我的印象是,如果不为整个应用程序替换 libc,就无法使用 uclibcdietlibcmusl 之类的东西。听起来您在暗示可以在不触及应用程序的情况下静态链接libmemory.so 使用的所有 libc 函数(从而使用libmemory.so 的内部malloc 实现):它仍然会使用正常的动态链接库。
  • 这个印象不正确吗?我可以构建musl 并将其静态链接到我的libmemory.so 而不会搞砸另一个libc 吗?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多