2010-08-12 4 views
3

Je tente de remplacer les opérateurs globaux new et delete par XCode 3.2, GCC 4.2, libstdC++ 4.0, version dynamique.Remplacement de libstdC++. Dylib (4.0) opérateurs globaux nouveaux et supprimés sous OSX

J'ai pris les prototypes directement à partir de l'en-tête "nouveau" et les ai implémentés. Ils sont collés ci-dessous.

Le projet est un .plugin donc une lib dynamique. Ce plug-in DOIT déléguer l'allocation aux propres routines alloc/free de l'application principale, qui se trouvent dans un ancien SDK C.

Tous mes propres appels à new/delete avec les allocations std :: list et std :: map sont correctement remplacés, MAIS pas quand std :: vector :: push_back doit augmenter son buffer. Dans ce cas, mon opérateur new n'est pas appelé mais mon opérateur delete est. Je le sais, car j'écris un token dans les quatre premiers octets de tout buffer alloué par mon nouvel opérateur et je vérifie ce jeton dans l'opérateur delete. Voir ci-dessous pour le code incriminé.

extern "C++" 
{ 
__attribute__((visibility("default"))) void* operator new(std::size_t) throw (std::bad_alloc); 
__attribute__((visibility("default"))) void* operator new[](std::size_t) throw (std::bad_alloc); 
__attribute__((visibility("default"))) void operator delete(void*) throw(); 
__attribute__((visibility("default"))) void operator delete[](void*) throw(); 
__attribute__((visibility("default"))) void* operator new(std::size_t, const std::nothrow_t&) throw(); 
__attribute__((visibility("default"))) void* operator new[](std::size_t, const std::nothrow_t&) throw(); 
__attribute__((visibility("default"))) void operator delete(void*, const std::nothrow_t&) throw(); 
__attribute__((visibility("default"))) void operator delete[](void*, const std::nothrow_t&) throw(); 

} 

Le code suivant provoque une assertion quand « yo » est hors de portée, car la mémoire allouée pour le std :: vecteur n'a pas été affecté par mon opérateur nouveau.

{ 
     std::vector<std::string> yo; 
     yo.push_back("yoyoma"); 
     yo.push_back("yoyoma"); 
     yo.push_back("yoyoma"); 
     yo.push_back("yoyoma"); 
    } 

Le code suivant est ok parce que std :: vector :: réserve appelle mon nouvel opérateur:

{ 
     std::vector<std::string> yo; 
     yo.reserve(4); 
     yo.push_back("yoyoma"); 
     yo.push_back("yoyoma"); 
     yo.push_back("yoyoma"); 
     yo.push_back("yoyoma"); 
    } 

GBD (débogueur) ne laissera pas rencontré pas dans le std :: vector :: Push_back implémentation quand il a besoin de développer le tampon (la méthode est nommée _M_insert_aux). Tout ce que je sais, c'est que mon opérateur new n'est jamais appelé depuis std :: vector :: push_back.

La solution de contournement ci-dessus ne peut pas être appliquée à toutes les bibliothèques tierces que j'utilise. L'un d'entre eux est un gros utilisateur de push_back.

J'ai essayé de lier statiquement à libstdC++. A mais j'ai le même problème.

Y a-t-il une spécialisation pour std :: vector std :: string> qui n'utilise pas le nouvel opérateur global?

BTW cela a fonctionné parfaitement sur windows avec VS9.

+0

Un moyen plus fiable de vérifier si vous recevez un appel est d'insérer un point d'arrêt avant d'appeler l'API de l'application. – Potatoswatter

Répondre

0

Je ne sais pas exactement comment faire exactement ce que vous demandez, mais vous pouvez obtenir votre propre sémantique d'allocation dans la STL en utilisant un allocateur personnalisé.

http://www.cplusplus.com/reference/std/memory/allocator/

Je pense que je me souviens quand je regardais Hans-Bohen GC pour C++ que la bibliothèque remplacerait nouvelle/supprimer une version GC mais il fallait encore passer un allocateur aux structures STL vous souhaite utiliser.

De plus, il peut y avoir du code dans les bibliothèques que vous utilisez en utilisant malloc. Quelque chose à quoi penser.

0

_M_insert_aux est en vector.tcc ce qui ne fonctionne pas bien avec GCC. Cependant, une analyse rapide montre qu'il appelle l'allocateur correctement, tout comme les autres méthodes.

pointer __new_start(this->_M_allocate(__len)); 

Vous pouvez essayer de définir un point d'arrêt dans votre operator new, la définition d'un allocateur personnalisé (vous pouvez tirer de std::allocator) qui imprime le débogage de sortie, ou définir un point d'arrêt dans new_allocator.h:91 où la bibliothèque doit appeler votre remplacement.

+0

L'implémentation dans vector.tcc est très cosher. En fait, j'étais en mesure d'intervenir dans ce code lors du débogage d'une application console simple. Je ne sais pas pourquoi GDB ne trouvera pas le code source lors du débogage d'un .dylib. –

0

L'explication la plus probable est que l'implémentation interne de std :: vector de GCC inclut des surcharges supplémentaires de nouvelles. MSVC a de nombreuses nouvelles surcharges de l'opérateur. Vous devrez déchirer le code source ou créer un nouvel allocateur personnalisé.

+0

GCC ne fait pas cela. – Potatoswatter

1

J'ai finalement résolu mon problème en utilisant la technique de George Costanza: faire le contraire. Au lieu d'essayer de rendre mes opérateurs nouveaux et de les supprimer visibles, je les ai complètement cachés.

L'astuce est de mettre ces derniers dans tous les libs statiques & dans les paramètres de l'ensemble:

  • Set C++ Standard Library Type: statique
  • Symboles cachés par défaut: coché
  • Fix & Continuer: décoché (très important sinon désactiver silencieusement le réglage précédent)

et de faire un nettoyage tous & b Parce qu'avec XCode 3.2, il suffit de cliquer sur Build après avoir changé ces paramètres.

De toute évidence, j'ai changé l'opérateur de nouveaux prototypes & suppression à:

#pragma GCC visibility push(hidden) 

extern "C++" 
{ 
    void* operator new(std::size_t) throw (std::bad_alloc); 
    void* operator new[](std::size_t) throw (std::bad_alloc); 
    void operator delete(void*) throw(); 
    void operator delete[](void*) throw(); 
    void* operator new(std::size_t, const std::nothrow_t&) throw(); 
    void* operator new[](std::size_t, const std::nothrow_t&) throw(); 
    void operator delete(void*, const std::nothrow_t&) throw(); 
    void operator delete[](void*, const std::nothrow_t&) throw(); 
} // extern "C++" 

#pragma GCC visibility pop 

Non Pourquoi ça marche? Doit avoir les deux Static + Hidden Symbols pour fonctionner. Il semble protéger mon plug-in bundle des implémentations de spécialisations STL qui ont souligné leurs allocateurs.

Notez également que cela s'est produit uniquement dans un plug-in de bundle chargé dynamiquement à partir d'une grosse application. Dans un projet .dylib trivial appelé à partir d'une application de la console tout a bien fonctionné avec tous les paramètres.

Questions connexes