【问题标题】:How to preload shared library and wrap malloc alongside using functions which use malloc in the same wrapped function?如何在同一个包装函数中使用使用 malloc 的函数预加载共享库和包装 malloc?
【发布时间】:2019-05-16 21:33:18
【问题描述】:

我想将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 标头并使用可执行文件运行我的 .so 库,它只会冻结并且什么都不做。

我怀疑 timelocaltime 在后台调用 malloc 会导致问题。另一方面,real_malloc 确实被调用了,所以应该没有问题。

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

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

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

cd /bin &amp;&amp; LD_PRELOAD=/home/username/Desktop/alloc/bin/libpreload.so ./ps

下面还有我的.so 的ldd 输出:

【问题讨论】:

  • 您的打印时间不正确
  • vdso 在查询时钟方面也有特殊性

标签: c linker mocking malloc shared-libraries


【解决方案1】:

如果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-函数可能不是线程安全的。

【讨论】:

  • 我需要使用来保护do_logging,因为我的可执行文件是多线程的,对吗?因为我的共享库不是,它只是声明malloc
  • 如果malloc 可以同时从多个线程调用,它必须是多线程安全的。它与哪个库启动线程无关,而仅与如何调用库函数有关
猜你喜欢
  • 1970-01-01
  • 2021-05-18
  • 1970-01-01
  • 2013-05-23
  • 1970-01-01
  • 2023-03-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多