【问题标题】:Overriding malloc using the LD_PRELOAD and calls malloc in library functions使用 LD_PRELOAD 覆盖 malloc 并在库函数中调用 malloc
【发布时间】:2016-03-13 22:37:33
【问题描述】:

我正在创建一个小型快速应用程序,用于检测其他应用程序中的内存泄漏。我使用 LD_PRELOAD 覆盖默认 malloc,并在程序中每次调用 malloc 时使用它存储在内存中。问题是C的一些库函数也使用malloc。此外,有些库函数不会释放分配的内存。让我们演示一下:
MyApp.cpp

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

static void * (* LT_MALLOC)(size_t) = 0;
static void (* LT_FREE)(void *) = 0;

static void init_malloc ()
{
  char *error;
  *(void **) (&LT_MALLOC) = dlsym (RTLD_NEXT, "malloc");
  dlerror ();
  if ((error = dlerror ()) != NULL)
    {
      fprintf (stderr, "%s\n", error);
      _exit(1);
    }
}

static void init_free ()
{
  char *error;
  *(void **) (&LT_FREE) = dlsym (RTLD_NEXT, "free");
  dlerror ();
  if ((error = dlerror ()) != NULL)
    {
      fprintf (stderr, "%s\n", error);
      _exit(1);
    }
}

extern "C"
void * malloc (size_t size) throw ()
{
  if (LT_MALLOC == 0)
    init_malloc ();
  printf ("malloc(%ld) ", size);
  void *p = LT_MALLOC(size);
  printf ("p = %p\n", p);
  return p;
}

extern "C"
void free (void *p) throw ()
{
  if (LT_FREE == 0)
    init_free ();
  printf ("free(%p)\n", p);
  LT_FREE(p);
}

还有test.c。 (假设最初没有源代码,我只有一个程序。)

#include <stdlib.h>
#include <stdio.h>
#include <time.h>

int main (void)
{
  printf ("test start\n");
  int *a = (int *)malloc(3 * sizeof (int));
  if (a)
    printf ("Allocated 3 int - %p\n", a);
  time_t t = time(NULL);
  a[0] = 1;
  printf ("time - %s", ctime(&t));
  printf ("a[0] = %d\n", a[0]);
  free (a);
  printf ("CALL FREE(a)\n");
  printf ("test done\n");
  return 0;
}


$ g++ -g -fPIC -c MyApp.cpp -o MyApp.o 
$ g++ -g -shared MyApp.o -o MyApp.so -ldl
$ gcc -g test.c -o test
$ export LD_PRELOAD=./MyApp.so

运行程序./test看看:

malloc(72704) p = 0x8aa040
test start
malloc(12) p = 0x6a0c50
Allocated 3 int - 0x6a0c50
free((nil))
malloc(15) p = 0x6a0c70
malloc(552) p = 0x6a0c90
free((nil))
malloc(1014) p = 0x6a0ec0
free(0x6a0c90)
malloc(20) p = 0x6a0c90
malloc(20) p = 0x6a0cb0
malloc(20) p = 0x6a0cd0
malloc(21) p = 0x6a0cf0
malloc(20) p = 0x6a0d10
malloc(20) p = 0x6a0d30
malloc(20) p = 0x6a0d50
malloc(20) p = 0x6a0d70
malloc(21) p = 0x6a0d90
free((nil))
time - Mon Mar 14 18:30:14 2016
a[0] = 1
free(0x6a0c50)
CALL FREE(a)
test done

但我想看看:

test start
malloc(12) p = 0x6a0c50
Allocated 3 int - 0x6a0c50
time - Mon Mar 14 18:30:14 2016
a[0] = 1
free(0x6a0c50)
CALL FREE(a)
test done

我希望我的应用程序避免在库函数中调用 malloc。但我不知道该怎么做。
malloc 可以找出哪个函数调用它:库还是您自己的?或者我们可以在库函数中调用默认值而不是覆盖malloc?还是别的?
附言我很抱歉我的英语不好。

【问题讨论】:

  • 为什么不直接使用 valgrind?
  • Valgrind 没那么快。

标签: c memory-leaks malloc overriding ld-preload


【解决方案1】:

我多次使用用我自己的版本替换malloc 的宏来编译我的代码的技术。我以为我已经写了一个答案来证明这一点,但显然不是。像这样的:

在“debugmalloc.h”或类似的地方:

#if DEBUG_MALLOC
#define malloc(x) myTrackingMalloc(x, __FILE__, __LINE__)
#define free(x) myTrackngFree(x, __FILE__, __LINE__)

extern void* myTrackingMalloc(size_t size, const char* file, int line);
extern void myTrackingFree(void* ptr, const char* file, int line);
#endif

然后在源文件中,例如“debugmalloc.c”:

#if DEBUG_MALLOC
void* myTrackingMalloc(size_t size, const char* file, int line)
{
    void *p = malloc(size);
    ... whatever extra stuff you need ... 
    return p;
}

void myTrackingFree(void* ptr, const char* file, int line)
{
    ... some extra code here ... 
    free(ptr);
}
#endif

[我通过修改size分配了一些额外的字节,然后添加了一个偏移量来返回适当的实际负载指针]

这相对容易实现,并且没有使用 LD_PRELOAD 注入的缺点 - 特别是您不需要区分代码和库。当然,您不需要实现自己的 malloc。

它确实有一个小缺点,它没有涵盖newdeletestrdup 和其他本身进行内存分配的库函数 - 你可以实现一个 newdelete 全局operator set [不要忘记数组版本!],但是替换 strdup 和任何其他可能分配内存的函数是相当多的工作 - 在这一点上,valgrind 可能会更快,即使它运行得很慢。

【讨论】:

    【解决方案2】:

    也许动态加载器 API 可以帮助您。在那里您可以找到函数 dladdr(),它返回模块和给定地址的符号名称(如果可用)。

    详细解释请参见 dlopen 的手册页。

    【讨论】:

      【解决方案3】:

      在发布的代码中,您没有跟踪 callocreallocstrdup。跟踪所有malloc 相关的分配函数会更加一致。

      您还可以跟踪 fopenfclose 以在执行期间禁用 mallocfree 跟踪。这还可以让您跟踪丢失的fclose() 呼叫。

      您可以对使用 malloc 的其他 C 库函数执行相同的操作。 printf 不太可能使用 malloc,但您可以跟踪 vfprintf 以过滤掉任何此类调用。包装可变参数函数很困难,但printf 系列都调用vfprintf 或一些近亲,这取决于您的C 库的实现。 当您自己拨打printf 时,请注意禁用vfprintf 跟踪!

      【讨论】:

        猜你喜欢
        • 2011-08-30
        • 2014-02-05
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-03-20
        相关资源
        最近更新 更多