Question

Ce que je ne comprends pas C / C ++ est:

Oui, tout le monde utilise pour obtenir executables fulgurantes, de sorte qu'ils compilez avec l'optimisation activée.

Mais pour la compilation des informations de débogage est activée, nous ne nous soucions pas de vitesse. Alors, pourquoi ne pas inclure plus d'informations dans ce mode de compilation, par exemple détecter quelques segfaults avant qu'ils ne surviennent? En effet, insérez un assert(ptr != NULL) avant chaque accès à un ptr de pointeur. Pourquoi ne peut le compilateur faire? Encore une fois, cela devrait être désactivé par défaut, mais il devrait y avoir une telle possibilité, je pense.

EDIT: Certaines personnes ont dit que la détection je l'ai suggéré n'a pas de sens ou ne fait rien que le rapport de segmentation fault ne le font déjà. Mais ce que je pense est juste un abort plus gracieux et instructif, qui imprime le nom du fichier et le numéro de ligne du code incriminé, tout comme un assert() ferait.

Était-ce utile?

La solution

Il y a quelques problèmes majeurs avec votre suggestion:

Quelles sont les conditions que vous voulez le compilateur de détecter? Sous Linux / x86, l'accès peut faire déborder unaligned SIGBUS et la pile peuvent provoquer SIGSEGV, mais dans les deux cas, il est techniquement possible d'écrire l'application pour détecter ces conditions et ne parviennent pas « gracieusement ». les vérifications de pointeurs NULL peuvent être détectés, mais les bugs les plus insidieux sont dus à un accès non valide du pointeur, plutôt que des pointeurs de NULL.

Les langages de programmation C et C ++ offrent une flexibilité suffisante de sorte qu'il est impossible pour une durée d'exécution de déterminer avec succès à 100% si une adresse aléatoire donnée est un pointeur valide d'un type quelconque.

Que voulez-vous l'environnement d'exécution à faire quand il détecte cette situation? Il ne peut pas corriger le comportement (à moins que vous croyez à la magie). Il ne peut continuer d'exécuter ou de sortie. Mais attendez une minute ... c'est ce qui se passe déjà lorsqu'un signal est livré! Le programme sort, un vidage de mémoire est généré, et ce vidage de la mémoire peut être utilisée par les développeurs d'applications pour déterminer l'état du programme lorsqu'il est écrasé.

Qu'est-ce que vous préconisez sonne vraiment comme vous voulez exécuter votre application dans un débogueur (gdb) ou par une certaine forme de virtualisation (valgrind). Cela est déjà possible, mais cela n'a aucun sens de le faire par défaut, car il fournit aucun avantage aux non-développeurs.

Mise à jour pour répondre aux commentaires:

Il n'y a aucune raison de modifier le processus de compilation pour les versions de débogage. Si vous avez besoin d'une version de débogage « douce » de l'application, vous devez exécuter à l'intérieur d'un débogueur. Il est très facile d'envelopper votre exécutable dans un script qui le fait pour vous en toute transparence.

Autres conseils

Qu'est-ce que le programme devrait faire dans ce cas? Si elle informe l'utilisateur d'un bogue, alors c'est ce que le fait segfault.

S'il est censé continuer et éviter le bug, comment savoir quoi faire?

Sans compter que si elle en quelque sorte savoir magie comment continuer correctement, alors vous avez un bug dans votre version release (debug sont destinés à vous aider à identifier et corriger les bugs - ne pas les cacher).


En réponse à l'information supplémentaire ajoutée à la question (je suppose que j'ai mal compris votre intention):

  

ce que je pense est juste un abort plus gracieux et instructif, qui imprime le nom du fichier et le numéro de ligne du code incriminé, tout comme un assert () ferait l'affaire.

Ceci est quelque chose que le compilateur pourrait faire - comme vous le dites, le compilateur serait essentiellement d'insérer automatiquement un assert() où un pointeur a été déréférencé. Cela pourrait ajouter assez de manière significative à la taille d'une version de débogage, mais il serait probablement encore acceptable pour beaucoup (ou la plupart) des fins. Je pense que ce serait une option raisonnable pour un compilateur de fournir.

