Opérateur de surcharge globale nouveau / supprimer dans MinGW

Je souhaite surcharger de nouveaux opérateurs / supprimer des applications dans mon application pour intercepter toutes les memory leaks. Cela fonctionne très bien sous Linux. Mais j’ai un problème sous Windows. La nouvelle surcharge / suppression ne fonctionne que pour .exe mais pas pour les appels à partir de fichiers .dll. De plus, si un object est créé dans mon code mais est en train de supprimer du fichier .dll, cela entraîne le blocage de l’application. La référence ici dit

Les versions (1 à 8) sont remplaçables: une fonction non membre fournie par l’utilisateur avec la même signature définie n’importe où dans le programme, dans n’importe quel fichier source, remplace la version par défaut. Sa déclaration n’a pas besoin d’être visible.

J’ai écrit une application de modèle Qt minimale pour tester cela. Ici mainwindow.cpp:

#include "mainwindow.h" #include "ui_mainwindow.h" #include  #include  // replacement of a minimal set of functions: void *operator new(std::size_t sz) { void *ptr = std::malloc(sz); std::printf("global op new called, size = %zu, pointer = 0x%p\n", sz, ptr); return ptr; } void operator delete(void* ptr) noexcept { std::printf("global op delete called, pointer = 0x%p\n", ptr); std::free(ptr); } MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow) { ui->setupUi(this); } MainWindow::~MainWindow() { delete ui; } 

Sortie:

 global op new called, size = 20, pointer = 0x00c4f608 global op new called, size = 24, pointer = 0x00c4f648 global op new called, size = 16, pointer = 0x00b35bf8 global op new called, size = 24, pointer = 0x00c4f6a8 global op new called, size = 24, pointer = 0x00c4f868 global op new called, size = 24, pointer = 0x00c4f988 global op delete called, pointer = 0x00c4f608 

Il a été testé avec Qt 4.8.7 / GCC 4.8.2 et Qt 5.5.1 / GCC 4.9.2. Alors, comment surcharger globalement nouveau / supprimer dans MinGW?

Post-scriptum J’ai écrit cas de test minimal pour reproduire le problème. Ça me sort

 $ ./main.exe global op new called, size = 4, pointer = 0x003e17b8 global op new called, size = 4, pointer = 0x003e3d68 library delete called, pointer = 0x003e17b8 global op delete called, pointer = 0x003e3d68 

Windows n’est pas Linux et vous devez vous comporter en conséquence.

En termes simples, il est généralement prudent de s’assurer que chaque fichier EXE / DLL gérera sa propre mémoire, c’est-à-dire que la mémoire allouée par un fichier EXE / DLL ne doit être désallouée que par le même fichier EXE / DLL. Cela signifie que lorsqu’une DLL fournit createObj fonction createObj , elle devrait également fournir une fonction destroyObj . Bien entendu, vous n’avez pas à le faire si vous pouvez vous assurer que tous les fichiers EXE et DLL utilisent la même DLL d’exécution (même version et sans exécution statique). Même avec cela, les fichiers EXE et DLL ne partagent pas leur operator new / delete .

Lorsque vous utilisez un débogueur de mémoire, vous devez lier son fichier object à chaque fichier EXE et DLL. Chaque EXE / DLL aura alors ses propres allocateurs de mémoire et détectera par elle-même.

J’ai trouvé la réponse sur GCC Bugzilla – Bug 77726 .

Liu Hao a écrit:

Il n’est pas intéressant de savoir si une bibliothèque de liens dynamics (DLL) sous Windows fonctionne différemment d’un object partagé sous Linux.

Windows ne dispose pas d’un éditeur de liens dynamic tel que ld.so sous Linux. Les symboles dans une DLL sont résolus au moment de la construction, contrairement à Linux, où les symboles dans un responsable de la sécurité sont résolus au moment du chargement. Le chargeur de DLL peut résoudre les symboles en adresses, mais il n’est pas aussi puissant que les éditeurs de liens. Par conséquent, un exécutable ne peut pas utiliser ses symboles forts pour remplacer les symboles faibles déjà résolus dans une DLL.

Si l’utilisateur ne définit pas une fonction de désallocation dimensionnée, celle par défaut de libstdc ++ *. Dll est utilisée. Elle appelle la fonction de désallocation faible, par défaut et non dimensionnée dans la même DLL, qui est le seul candidat possible lors de la création de la DLL. ne peut pas être remplacé.