Как предварительно загрузить разделяемую библиотеку и обернуть malloc вместе с использованием функций, которые используют malloc в одной и той же обернутой функции? - PullRequest
1 голос
/ 17 мая 2019

Я хочу обернуть 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 с исполняемым файлом, она просто зависнет и ничего не сделает.

Я подозреваю, что time или localtime вызывают malloc под капотом, и это как-то вызывает проблемы. С другой стороны, real_malloc действительно вызывается, поэтому проблем не должно быть.

Мой исполняемый файл многопоточный, но добавление мьютексов не помогло. Я собираю .so следующим образом:

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

Проблема может быть подтверждена с помощью программы Linux ps:

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

Также ниже вывод ldd для моего .so: enter image description here

1 Ответ

3 голосов
/ 17 мая 2019

Если ваши функции регистрации в 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 -функция не может быть поточно-безопасной.

...