Existe-t-il un programme C / C ++ pouvant tomber en panne avant main ()?

Existe-t-il un moyen pour un programme de tomber en panne avant main ()?

Avec gcc, vous pouvez marquer une fonction avec l’ atsortingbut constructeur (ce qui entraîne l’exécution de la fonction avant main ). Dans la fonction suivante, premain sera appelé avant main :

 #include  void premain() __atsortingbute__ ((constructor)); void premain() { fputs("premain\n", stdout); } int main() { fputs("main\n", stdout); return 0; } 

Donc, s’il y a un bogue en premain dans premain vous allez planter avant main .

Oui, au moins sous Windows. Si le programme utilise des DLL, il peut être chargé avant main() démarrage de main() . Les fonctions DllMain de ces DLL seront exécutées avant main() . S’ils rencontrent une erreur, ils peuvent provoquer l’arrêt ou la panne de tout le processus.

Si vous avez un programme C ++, il peut initialiser des variables et des objects via des fonctions et des constructeurs avant que main soit entré. Un bogue dans l’un de ces éléments pourrait entraîner le blocage d’un programme.

certainement en c ++; les objects statiques avec les constructeurs seront appelés avant le principal – ils peuvent mourir

pas sûr de c

ici est échantillon

 class X { public: X() { char *x = 0; *x = 1; } }; X x; int main() { return 0; } 

cela va s’écraser avant principal

La réponse simple est: oui .

Plus précisément, nous pouvons différencier deux causes. Je les appellerai dépendant de l’ implémentation et indépendant de l’implémentation .

Le seul cas qui ne dépend pas du tout de votre environnement est celui des objects statiques en C ++, qui a été mentionné ici. Le code suivant meurt avant main() :

 #include  class Useless { public: Useless() { throw "You can't construct me!"; } }; static Useless object; int main() { std::cout << "This will never be printed" << std::endl; return 0; } 

Plus intéressantes sont les causes dépendantes de la plate-forme . Certains ont été mentionnés ici. L'un des cas mentionnés ci-dessus était l'utilisation de bibliothèques liées dynamicment (DLL dans Windows, SO dans Linux, etc.) - si le chargeur de votre système d'exploitation les chargeait avant main() , cela pourrait entraîner la mort de votre application main() .

Une version plus générale de cette cause parle de toutes les choses que fait le point d'entrée de votre binary avant d'appeler votre point d'entrée ( main() ). Habituellement, lorsque vous construisez votre fichier binary, il y a un bloc de code assez sérieux qui est appelé lorsque le chargeur de votre système d'exploitation commence à exécuter votre fichier binary, et lorsqu'il est terminé, il appelle votre main() . Une chose commune à ce code est l'initialisation de la bibliothèque standard C / C ++. Ce code peut échouer pour plusieurs raisons (pénurie de ressources système qu’il essaie d’allouer).

Un moyen intéressant pour un binary d'exécuter du code avant main() sur Windows est d'utiliser des rappels TLS (google vous en dira plus). Cette technique se trouve généralement dans les logiciels malveillants comme un truc anti-débogage de base (cette astuce utilisée pour tromper ollydbg à l'époque, ne sait pas si c'est toujours le cas).

Le fait est que votre question est en fait équivalente à "y at-il un moyen que le chargement d’un fichier binary provoque l’exécution du code utilisateur avant le code dans main() ?", Et la réponse est que oui, oui!

Tout programme reposant sur des objects partagés (DLL) en cours de chargement avant main peut échouer avant principal.

Sous Linux, la bibliothèque de liens dynamics (ld – *. So) est exécutée pour fournir toutes les dépendances de bibliothèque bien avant le principal. Si des bibliothèques nécessaires ne peuvent pas être localisées, ayez des permissions qui ne vous permettent pas d’y accéder, ne sont pas des fichiers normaux, ou n’ont pas de symbole que l’éditeur de liens dynamics lié à votre programme pensait qu’il devrait avoir il a lié votre programme alors cela peut provoquer un échec.

De plus, chaque bibliothèque peut exécuter du code lorsqu’il est lié. C’est principalement parce que la bibliothèque peut avoir besoin de lier plus de bibliothèques ou peut avoir besoin de lancer des constructeurs (même dans un programme C, les bibliothèques peuvent avoir un C ++ ou quelque chose d’autre qui utilise des constrocteurs). De plus, les programmes standard C ont déjà créé les stdio std, stdout et stderr. Sur de nombreux systèmes, ils peuvent également être fermés. Cela implique qu’ils sont également gratuits (), ce qui implique qu’ils (et leurs tampons) ont été édités, ce qui peut échouer. Cela suggère également qu’ils ont peut-être fait d’autres choses avec les descripteurs de fichiers que ces structures FILE représentent, ce qui pourrait échouer.

