سؤال

باستخدام Linux/GCC/C++، أرغب في تسجيل شيء ما لـ stderr عندما يتم استدعاء malloc/free/new/delete.أحاول فهم تخصيصات الذاكرة الخاصة بالمكتبة، ولذلك أرغب في إنشاء هذا الإخراج أثناء تشغيل اختبارات الوحدة.أستخدم valgrind لاكتشاف تسرب الذاكرة، لكن لا يمكنني العثور على خيار لجعله يسجل التخصيصات فقط.

أيه أفكار؟أنا أبحث عن أبسط حل ممكن.إعادة ترجمة المكتبة ليس خيارا.

هل كانت مفيدة؟

المحلول

malloc_hook(3) يتيح لك أن تتدخل عالميًا بنفسك malloc وظيفة. (هناك __realloc_hook __free_hook إلخ أيضًا ، لقد تركتهم للتو من أجل البساطة.)

#include <stdio.h>
#include <malloc.h>

static void *(*old_malloc_hook)(size_t, const void *);

static void *new_malloc_hook(size_t size, const void *caller) {
    void *mem;

    __malloc_hook = old_malloc_hook;
    mem = malloc(size);
    fprintf(stderr, "%p: malloc(%zu) = %p\n", caller, size, mem);
    __malloc_hook = new_malloc_hook;

    return mem;
}

static void init_my_hooks(void) {
    old_malloc_hook = __malloc_hook;
    __malloc_hook = new_malloc_hook;
}

void (*__malloc_initialize_hook)(void) = init_my_hooks;
$ cat >mem.c <<'EOF'
(الرمز أعلاه)
EOF
$ cc -fPIC -shared -o mem.so mem.c
$ LD_PRELOAD=./mem.so ls
0x7ffc14931adc: malloc(5) = 0xb40010
0x7ffc1492c6b0: malloc(120) = 0xb40030
0x7ffc1497f61a: malloc(12) = 0xb40010
0x7ffc1492be38: malloc(776) = 0xb400b0
…

printf قد تتصل malloc, ، وهذا هو السبب في أننا نتراجع عن الخطاف مؤقتًا. كن حذرا من هذا إذا كنت عند ربط malloc بأي طريقة.

نصائح أخرى

يمكنك تتبع المكالمات إلى malloc/free مع ltrace:

#include <stdlib.h>

int main (void)
{
  void *ptr = malloc(10);
  free(ptr);

  return 0;
}


$ g++ test.cpp -o test
$ ltrace -e malloc,free ./test
malloc(10)                                       = 0x804a008
free(0x804a008)                                  = <void>
+++ exited (status 0) +++

لتتبع المكالمات الجديدة/الحذف دون إعادة تجميع ، من المحتمل أن تحتاج إلى استخدام شيء مثل LD_PRELOAD لتجاوز المكالمات مع الإصدارات الخاصة بك ، وهذا هو بالضبط ما تسرب هل قد يفعل ما تريد.

هذا المقال (قم بالتمرير لأسفل) يوفر وصفًا واضحًا وموجزًا ​​للغاية لكيفية تجاوز النطاق العالمي new و delete عوامل التشغيل في C++ (لاحظ أنها لا توفر مثالاً لـ new[], ، لكنها متشابهة في المفهوم).

فيما يتعلق بتجاوز malloc والمجاني، نظرًا لأنك تعمل على Linux ومع دول مجلس التعاون الخليجي، فإن أسهل طريقة هي الاستخدام malloc_hook و free_hook. هنا هو وصف جيد جدًا لكيفية عمل هذه الوظائف.

لم أختبر هذا بنفسي ، لكنني متأكد من أن هذه ستعمل:

  • نظرًا لأنك لا ترغب في إعادة تجميع المكتبة ، فقد يتطلب إعطاء إخراج ذي معنى (مقابل "New New Sult for 23 Bytes") الحصول على تتبع المكدس. أتذكر استخدام وظائف للتنقل في المكدس ، لكن لا يمكنني العثور عليها الآن. ربما يمكن لمكالمة إلى System () و Pstack (1) القيام بالخدعة.

  • يمكنك إعادة تعريف المشغل الجديد وحذفه ، ووضع هذا التعريف الجديد قبل مكتبة STD C ++. قد لا يلتقط هذا المكالمات من الحاويات والمكونات القياسية التي تستخدمها المكتبة المعنية. هذا سيتطلب إعادة.

  • يمكن استخدام استخدام ld_preload لتغيير المشغل الجديد وحذفه ديناميكيًا. لن يتطلب هذا إعادة ربط إذا كان تطبيقك مرتبطًا ديناميكيًا.

آمل أن تساعد هذه المؤشرات ، أنا آسف لأنني لا أملك وصفة.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top