Erstellen Sie eine Wrapper-Funktion für malloc und kostenlos in C

Lesezeit: 9 Minuten

Ich versuche, Wrapper-Funktionen für zu erstellen free und malloc in C, um mich über Speicherlecks zu informieren. Weiß jemand, wie man diese Funktionen so deklariert, wenn ich sie anrufe malloc() und free() Es wird meine benutzerdefinierten Funktionen aufrufen und nicht die Standard-Lib-Funktionen?

  • Nebenbei bemerkt, das ist es, was Tools wie Valgrind tun. Wenn Sie lieber etwas Standardmäßiges unter Unix oder Linux verwenden möchten, ist Valgrind eine gute Option.

    – sudo

    21. Juli 2017 um 19:15 Uhr

  • Verwandte: Was ist der LD_PRELOAD-Trick?

    – Gabriel Staples

    28. Juni 2021 um 22:45 Uhr

Benutzeravatar von Alex B
Alex B

Sie haben einige Möglichkeiten:

  1. GLIBC-spezifische Lösung (meistens Linux). Wenn Ihre Kompilierungsumgebung ist glibc mit gccist die bevorzugte Methode zu verwenden Malloc-Haken. Sie können damit nicht nur benutzerdefinierte angeben malloc und freeidentifiziert den Aufrufer aber auch anhand der Rücksendeadresse auf dem Stack.

  2. POSIX-spezifische Lösung. Definieren malloc und free als Wrapper für die ursprünglichen Zuordnungsroutinen in Ihrer ausführbaren Datei, die die Version von libc “überschreiben”. In der Verpackung können Sie das Original aufrufen malloc Implementierung, die Sie mit nachschlagen können dlsym mit RTLD_NEXT handhaben. Ihre Anwendung oder Bibliothek, die Wrapper-Funktionen definiert, muss mit verknüpft werden -ldl.

    #define _GNU_SOURCE
    #include <dlfcn.h>
    #include <stdio.h>
    
    void* malloc(size_t sz)
    {
        void *(*libc_malloc)(size_t) = dlsym(RTLD_NEXT, "malloc");
        printf("malloc\n");
        return libc_malloc(sz);
    }
    
    void free(void *p)
    {
        void (*libc_free)(void*) = dlsym(RTLD_NEXT, "free");
        printf("free\n");
        libc_free(p);
    }
    
    int main()
    {
        free(malloc(10));
        return 0;
    }
    
  3. Linux-spezifisch. Sie können Funktionen aus dynamischen Bibliotheken nicht-invasiv überschreiben, indem Sie sie in der angeben LD_PRELOAD Umgebungsvariable.

    LD_PRELOAD=mymalloc.so ./exe
    
  4. Mac OSX-spezifisch.

    Dasselbe wie Linux, außer dass Sie verwenden DYLD_INSERT_LIBRARIES Umgebungsvariable.

  • Hallo, ich bekomme eine Fehlermeldung, wie kann ich sie lösen? FEHLER: ld.so: Objekt ‘/home/tmp/libjmalloc.so’ von LD_PRELOAD kann nicht vorgeladen werden: ignoriert.

    – Thangaraj

    12. September 2011 um 7:31 Uhr

  • @Thangaraj, ich kann es nicht sagen, das ist ein sehr allgemeiner Fehler. Es kann sein, dass die Datei nicht gefunden oder für die falsche Architektur kompiliert wurde (x86 vs. x86_64) oder die Bibliothek nicht dem Benutzer gehört, dem die ausführbare Datei gehört, wenn das SUID-Bit gesetzt ist und die Bibliothek nicht gehört vom Eigentümer der ausführbaren Datei (andernfalls könnten Sie den Code Ihrer Bibliothek als anderer Benutzer ausführen).

    – Alex B

    12. September 2011 um 11:04 Uhr

  • Option 2 funktioniert gut, bis die Anwendung von valgrind ausgeführt wird und dann alle möglichen seltsamen Probleme auftreten. Ist dies darauf zurückzuführen, dass Valgrind eine ähnliche Überschreibung durchführt und eine Art Konflikt verursacht? Welche Option eignet sich am besten für die Malloc-Verpackung mit Valgrind?

    – davidA

    9. März 2016 um 2:13 Uhr

  • Sie verwenden printf() innerhalb des benutzerdefinierten malloc, aber printf() selbst verwendet malloc. Ich bekomme zum Beispiel Segfaults mit LD_PRELOAD=./malloc.so ls. Erzeugt das nicht eine unendliche Rekursion? Wie können wir den Funktionen in unserem benutzerdefinierten Malloc mitteilen, dass sie das libc-malloc verwenden sollen?

    – phip1611

    6. März 2019 um 21:52 Uhr

  • Wenn Sie überschreiben malloc() und free()anstatt sie einfach zu umschließen, müssen Sie einige besondere Überlegungen berücksichtigen, z. B. dass Sie möglicherweise eine unendliche Rekursion erstellen, wenn Sie aufrufen printf() von innen malloc()wie printf() darf anrufen malloc()die jetzt anruft printf()… für immer bis zum Stapelüberlauf. Siehe meine Antwort hier dazu: „Segmentation fault (core dumped)“ für: „No such file or directory“ für libioP.h, printf-parse.h, vfprintf-internal.c usw

    – Gabriel Staples

    2. Juli 2021 um 4:18 Uhr

