ส่งออกไปยัง stderr ทุกครั้งที่มีการเรียก malloc/free

ด้วย Linux/GCC/C++ ฉันต้องการบันทึกบางสิ่งเพื่อ stderr ทุกครั้งที่มีการเรียก malloc/free/new/delete ฉันกำลังพยายามทำความเข้าใจการจัดสรรหน่วยความจำของไลบรารี ดังนั้นฉันจึงต้องการสร้างเอาต์พุตนี้ในขณะที่ฉันกำลังรันการทดสอบหน่วย ฉันใช้ valgrind สำหรับการตรวจจับการรั่วไหลของ mem แต่ฉันไม่พบตัวเลือกที่จะทำให้เป็นเพียงแค่บันทึกการจัดสรร

มีความคิดอะไรบ้าง? ฉันกำลังมองหาวิธีแก้ปัญหาที่ง่ายที่สุดที่เป็นไปได้ การคอมไพล์ไลบรารีใหม่ไม่ใช่ตัวเลือก


person twk    schedule 15.11.2008    source แหล่งที่มา


คำตอบ (4)


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'
(the code above)
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 ด้วยวิธีใดก็ตาม

person ephemient    schedule 14.11.2009

คุณสามารถติดตามการโทรไปยัง malloc/ฟรีด้วย 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 เพื่อแทนที่การโทรด้วยเวอร์ชันของคุณเอง นี่คือสิ่งที่ LeakTracer ทำซึ่งอาจทำสิ่งที่คุณต้องการ

person Robert Gamble    schedule 15.11.2008

บทความนี้ (เลื่อนลงไปด้านล่าง) ให้ประโยชน์อย่างมาก คำอธิบายที่ชัดเจนและกระชับเกี่ยวกับวิธีแทนที่ตัวดำเนินการ new และ delete ทั่วโลกใน C++ (โปรดทราบว่าไม่มีตัวอย่างสำหรับ new[] แต่มีแนวคิดคล้ายกัน)

สำหรับการเอาชนะ malloc และฟรี เนื่องจากคุณทำงานบน Linux และ GCC วิธีที่ง่ายที่สุดคือใช้ malloc_hook และ free_hook ที่นี่ เป็นคำอธิบายที่ดีมากเกี่ยวกับวิธีการทำงานของฟังก์ชันเหล่านี้

person Emerick Rogul    schedule 15.11.2008
comment
โซลูชันทั้งสองนี้ดูเหมือนจะต้องมีการคอมไพล์ไลบรารีที่เป็นปัญหาใหม่ - person Robert Gamble; 15.11.2008

ฉันยังไม่ได้ทดสอบด้วยตัวเอง แต่ฉันค่อนข้างมั่นใจว่าสิ่งเหล่านี้จะได้ผล:

  • เนื่องจากคุณไม่ต้องการคอมไพล์ไลบรารีใหม่ การให้เอาต์พุตที่มีความหมาย (เทียบกับเพียง "เรียกใช้ใหม่ขนาด 23 ไบต์") อาจจำเป็นต้องได้รับการติดตามสแต็ก ฉันจำได้ว่าใช้ฟังก์ชันเพื่อนำทางสแต็ก แต่ตอนนี้ฉันหามันไม่เจอ บางทีการเรียกไปยัง system() และ pstack(1) สามารถทำเคล็ดลับได้

  • คุณสามารถกำหนดโอเปอเรเตอร์ใหม่และลบได้ และใส่คำจำกัดความใหม่นี้ไว้ข้างหน้าไลบรารี std c++ สิ่งนี้อาจไม่บันทึกการโทรจากคอนเทนเนอร์และส่วนประกอบมาตรฐานที่ไลบรารีดังกล่าวใช้อยู่ สิ่งนี้จะต้องมีการเชื่อมโยงใหม่

  • ใช้สามารถใช้ LD_PRELOAD เพื่อเปลี่ยนตัวดำเนินการใหม่และลบแบบไดนามิก สิ่งนี้ไม่จำเป็นต้องมีการเชื่อมโยงใหม่หากแอปพลิเคชันของคุณมีการเชื่อมโยงแบบไดนามิก

หวังว่าคำแนะนำเหล่านี้จะช่วยได้ ขออภัยที่ไม่มีสูตร

person coryan    schedule 15.11.2008