11
votes

Déterminer l'ordre d'initialisation statique après la compilation?

en C ++, je sais que le compilateur peut choisir d'initialiser les objets statiques dans n'importe quel ordre qu'elle choisit (sous réserve de quelques contraintes) et que, en général, vous ne pouvez pas choisir ou déterminer l'ordre d'initialisation statique.

Cependant, une fois qu'un programme a été compilé, le compilateur doit avoir décidé de la décision de l'ordre d'initialiser ces objets. y a-t-il un moyen de déterminer, d'un programme compilé avec des symboles de débogage, dans quel ordre Les constructeurs statiques seront appelés?

Le contexte est ceci: j'ai un programme considérable qui se sépare soudainement avant la construction principale () lorsqu'il est construit sous une nouvelle boîte à outils. Soit ceci est un problème d'ordre d'initialisation statique, soit quelque chose qui ne va pas avec l'une des bibliothèques de chargement. Cependant, lorsque je débogé avec GDB, l'emplacement du crash est simplement signalé comme une adresse brute sans aucune information ou retour symbolique. J'aimerais décider lequel de ces deux problèmes est en plaçant un point d'arrêt sur le constructeur du tout premier objet statiquement initialisé, mais je ne sais pas comment dire quel objet qui est.


5 commentaires

Avez-vous essayé de recompiler avec le drapeau "-g3"? Cela devrait mettre de nombreux symboles de débogage pour que vous puissiez travailler avec.


C'est la liaison qui détermine la commande finale dans toutes les unités de compilation. Je crois que G ++ a des pragmes qui peuvent aider à définir la commande.


La réponse est très spécifique à la plate-forme et vous avez réussi à garder votre plate-forme un secret. S'il vous plaît, révélez-le, ainsi que la version de GDB que vous avez utilisée.


De plus, veuillez afficher la trace de la pile GDB que vous avez obtenue. Est susceptible de contenir des indices importants.


Juste pour répondre à ceux-ci, c'était Linux / g ++, et il n'y avait littéralement pas de trace de pile que ce soit (juste une seule adresse mémoire), même avec le débogage complet sur le programme et également sur la ou les bibliothèques, y compris la bibliothèque qui a finalement été le problème. Je n'ai toujours aucune idée pourquoi c'était.


6 Réponses :


2
votes

Pourriez-vous initialiser des variables factices dans l'espace statique et mettre des points de rupture sur ces appels de fonction?

extern "C" int breakOnMe () { return 0 };

int break1 = breakOnMe ();
float pi = 3.1415;
int break2 = breakOnMe ();
myClass x = myClass (1, 2, 3);


6 commentaires

Est-il garanti que les variables statiques non-objets seront toujours initialisées avant que des objets statiques?


Dans Linux, les types de POD seront initialisés en les plaçant dans la section de données - ceux-ci seront chargés avant que tout code d'utilisateur ne soit exécuté.


Mais vous ne pouvez pas casser la section de données, la question est donc si un type de pod est initialisé au moyen d'un appel à une fonction (comme avec Break1 et Break2 dans l'exemple de Eduffy), est-ce garanti pour arriver avant que les constructeurs d'objets obtiennent appelé?


@Tyler, non, ils sont initialisés comme les appels de constructeur sont. Dans mes tests limités, ils semblent être initialisés par ordre de déclaration, mais cela peut ne pas être garanti.


@bdonlan: dans une unité de compilation. Cette commande est garantie.


Mais c'est bien sûr tout le problème - j'ai de nombreuses unités de compilation.



11
votes

en G ++ sur Linux, le constructeur statique et la commande destructeurs sont déterminés par des pointeurs de fonction dans les sections .CTORS et .DTors. Notez que, avec suffisamment de débogage disponible, vous pouvez réellement obtenir une backtrage: xxx

Ceci est avec les symboles de débogage pour libc et libstdc ++ installé. Comme vous pouvez le constater, le crash est arrivé ici dans le constructeur FOO :: FOO () pour l'objet statique FOO_INST.

Si vous souhaitez casser dans le processus d'initialisation, vous pouvez alors définir un point d'arrêt sur __do_global_ctors_aux et Passez à travers son désassemblage, je suppose. Ou attendez simplement que cela se bloque pour obtenir le backtrace comme ce qui précède.


1 commentaires

Sur Quelques plates-formes cette réponse est correcte. Sur d'autres plates-formes, c'est faux. Vous ne devriez probablement pas supposer que "le monde entier est fait de binaires elfe".





1
votes

Vous pouvez trouver la commande que les TU sont initialisés à l'aide de modèles comme en surbrillance par cette Question . Il nécessite un petit morceau de code de code à chacun des TU qui vous intéresse:

static const char * SRC_FILE=__FILE__;
#include "order.h"

int main ()
{
}


0 commentaires

0
votes

En réalité, grâce à l'utilisation de singletons, vous pouvez contrôler l'ordre de l'initialisation des objets globaux / statiques de manière assez efficace en C ++.

Par exemple, dites que vous avez: P>

//..some code
global().abc.foo();
//..more code here
global().def.bar();


0 commentaires