Je ne suis pas sûr de ce que les fournisseurs compilateur dire ... Peut-être poster une demande Connect site de Microsoft pour la produit de VC et de voir ce qu'ils disent.

Je suis d'accord avec Michael Burr que cela ne fait pas vraiment ou aider à quoi que ce soit.

En outre, cela ne fonctionne toujours pas pour les pointeurs ballants qui ont tendance à être à suivre beaucoup plus insidieuse et difficile vers le bas que les pointeurs nuls.

Au moins avec des pointeurs nuls, il est assez simple pour vous assurer qu'ils sont valides avant de les déréférencer.

Je pense que l'affiche originale veut l'application pour arrêter dans le débogueur. Vous auriez accès à toutes les variables de la pile et la pile vous donc avoir une chance de comprendre pourquoi votre programme est dans cet état.

Si vous développez en C / C ++, un gestionnaire de mémoire de débogage peut vous faire économiser une tonne de temps. les dépassements de mémoire tampon, l'accès supprimé la mémoire, les fuites de mémoire, etc. sont assez faciles à trouver et corriger. Il existe plusieurs sur le marché ou vous pouvez passer 2 ou 3 jours pour écrire votre propre et d'obtenir 90% de la fonctionnalité nécessaire. Si vous écrivez des applications sans eux, vous faites votre travail beaucoup plus difficile qu'il doit être.

Il y a une raison simple assert(ptr != NULL) ne fonctionnera pas avant le déréférencement d'un pointeur ne fonctionne pas: Pas tous les pointeur invalide (même ceux qui ont commencé la vie comme NULL) est en fait égal à 0

.

Considérons d'abord le cas où vous avez un struct avec plusieurs membres:

struct mystruct {
    int first;
    int second;
    int third;
    int fourth;
};

Si vous avez un ptr de pointeur vers mystruct et vous essayez d'accéder ptr->second, le compilateur va générer du code que les annonces 4 (en supposant des nombres entiers 32 bits) à ptr et accéder à cet emplacement de mémoire. Si ptr est 0, l'emplacement de la mémoire réelle sera 4. accessible C'est encore invalide, mais ne serait pas pris par une simple affirmation. (Le compilateur pouvait raisonnablement attendre de vérifier l'adresse de ptr avant d'ajouter 4, dans ce cas, l'affirmation serait l'attraper.)

En second lieu, considérons le cas où vous avez un tableau de struct mystruct et vous passez un élément arbitraire à une autre fonction. Si vous essayez d'accéder au deuxième élément du tableau, il commencera à 16 octets au-delà du premier pointeur. Il n'y a aucun moyen que le compilateur pourrait raisonnablement censé faire ce que vous voulez de manière fiable dans tous les cas, sans attraper arithmétique pointeur légitime.

Qu'est-ce que vous voulez vraiment faire est d'utiliser le système d'exploitation et le matériel pour attraper accès mémoire invalide et non alignés et de tuer votre application, puis déterminer comment obtenir les informations de débogage dont vous avez besoin. Le plus simple est de simplement courir à l'intérieur d'un débogueur. Si vous utilisez gcc sous Linux, voir comment générer un stacktace quand mes C ++ application se bloque . Je suppose qu'il existe des moyens semblables à faire la même chose avec d'autres compilateurs.

Il est déjà l'équivalent d'un assert (PRT! = NULL) comme une partie du système d'exploitation. Voilà pourquoi vous obtenez une erreur de segmentation au lieu d'écraser les données importantes importantes à l'adresse 0 et vraiment chambouler le système.

Étant donné que vous avez un fichier de symboles pour votre exécutable, il est possible de cartographier l'emplacement de l'accident à un numéro de ligne. Le débogueur fait pour vous si vous êtes en cours d'exécution, il dans le débogueur, comme d'autres l'ont mentionné. Visual C ++ offre même « juste à temps » mise au point où, quand le programme se bloque, vous pouvez joindre un débogueur au processus écrasé pour voir où est le problème.

