MemTrack - Détection de fuites mémoire
Posté le 02/04/2025 19:40
Hello les gens !
Voici un petit système pour détecter les fuites mémoire dynamiques dans un programme Casio utilisant gint, compatible aussi bien en C qu’en C++.
Le but est simple : à la fin du programme, savoir combien de blocs mémoire n'ont pas été libérés, même ceux alloués dans des libs externes.
Fonctionnalités
- Remplace malloc/free et new/delete par une version trackée
- Compatible avec les appels depuis des libs .a
- Affiche automatiquement un message à la fin du programme
- Optionnel, activable/désactivable via CMake
- Aucun outil externe requis
- Ne modifie pas gint ou la libc
Intégration
1. Copier le fichier memtrack.h/.hpp dans votre projet :
#if !defined(MEMTRACK_H) && defined(MEMTRACK_ENABLED)
#define MEMTRACK_H
#include <stdlib.h>
#include <stdio.h>
#include <gint/gint.h>
#include <gint/keyboard.h>
#include <gint/display.h>
#include <gint/kmalloc.h>
#ifdef __cplusplus
extern "C" {
#endif
// --- Compteur global ---
static int memtrack_alloc_count = 0;
void memtrack_init(void)
{
memtrack_alloc_count = 0;
}
// --- malloc/free overrides ---
void* malloc(size_t size)
{
++memtrack_alloc_count;
return kmalloc(size, NULL);
}
void free(void* ptr)
{
--memtrack_alloc_count;
kfree(ptr);
}
void* calloc(size_t count, size_t size) {
++memtrack_alloc_count;
return kmalloc(count * size, NULL);
}
void* realloc(void* ptr, size_t size) {
return krealloc(ptr, size);
}
// --- Report à la fin du programme ---
__attribute__((destructor))
static void memtrack_report_leaks(void)
{
dclear(C_BLACK);
if(memtrack_alloc_count > 0) {
char buffer[64];
snprintf(buffer, sizeof(buffer), "Memory leak: %d block(s)", memtrack_alloc_count);
dprint(1, 1, C_WHITE, buffer);
} else {
dprint(1, 1, C_WHITE, "No memory leaks!");
}
dupdate();
getkey(); // pause
}
#ifdef __cplusplus
}
#endif
// --- Opérateurs C++ ---
#ifdef __cplusplus
#include <new>
void* operator new(std::size_t size)
{
return malloc(size);
}
void* operator new[](std::size_t size)
{
return malloc(size);
}
void operator delete(void* ptr) noexcept
{
free(ptr);
}
void operator delete[](void* ptr) noexcept
{
free(ptr);
}
void operator delete(void* ptr, unsigned int)
{
free(ptr);
}
void operator delete[](void* ptr, unsigned int)
{
free(ptr);
}
#endif // __cplusplus
#endif // MEMTRACK_ENABLED
2. Dans main() : reset du compteur
#include "memtrack.hpp"
int main(void)
{
memtrack_init(); // Ignore les allocations faites avant main()
//code...
return 1;
}
3. Dans CMakeLists.txt
Ajouter en haut cette ligne (ON ou OFF) :
option(MEMTRACK "Enable memory leak tracking" ON)
Et ajouter les lignes suivantes :
if(MEMTRACK)
target_compile_definitions(myaddin PRIVATE MEMTRACK_ENABLED=1)
target_compile_options(myaddin PRIVATE
-fno-builtin-malloc
-fno-builtin-free
-fno-builtin-realloc
-fno-builtin-calloc
-fno-builtin-new
-fno-builtin-delete
)
endif()
Voilà en espérant que cela peut vous être utile
PS : Je me suis cassé la tête à chercher dans tout gint la fonction builtin de malloc et free, j'ai trouvé que ça, s'il y a un problème, signalé le moi
Citer : Posté le 02/04/2025 23:57 | #
Les fonctions internes de gint sont dans kmalloc, après c'est intéressant de toucher à ça que si tu compte faire une pr
Le malloc()/free() standards sont dans la libc, plus précisément dans src/stdlib/
Caltos : G35+EII, G90+E (briquée
Citer : Posté le 03/04/2025 08:29 | #
Pas de problème avec ta méthode, je pense ! Je sais pas comment j'ai raté ça dans ta question précédente. x)
Tu peux même enregistrer file/line avec les allocations en vrai, pour les diagnostics :o
Citer : Posté le 03/04/2025 17:42 | #
Les fonctions internes de gint sont dans kmalloc, après c'est intéressant de toucher à ça que si tu compte faire une pr
Le malloc()/free() standards sont dans la libc, plus précisément dans src/stdlib/
Ouai j'ai vu ça, mais le souci d'utiliser la libc c'est que ça crée une récursion infinie, c'est pour ça que j'ai utilisé kmalloc.
Pas de problème avec ta méthode, je pense ! Je sais pas comment j'ai raté ça dans ta question précédente. x)
Tu peux même enregistrer file/line avec les allocations en vrai, pour les diagnostics :o
Je n'ai pas compris ce que tu veux dire avec file/line ?
Albert Einstein
Citer : Posté le 03/04/2025 17:51 | #
Puisque tu définis tes propres fonctions, tu as l'option d'insérer les macros __FILE__ et __LINE__ en paramètre aux fonctions (au moins pour malloc/free, les opérateurs C++ c'est plus dur sans doute...) et du garder cette info de provenance dans un coin (e.g. les 8 premiers octets de l'allocation) pour qu'en cas de fuite tu puisses dire qui a alloué.
Citer : Posté le 03/04/2025 19:22 | #
Puisque tu définis tes propres fonctions, tu as l'option d'insérer les macros __FILE__ et __LINE__ en paramètre aux fonctions (au moins pour malloc/free, les opérateurs C++ c'est plus dur sans doute...) et du garder cette info de provenance dans un coin (e.g. les 8 premiers octets de l'allocation) pour qu'en cas de fuite tu puisses dire qui a alloué.
J'avais vu ça mais le problème c'est que les macro ne peuvent pas remplacer les fonctions malloc et free qui sont à l'intérieur d'une lib.
Par contre il y a un truc que je ne comprend pas, pourquoi quand je fais un gint_world_switch mon memtrack_alloc_count est reset alors que je fait un leak ((void)image_alloc(20,20,1);) volontairement avant le gint_world_switch ?
[Edit] En fait non c'est bon j'ai trouvé le problème, c'est parce que j'avais oublié de géré calloc
Albert Einstein