簡體   English   中英

使用LD_PRELOAD覆蓋malloc並在庫函數中調用malloc

[英]Overriding malloc using the LD_PRELOAD and calls malloc in library functions

我正在創建一個小型的快速應用程序,它可以檢測其他應用程序中的內存泄漏。 我使用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 或者是其他東西?
PS:對不起,我的英語不好。

也許Dynamic Loader API可以為您提供幫助。 在這里,您可以找到函數dladdr(),該函數返回模塊和給定地址的符號名稱(如果有)。

有關詳細說明,請參見dlopen的手冊頁。

我有很多次使用通過宏替換我自己的版本的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全局運算符集[別忘了數組版本!],但是替換strdup和任何其他可能分配內存的函數都需要大量工作-到那時,即使valgrind運行得很慢,它也可能會更快。

在發布的代碼中,您不會跟蹤callocreallocstrdup 跟蹤所有與malloc相關的分配函數將更加一致。

您還可以跟蹤fopenfclose以在執行它們的過程中禁用mallocfree跟蹤。 這也將允許您跟蹤丟失的fclose()調用。

您可以對使用malloc其他C庫函數執行相同的操作。 printf不太可能使用malloc ,但是您可以跟蹤vfprintf來過濾掉任何此類調用。 包裝可變參數函數很困難,但是printf家族全都調用vfprintf或一些親戚,這取決於您的C庫的實現。 自己調用printf時請小心禁用vfprintf跟蹤!

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM