63 votes

Ce qui est le plus difficile de bug-vous déjà trouvé et corrigé?

Ce qui fait qu'il est difficile à trouver? Comment avez-vous le retrouver?

Pas assez proche de proche, mais voir aussi
http://stackoverflow.com/questions/175854/what-is-the-funniest-bug-youve-ever-experienced

201voto

sharkin Points 4935

Un jpeg de l'analyseur, en cours d'exécution sur une caméra de surveillance, qui s'est écrasé à chaque fois que le PDG de la compagnie entra dans la chambre.

100% reproductible d'erreur.

Je ne plaisante pas!

C'est pourquoi:

Pour vous qui ne connaissez pas beaucoup sur la compression JPEG - l'image est une sorte de décomposer en une matrice de petits blocs qui sont ensuite encodés à l'aide de la magie etc.

L'analyseur étouffé lorsque le chef de la direction est entré dans la salle, parce qu'il avait toujours un t-shirt avec un motif carré sur elle, ce qui a déclenché certains cas spécial du contraste et de la limite de bloc algorithmes.

Vraiment classique.

115voto

James Curran Points 55356

Ce n'est pas arrivé à moi, mais un ami m'en a parlé.

Il avait pour déboguer une application qui plante très rarement. Il ne serait d'échouer sur les mercredis-en septembre, après la 9e. Oui, 362 jours de l'année, il était beau, et trois jours sur l'année, le programme se bloque immédiatement.

Il serait le format de la date "le mercredi, septembre 22 2008", mais la mémoire tampon a un caractère trop court -- donc, il ne ferait que provoquer un problème quand vous avez eu une à 2 chiffres DOM sur une journée avec le nom le plus long du mois avec le nom le plus long.

60voto

James Curran Points 55356

Cela nécessite de connaître un peu de Z-8000 assembleur, que je vais expliquer que nous allons.

Je travaillais sur un système embarqué (Z-8000 assembleur). Une autre division de l'entreprise a été la construction d'un système différent sur la même plate-forme, et avait écrit une bibliothèque de fonctions, qui, je l'utilise également sur mon projet. Le bug, c'est que chaque fois que j'ai appelé une fonction, le programme s'est écrasé. J'ai vérifié toutes mes entrées; ils étaient beaux. Ça devait être un bug dans la bibliothèque, à l'exception que la bibliothèque avait été utilisé (et a fonctionne bien) en milliers de POS sites à travers le pays.

Maintenant, Z-8000 Processeurs 16 registres 16 bits, R0, R1, R2 ...R15, qui peuvent également être traités comme des 8 registres 32 bits, nommé RR0, RR2, RR4..RR14 etc. La bibliothèque a été écrit à partir de zéro, refactoring un tas de vieux bibliothèques. Il était très propre et suivi strict des normes de programmation. Au début de chaque fonction, chaque registre qui serait utilisé dans la fonction a été poussé sur la pile, afin de préserver sa valeur. Tout a été soigné et bien rangé, c'était parfait.

Néanmoins, j'ai étudié l'assembleur d'inscription à la bibliothèque, et j'ai remarqué quelque chose d'étrange à propos de cette fonction --- Au début de la fonction, il a POUSSER RR0 / PUSH RR2 et à la fin de a POP RR2 / POP R0. Maintenant, si vous n'avez pas suivi, il a dépassé les 4 valeurs sur la pile au début, mais seulement supprimé 3 d'entre eux à la fin. C'est une recette pour un désastre. Il y a une valeur inconnue sur le haut de la pile, où l'adresse de retour. La fonction ne pouvait pas travailler.

Sauf, je vous rappelle, que c'ÉTAIT le travail. Il a été appelé des milliers de fois par jour sur des milliers de machines. Il n'est pas possible de ne PAS fonctionner.

Après un certain temps de débogage (qui n'était pas facile en assembleur sur un système embarqué avec les outils du milieu des années 1980), il serait toujours bloquer sur le retour, parce que la mauvaise valeur a été de l'envoyer à une adresse au hasard. De toute évidence, j'ai eu pour déboguer l'application développée, de comprendre pourquoi il ne l'a pas manqué.

Eh bien, rappelez-vous que la bibliothèque a été très bon sur la préservation des valeurs dans les registres, donc une fois que vous mettez une valeur dans le registre, il y est resté. R1 avait 0000. Il aurait toujours 0000 lorsque cette fonction a été appelée. Le bug donc à gauche 0000 sur la pile. Ainsi, lorsque la fonction se termine, il va sauter à l'adresse 0000, qui s'est trouvé être un RET, qui pop la valeur suivante (la bonne adresse de retour) hors de la pile, et sauter à la. Les données parfaitement masqué le bug.

Bien sûr, dans mon application, j'ai eu une valeur différente en R1, il vient de tomber en panne....

50voto

Thorsten79 Points 7975

C'était sur Linux, mais qui pourrait être arrivé sur pratiquement n'importe quel OS. Aujourd'hui, la plupart d'entre vous sont probablement familiers avec l'API socket BSD. Nous sommes heureux de l'utiliser année après année, et il fonctionne.

Nous avons travaillé sur une application massivement parallèle qui aurait de nombreux sockets ouverts. Pour tester son fonctionnement, nous avons eu une équipe de test qui permettrait d'ouvrir des centaines et parfois plus d'un millier de connexions pour le transfert de données. Avec le plus grand nombre de canaux de notre application serait commencer à montrer le comportement bizarre. Parfois, il vient de tomber en panne. L'autre fois nous avons eu des erreurs qui ne pouvaient tout simplement pas être vrai (par exemple, accepter() pour retourner le même descripteur de fichier sur les appels ultérieurs qui, évidemment, a entraîné le chaos.)

Nous avons pu voir dans les fichiers journaux que quelque chose allait mal, mais c'était incroyablement dur à cerner. Tests avec Rational Purifier dit rien était faux. Mais quelque chose clochait. Nous avons travaillé sur cela pendant des jours et suis de plus en plus frustré. C'était un showblocker parce que le déjà négocié test de causer des ravages dans l'application.

Que l'erreur ne s'est produite en haute charge de situations, j'ai vérifié tout ce que nous avons fait avec les sockets. Nous n'avions jamais testé élevé de cas de charge dans les Purifier, car il n'était pas possible dans une mémoire intensive de la situation.

Finalement (et heureusement) je me suis souvenu que dans le grand nombre de sockets peut-être un problème avec select() qui attend les modifications de l'état sur les sockets (peut lire / peut écrire / erreur). Bien sûr, notre application a commencé à faire des ravages exactement le moment où il atteint le descripteur de socket avec 1025. Le problème est que select() fonctionne avec peu paramètres du champ. Les champs de bits sont remplis par des macros FD_SET() et ses amis qui NE vérifient PAS LEURS PARAMÈTRES DE VALIDITÉ.

Donc, chaque fois que nous avons eu plus de 1 024 descripteurs (chaque OS a ses propres limites, Linux vanille amandes 1024, la valeur réelle est définie comme FD_SETSIZE), le FD_SET macro ferait un plaisir de les remplacer son champ de bits et d'écrire les ordures dans la structure suivante dans la mémoire.

J'ai remplacé tous les appels à select() avec poll (), qui est une bonne alternative à l'arcane appel select (), de charge élevée et les situations n'ont jamais été un problème everafter. Nous avons été chanceux car toutes les sockets de manutention ont été dans un cadre de classe où 15 minutes de travail pourrait résoudre le problème. Il aurait été bien pire si les appels à select() a été aspergé de tous les coins du code.

Leçons apprises:

  • même si une fonction de l'API est de 25 ans et tout le monde l'utilise, il peut avoir des coins sombres vous ne connaissez pas encore

  • décochée mémoire écrit de l'API de macros sont MAL

  • un outil de débogage comme Purifier ne peut pas résoudre toutes les situations, surtout quand une grande quantité de mémoire est utilisée

  • Toujours avoir un cadre pour votre application si possible. En l'utilisant, non seulement augmente la portabilité, mais vous aide également dans le cas de l'API de bugs

  • de nombreuses applications d'utiliser select() sans penser à la prise de limite. Donc, je suis sûr que vous pouvez causer des bugs dans BEAUCOUP de logiciels populaires simplement à l'aide de nombreux de nombreux supports. Heureusement, la plupart des applications n'auront jamais plus de 1024 sockets.

  • Au lieu d'avoir une sécurité de l'API, de l'OS développeurs, comme pour mettre le blâme sur le développeur. Le Linux, sélectionnez (en) page de man dit

"Le comportement de ces macros est undefined si un descripteur de valeur est inférieur à zéro ou supérieur ou égal à FD_SETSIZE, qui est normalement au moins égal au nombre maximum de descripteurs pris en charge par le système".

C'est trompeuse. Linux peut ouvrir plus de 1024 sockets. Et le comportement est absolument bien définis: en Utilisant les valeurs de la ruine de l'application en cours d'exécution. Au lieu de faire les macros résisté à des valeurs illégales, les développeurs ont tout simplement écraser les autres structures. FD_SET est mis en œuvre qu'en ligne de l'assemblée(!) dans le linux les en-têtes et permettra d'évaluer à un seul assembleur instruction écrire. Pas la moindre vérification des limites qui se passe n'importe où.

Pour tester votre application, vous pouvez gonfler artificiellement le nombre de descripteurs utilisés par programmation l'ouverture FD_SETSIZE des fichiers ou des prises directement après le main (), puis l'exécution de votre application.

Thorsten79

43voto

mkClark Points 648

Le mien était un problème matériel...

Retour dans la journée, j'ai utilisé un DEC VaxStation avec un 21" CRT moniteur. Nous avons déménagé dans un laboratoire de notre nouveau bâtiment, et installé deux VaxStations dans les coins opposés de la pièce. A la mise sous tension,mon écran clignotait comme une discothèque (ouais, c'était les années 80), mais le moniteur n'a pas.

D'accord, de swaps de moniteurs. L'autre moniteur (maintenant connecté à mon VaxStation) vacillait, et mon ancien moniteur (déplacé à travers la pièce) n'a pas.

Je me suis souvenu que des tubes cathodiques moniteurs ont été susceptable à des champs magnétiques. En fait, ils ont été très susceptable à 60 Hz champs magnétiques alternatifs. J'ai immédiatement soupçonné que quelque chose dans ma zone de travail a été génératrice de 60 Hz alterating champ magnétique.

Au début, je me doutais de quelque chose dans ma zone de travail. Malheureusement, le moniteur vacillait, même lorsque tous les autres de l'équipement est hors tension et débranché. À ce moment, j'ai commencé à soupçonner quelque chose dans le bâtiment.

Pour tester cette théorie, nous avons converti la VaxStation et ses 85 lb moniteur dans un système portable. Nous avons placé l'ensemble du système sur un rollaround panier, et relié à 100 pieds de l'orange de la construction de la rallonge. Le plan était d'utiliser cette installation comme un portable mesureur de champ,afin de trouver la fausse pièce d'équipement.

Rouler le moniteur autour de nous confondre totalement. Le moniteur clignotait dans exactement la moitié de la salle, mais pas de l'autre côté. La chambre était dans la forme d'un carré, avec des portes dans les coins opposés, et l'écran clignotait sur un côté de la diagnal ligne reliant les portes, mais pas sur l'autre côté. La salle est entourée sur ses quatre côtés par des couloirs. Nous avons poussé le moniteur dans les couloirs, et le scintillement de l'arrêté. En fait, nous avons découvert que le scintillement, ne s'est produite dans une triangulaire en forme de moitié de la pièce, et nulle part ailleurs.

Après une période de confusion totale, je me suis souvenu que la chambre avait un double plafond, système d'éclairage, avec des interrupteurs à chaque porte. À ce moment, j'ai compris ce qui n'allait pas.

J'ai déplacé le moniteur à la moitié de la salle avec le problème, et a transformé le plafond lights off. Le scintillement de l'arrêté. Quand j'ai tourné les lumières, le scintillement de la reprise. Tournant la lumière et hors de la lumière de l'interrupteur, transformé le scintillement sur ou à l'intérieur de la moitié de la salle.

Le problème a été causé par quelqu'un coupe les coins ronds quand ils câblé les lumières du plafond. Lorsque le câblage en place dans les deux sens sur un interrupteur de circuit d'éclairage, vous exécutez une paire de câbles entre les contacts de l'interrupteur SPDT, et un seul fil de la commune sur un interrupteur, à travers les lumières, et plus de la commune sur l'autre interrupteur.

Normalement, ces fils sont bundeled ensemble. Ils partent comme un groupe d'un switchbox, courir à la surcharge de support au plafond, et sur une autre case. L'idée, c'est que tous les porteurs de courant de fils sont bundeled ensemble.

Lorsque le bâtiment a été câblé, le seul fil entre les commutateurs et de la lumière a été acheminé à travers le plafond, mais le fils de voyager entre les commutateurs ont été acheminés à travers les murs.

Si tous les fils a couru proches et parallèles les uns aux autres, alors le champ magnétique généré par le courant dans un fil a été annulé par le champ magnétique généré par l'égale et opposée de courant à proximité, dans un fil. Malheureusement, la façon dont les lumières ont été programmés signifie que la moitié de la salle était essentiellement à l'intérieur de un grand, à un seul tour primaire du transformateur. Lorsque les lumières étaient allumé, le courant circulait dans une boucle, et le pauvre moniteur a été essentiellement assis à l'intérieur d'un grand électro-aimant.

Morale de l'histoire: le chaud et Le neutre lignes d'alimentation CA de câblage sont à côté les uns des autres pour une bonne raison.

Maintenant, tout ce que j'avais à faire était d'expliquer à la direction pourquoi ils avaient de refiler une partie de leur nouveau bâtiment...

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X