Cependant, si vous voulez avoir cette fonctionnalité sur les machines où Visual C ++ n'est pas installé, il est encore possible de le faire avec un certain codage. Vous pouvez configurer un gestionnaire d'exception en utilisant SetUnhandledExceptionFilter qui sera appelée lorsque votre programme se bloque. Dans le gestionnaire, vous pouvez consulter le dossier d'exception et utiliser SymGetLineFromAddr64 pour déterminer quelle ligne source qui exécutait. Il existe de nombreuses fonctions dans la bibliothèque « d'aide de débogage » qui vous permet d'extraire toutes sortes d'informations. Voir les articles sur MSDN , et aussi la articles sur www.debuginfo.com .

Alors vous dites que avant que le système renvoie une erreur, il doit lancer une erreur .... vous avertir de l'erreur imminente?

Qu'est-ce que le point soit? Quand je reçois une erreur de segmentation, je sais que cela veut dire que je suis une erreur de segmentation. Je ne suis pas besoin d'un autre message disant d'abord « vous allez maintenant obtenir un segfault ».

Suis-je manque complètement le point ici? : P

Edit: Je vois ce que vous entendez dans votre édition, mais il est pas facile à mettre en œuvre. Le problème est que ce n'est pas le compilateur ou la langue ou l'exécution qui décide ce qui devrait se produire si vous accédez à un mauvais pointeur. La langue fait officiellement aucune promesse ou des garanties à ce sujet. Au lieu de cela, les incendies OS hors une erreur, sans savoir que c'est un exécutable de débogage, sans savoir quel numéro de ligne déclenché le problème, ou quoi que ce soit d'autre. La seule chose que cette erreur est dit « vous avez essayé d'accéder à l'adresse X, et je ne peux pas permettre cela. Die ». Que doit faire le compilateur faire avec ça?

Alors, qui devrait générer ce message d'erreur utile? Et comment? Le compilateur peut le faire, bien sûr, mais l'emballage tous un accès unique pointeur dans la gestion des erreurs, afin d'assurer que si une violation segfault / accès se produit, nous l'attraper, et déclencher une assertion à la place. Le problème est, ce serait lent ridiculement . Pas seulement « trop lent pour la libération », mais « trop lent pour être utilisable ». Il suppose également que le compilateur a accès à tout le code que vous appelez dans. Que faire si vous appelez une fonction dans une bibliothèque tiers? Pointer accès à l'intérieur qui ne peut pas être enveloppées dans le code de gestion des erreurs, car le compilateur ne génère pas de code pour cette bibliothèque.

L'OS peut le faire, en supposant qu'il était prêt / capable de charger les fichiers de symboles pertinents, en quelque sorte détectez si oui ou non vous êtes en cours d'exécution d'un exécutable de débogage et ainsi de suite ... Juste pour que ce peut imprimer un numéro de ligne. Parlez de overengineering. Ceci est à peine le travail du système d'exploitation.

Et enfin, qu'est-ce que vous gagner en faisant cela? Pourquoi ne pas simplement lancer votre débogueur? Il casse automatiquement quand quelque chose comme cela arrive, vous donner son numéro de ligne précise et tout le reste.

pourrait être fait, mais ce serait terriblement compliqué et implique à la fois le compilateur et le système d'exploitation et le bénéfice serait extrêmement faible. Vous obtiendrez une boîte de pop-up vous indiquant les informations que votre débogueur est déjà en mesure de vous le dire. Et avec cette information, vous auriez alors ... le feu votre débogueur de toute façon pour savoir ce qui a mal tourné.

Bonne idée, mais seulement dans un cas particulier. C'est avant vous déréférencer un pointeur funciton. La raison en est que le débogueur toujours botter, mais après déréférencement d'un pointeur de fonction null la pile est prise. Par conséquent, vous avez des difficultés à trouver le code incriminé. Si l'appelant vérifié avant d'appeler, le débogueur serait en mesure de vous donner une pile complète.

Une vérification plus générique serait de voir si les points de pointeur vers la mémoire qui est exécutable. NULL est pas, mais de nombreux systèmes d'exploitation peuvent également utiliser les fonctions de CPU pour faire des segments de mémoire spécifiques non exécutable.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top