Sie können mit LD_PRELOAD Wrapper- und “Overwrite”-Funktionen ausführen – ähnlich wie im zuvor gezeigten Beispiel.

LD_PRELOAD=/path.../lib_fake_malloc.so ./app

Aber ich empfehle, dies “etwas” schlauer zu machen, meine ich Aufruf von dlsym einmal.

#define _GNU_SOURCE
#include <stdio.h>
#include <stdint.h>
#include <dlfcn.h>

void* malloc(size_t size)
{
    static void* (*real_malloc)(size_t) = NULL;
    if (!real_malloc)
        real_malloc = dlsym(RTLD_NEXT, "malloc");

    void *p = real_malloc(size);
    fprintf(stderr, "malloc(%d) = %p\n", size, p);
    return p;
}

Beispiel habe ich hier gefunden: http://www.jayconrod.com/cgi/view_post.py?23 Beitrag von Jay Conrod.

Aber was ich auf dieser Seite wirklich cool fand, ist Folgendes: GNU-Linker bietet eine sinnvolle Option, –wickeln . Wenn ich “man ld” überprüfe, gibt es folgendes Beispiel:

void *
__wrap_malloc (size_t c)
{
    printf ("malloc called with %zu\n", c);
    return __real_malloc (c);
}

Ich stimme ihnen zu, das ist ein “triviales Beispiel” :). Auch dlsym wird nicht benötigt.

Lassen Sie mich einen weiteren Teil meiner “man ld” -Seite zitieren:

--wrap=symbol
       Use a wrapper function for symbol.
       Any undefined reference to symbol will be resolved to "__wrap_symbol".
       Any undefined reference to "__real_symbol" will be resolved to symbol.