D’autres choses qui pourraient éventuellement se produire pourraient être si le système d’exploitation devait gâcher la configuration des variables d’environnement et / ou des arguments de ligne de commande transmis au programme. Le code avant principal est susceptible d’avoir quelque chose avec ces données avant d’appeler main.

Beaucoup de choses se passent avant le principal. Chacun d’entre eux peut échouer de manière fatale.

Je ne suis pas sûr, mais si vous avez une variable globale comme celle-ci:

 static SomeClass object; int main(){ return 0; } 

Le constructeur ‘SomeClass’ pourrait éventuellement planter le programme avant l’exécution principale.

Il y a beaucoup de possibilités.

Tout d’abord, nous devons comprendre ce qui se passe avant que main soit exécutée:

  • Charge de bibliothèques dynamics
  • Initialisation des globales
  • Un des compilateurs, certaines fonctions peuvent être exécutées explicitement

Maintenant, tout cela peut provoquer un crash de plusieurs manières:

  • le comportement non défini habituel (déréférencement d’un pointeur nul, access à la mémoire que vous ne devriez pas …)
  • une exception levée> puisqu’il n’y a pas de catch , la terminate est appelée et la fin du programme

C’est vraiment ennuyeux bien sûr et peut-être difficile à déboguer, et c’est pourquoi vous devriez éviter d’exécuter autant que possible du code avant main et préférez l’initialisation paresseuse si vous le pouvez, ou l’initialisation explicite dans main .

Bien sûr, lorsque la DLL est défaillante et que vous ne pouvez pas la modifier, vous risquez de souffrir.

Sorte de: http://blog.ksplice.com/2010/03/libc-free-world/

Si vous comstackz sans bibliothèque standard, comme ceci: gcc -nostdlib -o hello hello.c

il ne saura pas comment exécuter main () et se plantera.

Les objects globaux et statiques d’un programme C ++ auront leurs constructeurs appelés avant que la première instruction de main () soit exécutée, donc un bogue dans l’un des constructeurs peut provoquer un blocage.

Cela ne peut pas arriver dans les programmes C, cependant.

Cela dépend de ce que vous voulez dire par “avant principal”, mais si vous voulez dire “avant que votre code dans main ne soit réellement exécuté”, alors je peux penser à un exemple: si vous déclarez un grand tableau comme variable locale La taille de ce tableau dépasse l’espace de stack disponible, puis vous risquez d’obtenir un stack overflow lors de l’entrée dans main, avant l’exécution de la première ligne de code.

Un exemple quelque peu artificiel serait:

 int a = 1; int b = 0; int c = a / b; int main() { return 0; } 

Il est peu probable que vous fassiez quelque chose comme ça, mais si vous faites beaucoup de macro-magie, c’est tout à fait possible.

 class Crash { public: Crash( int* p ) { *p = 0; } }; static Crash static_crash( 0 ); void main() { } 

Bien sûr, s’il y a un bogue dans le système d’exploitation ou le code d’exécution. C ++ est particulièrement connu pour ce comportement, mais il peut toujours se produire en C.

Vous n’avez pas dit quelle plateforme / libc. Dans le monde intégré, il y a souvent beaucoup de choses qui s’exécutent avant main() , en grande partie avec la configuration de la plate-forme, qui peuvent mal tourner. (Ou bien si vous utilisez un script de linker funky sur un OS normal, tous les paris sont désactivés, mais je suppose que c’est assez rare.)

certaines librairies d’abstraction de la plateforme remplacent (je ne connais personnellement que les librairies C ++ comme Qt ou ACE, qui le font, mais certaines librairies C font peut-être quelque chose comme ça) “main” int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow ); et configurer des éléments de la bibliothèque, convertir les arguments de la ligne de commande en int argc, char* argv[] normal int argc, char* argv[] et ensuite appeler le int main(int argc, char* argv[]) normal int main(int argc, char* argv[])

Bien sûr, de telles bibliothèques peuvent provoquer un blocage lorsqu’elles ne l’ont pas implémenté correctement (peut-être à cause d’arguments de ligne de commande mal formés).

Et pour les personnes qui ne savent pas à ce sujet, cela peut ressembler à un crash avant la main

J’avais fait face au même problème. La cause principale trouvée était que trop de variables locales (tableaux énormes) étaient initialisées dans le processus principal, entraînant une taille de variables locales supérieure à 1,5 Mo.
Cela se traduit par un grand saut car le pointeur de la stack est assez volumineux et le système d’exploitation détecte ce saut comme non valide et bloque le programme car il pourrait être malveillant.

Pour déboguer ceci.
1. Lancez GDB
2. Ajouter un point d’arrêt au principal
3. démonter le principal
4. Vérifiez les sous $ 0xGGGGGGG,% esp
Si cette valeur GGGGGG est trop élevée, vous verrez le même problème que moi.

Donc, vérifiez la taille totale de toutes les variables locales dans la principale.