c - 如何预加载共享库并使用在同一包装函数中使用 malloc 的函数来包装 malloc?

标签 c linker mocking malloc shared-libraries

我想将 malloc 包装在一个函数中,该函数将打印分配大小、指针地址和分配时间。这可以通过我的 malloc 实现预加载我的共享库来实现。这段代码实现了:

#define _GNU_SOURCE

#include <stdio.h>
#include <dlfcn.h>

static void* (*real_malloc)(size_t size) = NULL;
static void* (*real_calloc)(size_t nelements, size_t elementSize) = NULL;

static void init(void)
{
    real_malloc = dlsym(RTLD_NEXT, "malloc");
    if (NULL == real_malloc)
    {
        fprintf(stderr, "Error: %s\n", dlerror());
    }
}

void *malloc(size_t size)
{
    if(real_malloc == NULL)
    {
        init();
    }

    void *p = NULL;

    p = real_malloc(size);
    fprintf(stderr, "size=%lu, pointer=%p\n", size, p);
    return p;
}

但是如果我将时间打印功能添加到 malloc 中:

static void printTime()
{
  time_t timer;
    char buffer[26];
    struct tm* tm_info;

    time(&timer);
    tm_info = localtime(&timer);

    strftime(buffer, 26, "%Y-%m-%d %H:%M:%S", tm_info);
    fprintf(stderr, "%s\n", buffer);
}

并添加 time.h header 并使用可执行文件运行我的 .so 库,它将简单地卡住并且不执行任何操作。

我怀疑 timelocaltime 在幕后调用 malloc 并以某种方式导致问题。另一方面,real_malloc 确实被调用,所以应该不会有问题。

我的可执行文件是多线程的,但添加互斥体没有帮助。我编译.so的方式如下:

gcc -fPIC -shared -o bin/libpreload.so myAlloc.c -ldl

可以使用 Linux ps 程序验证该问题:

cd/bin && LD_PRELOAD=/home/用户名/Desktop/alloc/bin/libpreload.so ./ps

下面是我的 .so 的 ldd 输出: enter image description here

最佳答案

如果 malloc 中的日志记录函数最终调用 malloc,您需要跳出递归循环。

因此,仅当在日志记录之外调用 malloc 时才进行日志记录。

void *malloc(size_t size)
{
    if(real_malloc == NULL)
    {
        init();
    }

    void *p = NULL;

    p = real_malloc(size);

    if (do_logging)
      {
         do_logging = 0;
         fprintf(stderr, "size=%lu, pointer=%p\n", size, p);
         printTime();
         do_logging = 1;
      }
    return p;
}

当然,如果您希望它在多线程程序中工作,您必须将 do_logging 放入线程本地存储中。在 c11 及更高版本中,您可以这样做:

#include <threads.h>
thread_local int do_logging = 1;

哦,你的 init 函数可能不是线程安全的。

关于c - 如何预加载共享库并使用在同一包装函数中使用 malloc 的函数来包装 malloc?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56176875/

相关文章:

c - 在c中读取JPEG头文件

c++ - 调整 Makefile 以包含 SDL2

unit-testing - 在 CakePHP 中模拟一个 Controller 方法

php - 在 Laravel 6 中模拟 Auth::user()

mocking - 为什么要麻烦模拟存储库?

c - 如何复制其中包含结构详细信息的节点 c

c - 如何在 ruby​​ Fiddle 中处理数组指针

c++ - 如何在 Arduino 中使用时间库?

c - C 头文件和库的分发和链接

c - 奇怪的链接行为 - gcc 库