Ich hoffe, die Beschreibung ist vollständig und zeigt, wie man diese Dinge benutzt.

  • Hallo, ich bekomme eine Fehlermeldung, wie kann ich sie lösen? FEHLER: ld.so: Objekt ‘/home/tmp/libjmalloc.so’ von LD_PRELOAD kann nicht vorgeladen werden: ignoriert.

    – Thangaraj

    12. September 2011 um 7:30 Uhr

  • Seltsam. In der Vergangenheit hat es funktioniert, derzeit habe ich den gleichen Fehler wie Sie. Wie ich es google, gibt es viele viele ähnliche Fälle. Bitte teilen Sie uns mit, wenn Sie eine Lösung gefunden haben. Ich habe es versucht und konnte nicht – “Datei” zeigt, dass Binärdateien derselbe Bogen sind, also sollte es funktionieren. Es braucht mehr Aufmerksamkeit.

    – Grzegorz Wierzowiecki

    12. September 2011 um 12:30 Uhr

  • Ich hatte ein Problem in zwei Systemen, in einem System habe ich korrigiert, indem ich den relativen Pfad durch den absoluten Pfad ersetzt habe, und im anderen System habe ich immer noch gegraben :). Ich habe einen Zweifel, dass diese Methode für kleine Programme geeignet ist. Angenommen, ich habe ein großes Programm, wie kann ich dann herausfinden, woher (welche Funktion) die malloc-Funktion aufgerufen wird.

    – Thangaraj

    13. September 2011 um 17:23 Uhr

  • Gut, dass Sie geschrieben haben, dass der vollständige Pfad in einer Ihrer beiden Konfigurationen funktioniert. Ich habe ausgecheckt. In meiner Konfiguration funktioniert es nicht, wenn der Pfad Leerzeichen enthält oder zu lang ist. Also einfach, Kopieren Sie libjmalloc.so in /tmp und führen Sie es aus LD_PRELOAD=/tmp/libjmalloc.so ./a.out . Es löst das Problem in meinem Fall. Hilft es bei dir?

    – Grzegorz Wierzowiecki

    13. September 2011 um 22:00 Uhr

  • Haben Sie Eingaben für; Ich habe einen Zweifel, dass diese Methode für kleine Programme geeignet ist. Angenommen, ich habe ein großes Programm, wie kann ich dann herausfinden, woher (welche Funktion) die malloc-Funktion aufgerufen wird.

    – Thangaraj

    14. September 2011 um 4:44 Uhr


Benutzeravatar von user9869932
Benutzer9869932

In meinem Fall musste ich memalign/aligned_malloc unter malloc packen. Nachdem ich andere Lösungen ausprobiert hatte, implementierte ich schließlich die unten aufgeführte. Es scheint gut zu funktionieren.

mymalloc.c.

/* 
 * Link-time interposition of malloc and free using the static
 * linker's (ld) "--wrap symbol" flag.
 * 
 * Compile the executable using "-Wl,--wrap,malloc -Wl,--wrap,free".
 * This tells the linker to resolve references to malloc as
 * __wrap_malloc, free as __wrap_free, __real_malloc as malloc, and
 * __real_free as free.
 */
#include <stdio.h>

void *__real_malloc(size_t size);
void __real_free(void *ptr);


/* 
 * __wrap_malloc - malloc wrapper function 
 */
void *__wrap_malloc(size_t size)
{
    void *ptr = __real_malloc(size);
    printf("malloc(%d) = %p\n", size, ptr);
    return ptr;
}

/* 
 * __wrap_free - free wrapper function 
 */
void __wrap_free(void *ptr)
{
    __real_free(ptr);
    printf("free(%p)\n", ptr);
}
 

In C war die von mir verwendete Methode ähnlich wie:

#define malloc(x) _my_malloc(x, __FILE__, __LINE__)
#define free(x) _my_free(x)

Dadurch konnte ich ohne allzu große Schwierigkeiten die Zeile und Datei erkennen, in der der Speicher zugewiesen wurde. Es sollte plattformübergreifend sein, wird aber auf Probleme stoßen, wenn das Makro bereits definiert ist (was nur der Fall sein sollte, wenn Sie einen anderen Speicherleckdetektor verwenden).

Wenn Sie dasselbe in C++ implementieren möchten, ist die Vorgehensweise etwas länger Komplex aber verwendet den gleichen Trick.

Hier ist eine Reihe von Wrapper-Funktionen, die ich jahrelang verwendet habe (und immer noch tue, wenn ich in C eintauche), um nicht freigegebenen Speicher, mehrfach freigegebenen Speicher, Verweise auf freigegebenen Speicher, Pufferüberläufe/-unterläufe und das Freigeben von Speicher zu erkennen wurde nicht vergeben.

