在C语言中是否有一种方法可以覆盖malloc/free函数?

8
有没有一种方法可以从C应用程序本身钩取malloc/free函数调用?

1
但你可以将其包装在自己的函数中,以便不覆盖原有内容。 - AntonH
2
这是非常特定于平台的,你应该明确指定你正在使用的平台/工具链。 - Matteo Italia
1
显然你不能覆盖它。因为C不支持函数重载。 - Sathish
1
@Sujith 无论在哪里,如果你使用C语言,你就不能。 - Sathish
1
规则是调用malloc的代码和调用free的代码应该在同一个.so文件中。因此,将库的内存公开为不透明句柄,并使用自己库中的代码进行管理,类似于FILE的fopen/fclose。 - user3458
显示剩余6条评论
8个回答

6

malloc()free()是在标准库中定义的;当链接代码时,链接器仅会搜索还未被先前遇到的目标代码解析的符号,并且从编译生成的目标文件始终在任何库之前链接。

因此,您可以通过在自己的代码中定义它来覆盖任何库函数,确保它具有正确的签名(相同的名称、相同数量和类型的参数以及相同的返回类型)。


这个回答非常接近问题,尽管原始问题中要求的是malloc钩子函数,而不是重新实现。(+1) - Andreas Grapentin
1
@AndreasGrapentin:我不清楚他所说的“hooks”是什么意思,但这似乎与标题所暗示的问题略有不同。看起来他在问两个问题。 - Clifford

5

是的,你可以。这里有一个示例程序。它可以使用gcc 4.8.2进行编译和构建,但由于实现不可行,所以没有实际用途。

#include <stdlib.h>

int main()
{
   int* ip = malloc(sizeof(int));
   double* dp = malloc(sizeof(double));

   free(ip);
   free(dp);
}

void* malloc(size_t s)
{
   return NULL;
}

void free(void* p)
{
}

3
对于GNU / Linux,glibc还导出了__libc_malloc等函数,因此您可以从自己的malloc函数中调用它们,并仍然使用由glibc提供的malloc函数,并根据需要添加钩子逻辑。虽然不具备可移植性,但您需要使用dlsym来实现更具可移植性的解决方案。 - Andreas Grapentin
1
最后终于有人知道他们在说什么了。话虽如此,这段代码确实可以运行,但并没有分配内存。 - Clifford
1
@AndreasGrapentin:这取决于你的需求。你可以分配一个大的静态数组,并使用自己的分配算法将其用作堆,那么就没有操作系统依赖性。这基本上是大多数无操作系统嵌入式系统的做法。 - Clifford
@Clifford 这在应用程序代码中几乎从来都不是一个好主意,嵌入式系统当然又是另外一回事了。 - Andreas Grapentin
1
@AndreasGrapentin: 确实如此,但是这个问题涉及到GCC/Linux的事实还没有在问题中被明确提出,只有后来的评论,而我们无法知道为什么要问这个问题-因此需要“根据您的需求而定”的限定语。在Linux中,您将失去重要的灵活性和功能,例如虚拟内存,而大量的静态分配可能会影响其他被强制交换的进程的性能-但这个想法已经存在了(我是一个嵌入式系统开发人员)。 - Clifford
@Clifford 再次提到,非常正确。我认为我受到了问题主体中“hook”一词的影响 - 而 malloc hook 通常不是重新实现 =)这个问题需要一些澄清。很高兴你在上面的评论中请求了它们! - Andreas Grapentin

2

不确定这是否算作“覆盖”,但您可以通过使用宏有效地更改调用mallocfree的代码的行为:

#define malloc(x) my_malloc(x)
#define free(x) my_free(x)

void * my_malloc(size_t nbytes)
{
    /* Do your magic here! */
}

void my_free(void *p)
{
    /* Do your magic here! */
}

int main(void)
{
   int *p = malloc(sizeof(int) * 4); /* calls my_malloc */
   free(p);                          /* calls my_free   */
}

2

您可能需要使用LD_PRELOAD机制来替换mallocfree函数。


你能否添加更多信息,以便读者不需要谷歌“LD_PRELOAD”?顺便说一句,这是一个非常有趣的技巧,我以前从未见过它被使用过。 - Z4-tier

1
正如许多人已经提到的,这非常具有特定平台性。最“便携”的方法在this question的一个被接受的答案中描述了。将其移植到非POSIX平台需要找到适当的替代dlsym。
由于您提到了Linux/gcc,malloc钩子可能是最好的选择。

malloc 钩子已被弃用 - 取而代之的是,malloc 和相关函数作为弱符号导出,允许用户代码覆盖它们(请参见我在上面评论中链接的问题)。 - Andreas Grapentin

0

根据您使用的平台,您可能可以从库中删除默认的malloc/free,并使用链接器或图书管理员工具添加自己的malloc/free。我建议您只在私有区域中执行此操作,并确保不会损坏原始库。


危险且不必要。编辑:至少针对GNU / Linux =) - Andreas Grapentin
1
你不需要走那么远 - 只需定义一个同名函数,链接器就不会搜索库文件了。 - Clifford

0
在Windows平台上有一个Detour库,它可以在汇编语言级别上基本修补任何给定的函数。这允许拦截任何C库或操作系统调用,如CreateThreadHeapAlloc等。我在工作应用程序中使用了这个库来覆盖内存分配函数。
这个库是特定于Windows的。在其他平台上很可能有类似的库。

-1

C语言不支持函数重载,因此无法进行覆盖。


4
重载与接管无关。 - chris
@chris 是的,没错。但是我认为,由于我们可以在C++中重载new操作符,所以我们无法在C语言中重载malloc函数。 - Pranit Kothari
1
重载malloc如何帮助替换它?除非您为非size_t参数提供更好的匹配项,否则调用malloc的所有内容仍将使用原始内容,即使是具有size_t参数的调用也仍将使用原始内容。 - chris
这真的取决于你使用的平台。在嵌入式系统中,编写自己的malloc()是相当常见的。 - TRKemp
1
赶快告诉dlmalloc、tcmalloc、jemalloc以及其他许多人,他们不能这样做! - Javier
2
重载(Overload)和覆盖(Override)在C或C++中并不是同一回事。你可以通过定义来覆盖任何库代码。 - Clifford

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接