ftp://ftp.digitalmars.com/ctools.zip

Sie sind seit 25 Jahren dabei und haben sich bewährt.

Sie könnten den Makro-Präprozessor verwenden, um malloc neu zu definieren und die mem-Pakete frei zu verwenden, aber ich rate davon ab, da er Bibliotheksaufrufe nicht wie strdup an malloc umleitet.

  • Auth geschützter Link

    – Christoffer Bubach

    30. Dezember 2019 um 9:22 Uhr

Benutzeravatar von Don Wakefield
Don Wakefield

Wenn es Ihr Ziel ist, Speicherlecks zu beseitigen, ist ein einfacherer, weniger aufdringlicher Weg die Verwendung eines Tools wie Valgrind (kostenlos) bzw Reinigen (teuer).

  • Auth geschützter Link

    – Christoffer Bubach

    30. Dezember 2019 um 9:22 Uhr

Roddys Benutzeravatar
Roddy

Wenn Sie Ihre eigenen Funktionen für malloc() und free() definieren und diese explizit mit Ihren Anwendungen verknüpfen, sollten Ihre Funktionen denen in der Bibliothek vorgezogen werden.

Ihre Funktion mit dem Namen „malloc“ kann dann jedoch nicht die malloc-Funktion der Bibliothek aufrufen, da es in „c“ kein Konzept für separate Namespaces gibt. Mit anderen Worten, Sie müssten die Interna von malloc implementieren und sich selbst befreien.

Ein anderer Ansatz wäre, die Funktionen my_malloc() und my_free() zu schreiben, die die Funktionen der Standardbibliothek aufrufen. Dies würde bedeuten, dass jeder Code, der malloc aufruft, geändert werden müsste, um Ihre my_xxx-Funktionen aufzurufen.

  • Und Sie können #define malloc my_malloc verwenden, damit Ihr Code ohne Änderungen funktioniert. Aber Sie müssen bei der Verwendung konsistent sein – verwenden Sie my_malloc nicht, wenn der Speicher in einer Bibliothek freigegeben wird, oder umgekehrt.

    – Markieren Sie Lösegeld

    4. November 2008 um 17:04 Uhr

  • Die Absätze 2 und 3 sind irreführend.

    – Matt Tischler

    12. September 2011 um 23:03 Uhr

  • @Matt Joiner – kannst du das bitte näher erläutern?

    – Roddy

    16. September 2011 um 7:46 Uhr

  • P2: Wenn es Namespaces gäbe, würde es immer noch nichts an der Situation ändern. Auch du kann Rufen Sie anschließend die eigentliche malloc-Funktion auf. Das hat nichts mit C zu tun. P3: Ja, das könntest du, und das würde Aufrufe an malloc/free nicht richtig in Code einhängen, über den du keine Kontrolle hättest. Du kann Weisen Sie den Linker an, Verweise auf andere Namen umzuleiten. Ohne den C-Code zu ändern. Zusammenfassung: Keine der von Ihnen behaupteten Einschränkungen existiert wirklich, und keine der von Ihnen angegebenen Problemumgehungen ist notwendig.

    – Matt Tischler

    16. September 2011 um 9:13 Uhr


  • @Matt – Danke: Malloc-Hooks und –Wrap waren mir nicht bekannt, ABER sie sind sehr toolchain- und betriebssystemspezifisch. Nur gcc unterstützt sie, AFAICT – und das OP hat kein Betriebssystem oder Tools angegeben. C++-Namespaces könnten einen ähnlichen Hack wie der #define-Ansatz bieten, aber ich würde zustimmen, dass er alles andere als ideal ist und unter dem von Ihnen erwähnten Problem leidet. Im Allgemeinen bin ich immer noch zufrieden mit meiner Antwort.

    – Roddy

    16. September 2011 um 10:54 Uhr


1404250cookie-checkErstellen Sie eine Wrapper-Funktion für malloc und kostenlos in C

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy