Frage

Dies ist ein "Teilen Sie das Wissen?" - Frage.Ich bin daran interessiert, lernen aus Ihren erfolgen und/oder Fehler.

Informationen, die hilfreich sein könnten...

Hintergrund:

  • Kontext:Sprache, Anwendung, Umwelt, etc.
  • Wie wurde der Fehler festgestellt ?
  • Wer oder was identifiziert den Fehler ?
  • Wie Komplex war die Reproduktion der Fehler ?

Die Jagd.

  • Was war Ihr plan ?
  • Welchen Schwierigkeiten sind Sie begegnet ?
  • Wie wurde der problematische code auch endlich gefunden ?

Die Tötung.

  • Wie Komplex war die zu beheben ?
  • Wie haben Sie bestimmen den Umfang der fix ?
  • Wie viel code war in der fix ?

Postmortal.

  • Was war die Ursache technisch ? Pufferüberlauf, etc.
  • Was war die Ursache von 30.000 Fuß ?
  • Wie lange hat der Prozess letztlich nehmen ?
  • Gab es irgendwelche Funktionen negativ beeinflusst durch das Update ?
  • Welche Methoden, tools, Motivation fanden Sie besonders hilfreich ?...schrecklich nutzlos ?
  • Wenn Sie könnten, tun es alle wieder ?............

Diese Beispiele stellen Allgemeine, nicht anwendbar in jeder situation und möglicherweise nutzlos.Bitte jahreszeit so brauchte.

War es hilfreich?

Lösung

Es war tatsächlich in einem Bild-Viewer-Unterkomponenten unserer Bewerbung von Drittanbietern.

Wir stellten fest, dass 2-3 der Benutzer unserer Anwendung häufig die Image-Viewer-Komponente haben würden, die eine Ausnahme auswirft und schrecklich stirbt. Wir hatten jedoch Dutzende anderer Benutzer, die das Problem nie gesehen haben, obwohl die Anwendung für die gleiche Aufgabe den größten Teil des Arbeitstages verwendet wurde. Es gab auch einen Benutzer, der es viel häufiger bekam als der Rest von ihnen.

Wir haben die üblichen Schritte ausprobiert:

(1) ließ sie Computer mit einem anderen Benutzer wechseln, der nie das Problem hatte, den Computer/die Konfiguration auszuschließen. - Das Problem folgte ihnen.

(2) ließ sich in die Anwendung anmelden und als Benutzer arbeiten, der das Problem nie gesehen hat. - Das Problem folgte ihnen immer noch.

(3) hatte den Benutzerbericht, welches Bild sie betrachteten, und richteten einen Testkabelbaum ein, um das Bild tausende Male in schneller Folge zu wiederholen. Das Problem war nicht im Gurt.

(4) ließ ein Entwickler bei den Benutzern sitzen und sie den ganzen Tag beobachten. Sie sahen die Fehler, bemerkten aber nicht, dass sie etwas Außergewöhnliches taten, um sie zu verursachen.

Wir hatten wochenlang Probleme damit, herauszufinden, was die "Fehlerbenutzer" gemeinsam hatten, die die anderen Benutzer nicht taten. Ich habe keine Ahnung, wie, aber der Entwickler in Schritt (4) hatte einen Eureka -Moment auf der Fahrt, um eines Tages Encyclopedia Brown würdig zu arbeiten.

Er erkannte, dass alle "Fehlerbenutzer" linkshändig waren, und bestätigte diese Tatsache. Nur linkshändige Benutzer haben die Fehler, nie Rechte. Aber wie konnte Linkshänder einen Fehler verursachen?

Wir ließen ihn hinsetzen und beobachteten die Linkshänder wieder speziell auf alles, was sie anders machen könnten, und so fanden wir es.

Es stellte sich heraus, dass der Fehler nur stattfand, wenn Sie die Maus in die Pixelspalte im Bildbetrieb in die Spalte der Pixel verschoben haben, während sie ein neues Bild lud (Überlauffehler, da der Anbieter eine 1-R-Berechnung für das Mausover-Ereignis hatte).

Während die Benutzer auf natürliche Weise ihre Hand (und damit die Maus) auf die Tastatur bewegten, haben die Benutzer offenbar auf natürliche Weise die Hand (und damit die Maus) auf die Tastatur gebracht.

Der einzige Benutzer, der zufällig den Fehler bekam, war einer dieser Hinzufügen, die ihre Maus zwanghaft ungeduldig bewegten, während sie auf die nächste Seite wartete. Daher bewegte sie die Maus viel schneller nach rechts und schlug die Das Timing genau richtig, also hat sie es getan, als das Ladungsereignis passierte. Bis wir eine Lösung von der Verkäufer bekamen, sagten wir ihr, dass sie nach Klicken (nächstes Dokument) nur die Maus loslassen und sie erst berühren sollten, bis sie geladen wurde.

Es war fortan in der Legende im Entwicklerteam als bekannt "Der linkshändige Fehler"

Andere Tipps

Dies ist von a lang Vorzeit (die späten 1980er Jahre).

Das Unternehmen, für das ich gearbeitet habe, schrieb ein CAD -Paket (in Forran), das auf verschiedenen Unix -Workstations (HP, Sun, Silcon Graphics usw.) lief. Wir haben unser eigenes Dateiformat verwendet, um die Daten zu speichern, und als das Paket gestartet wurde, war der Speicherplatz knapp, sodass viele Bit -Verschiebungen verwendet wurden, um mehrere Flags in Entitätsheadern zu speichern.

Die Art der Entität (Zeile, Bogen, Text usw.) wurde beim Speichern mit 4096 (glaube ich) multipliziert. Zusätzlich wurde dieser Wert negiert, um ein gelöschtes Element anzuzeigen. Um den Typ zu bekommen, den wir hatten, hatten wir Code:

type = record[1] MOD 4096

Auf jeder Maschine mit Ausnahme eines, die ± 1 (für eine Linie), ± 2 (für einen Bogen) usw. ergab, konnten wir dann das Schild überprüfen, um zu sehen, ob gelöscht wurde.

Auf einer Maschine (HP, glaube ich) hatten wir ein seltsames Problem, bei dem die Behandlung von gelöschten Gegenständen vermasselt wurde.

Dies geschah in den Tagen vor IDEs und visueller Debugger, so dass ich Trace -Anweisungen einfügen und protokollieren musste, um das Problem aufzuspüren.

Ich stellte schließlich fest, dass es daran lag, während jeder andere Hersteller implementierte MOD so dass -4096 MOD 4096 führte zu -1 HP hat es mathematisch richtig implementiert, damit -4096 MOD 4096 führte zu -4097.

Am Ende musste ich die gesamte Codebasis durchgehen, um das Zeichen des Wertes zu speichern und es positiv zu machen, bevor ich die durchführte MOD und dann das Ergebnis mit dem Vorzeichenwert multiplizieren.

Dies dauerte mehrere Tage.

Wow, gute Lektüre hier!

Mein härtester war vor Jahren, als Turbo Pascal groß war, obwohl es einer der frühen C ++ - IDES dieser Zeit gewesen sein könnte. Als alleiniger Entwickler (und der dritte Typ bei diesem Startup) hatte ich etwas wie ein vereinfachtes Verkäufer-freundliches CAD-Programm geschrieben. Es war damals großartig, entwickelte aber einen bösen zufälligen Absturz. Es war unmöglich, sich zu reproduzieren, aber es passierte häufig genug, dass ich mich auf eine Insektenjagd machte.

Meine beste Strategie war es, im Debugger einstufen. Der Fehler ereignete sich nur, als der Benutzer genug von einer Zeichnung eingegeben hatte und vielleicht in einem bestimmten Modus oder Zoomzustand sein musste, sodass es viele mühsame Einstellungen und Löschten von Haltepunkten gab, die normal für eine Minute lief, um eine Zeichnung einzugeben, und dann Treten Sie durch einen großen Stück Code. Besonders hilfreich waren Haltepunkte, die einige einstellbare Häufigkeiten überspringen würden und dann brechen. Diese ganze Übung musste mehrmals wiederholt werden.

Schließlich schränkte ich es an einen Ort ein, an dem eine Unterroutine angerufen wurde und eine 2 erhielt, aber von ihm eine Kaudernummer. Ich hätte das früher erwecken können, aber nicht in diese Unterroutine eingetreten war, vorausgesetzt, es bekam das, was es gegeben hatte. Geblendet, wenn man angenommen hat, dass die einfachsten Dinge in Ordnung waren!

Es stellte sich heraus, dass es ein 16-Bit-Int auf den Stapel füllt, aber die Unterroutine erwartet 32-Bit. Oder sowas ähnliches. Der Compiler hat nicht den gesamten Wert automatisch auf 32 Bit gepadelt oder eine ausreichende Typüberprüfung durchgeführt. Es war trivial zu beheben, nur ein Teil einer Zeile, kaum ein Gedanke. Aber um dorthin zu gelangen, dauerte es drei Tage lang, um das Offensichtliche zu jagen und zu befragen.

Ich habe also persönliche Erfahrungen mit dieser Anekdote über den teuren Berater, der nach einer Weile irgendwo tippen und 2000 US -Dollar berechnet. Die Führungskräfte fordern eine Aufschlüsselung, und es kostet 1 US -Dollar für den Tap, 1999 für das Wissen, wohin sie tippen sollen. Außer in meinem Fall war es Zeit nicht Geld.

Lektionen gelernt: 1) Verwenden Sie die besten Compiler, bei denen "bestes" so definiert ist, dass es so viele Probleme umfasst, wie die Informatik weiß, wie man nachprüft, und 2) die einfachen offensichtlichen Dinge in Frage stellen oder zumindest ihre ordnungsgemäße Funktionen überprüfen.

Seitdem waren alle schwierigen Fehler wirklich schwierig, da ich weiß, dass ich die einfachen Dinge gründlicher überprüfen kann als nötig.

Lektion 2 gilt auch für den härtesten Elektronik -Fehler, den ich je behoben habe, auch mit einer trivialen Lösung, aber mehrere intelligente EES waren seit Monaten überrascht. Aber dies ist kein Elektronikforum, also werde ich nicht mehr davon sagen.

Die Networking -Daten -Rennbedingung aus der Hölle

Ich habe einen Netzwerk -Client/Server (Windows XP/C#) geschrieben, um mit einer ähnlichen Anwendung auf einem wirklich alten (Encore 32/77) Workstation zu arbeiten, das von einem anderen Entwickler verfasst wurde.

Was die Anwendung im Wesentlichen tat, war, bestimmte Daten auf dem Host zu teilen/zu manipulieren, um den Hostprozess zu steuern, der das System mit unserer schicken PC-basierten Multi-Monitor-Touchscreen-Benutzeroberfläche ausführt.

Dies tat dies mit einer 3 geschichteten Struktur. Der Kommunikationsprozess liest/schrieb Daten zum/vom Host, hat alle erforderlichen Formatkonvertierungen (Endiant, Floating Point -Format usw.) durchgeführt und die Werte zu/aus einer Datenbank geschrieben/lesen. Die Datenbank fungierte als Datenvermittler zwischen dem COMMS- und Touchscreen -Benutzeroberflächen. Die App von Touchscreen UI generierte Touchscreen -Schnittstellen, basierend auf der Anzahl der Monitore, die an den PC angeschlossen wurden (sie wurde automatisch erkannt).

In dem Zeitrahmen, der ein Wertepaket zwischen dem Host und unserem PC mit einer maximalen MAX-Werte gleichzeitig mit einer maximalen Latenz von ~ 110 ms pro Hin- die Computer). Die Anzahl der zulässigen Variablen basierend auf der variablen Anzahl angehängter Touchscreens stand streng streng. Außerdem hatte der Host (obwohl eine ziemlich komplexe Mehrprozessor-Architektur mit gemeinsamem Speicherbus für Echtzeit-Computing) etwa 1/10. die Verarbeitungsleistung meines Handys hatte, sodass er so wenig Verarbeitung wie möglich und Server durchführen sollte /Client musste in der Versammlung geschrieben werden, um dies zu versichern (der Host führte eine vollständige Echtzeitsimulation aus, die nicht von unserem Programm betroffen sein konnte).

Das Problem war. Einige Werte, wenn sie auf dem Touchscreen geändert wurden, würden nicht nur den neu eingegebenen Wert benötigen, sondern zufällig zwischen diesem Wert und dem vorherigen Wert zyklieren. Das und nur auf wenigen spezifischen Werten auf einigen bestimmten Seiten mit einer bestimmten Kombination von Seiten zeigten jemals das Symptom. Wir haben das Problem fast komplett verpasst, bis wir damit begonnen haben, es durch den anfänglichen Kundenakzeptanzprozess zu führen


Um das Problem festzuhalten, habe ich einen der oszillierenden Werte ausgewählt:

  • Ich habe die Touchscreen -App überprüft, sie schwankte
  • Ich habe die Datenbank geprüft und schwingend
  • Ich habe die Comms -App geprüft, schwingend

Dann brach ich Wireshark aus und begann manuell zu dekodieren Paketfangen. Ergebnis:

  • Nicht oszillierend, aber die Pakete sahen nicht richtig aus, es gab zu viele Daten.

Ich habe jedes Detail des COMMS -Codes hundertmal keinen Fehler/Fehler gefunden.

Schließlich fing ich an, E -Mails an den anderen Entwickler zu schießen, in dem ich detailliert fragte, wie sein Ende funktioniert hat, um zu sehen, ob es etwas fehlte. Dann fand ich es.

Als er Daten schickte, spüle er anscheinend das Array der Daten vor der Übertragung nicht. Im Wesentlichen überschrieben er nur den letzten Puffer, der mit den neuen Werten verwendet wurde, die die alten überschreiben, aber die alten Werte, die nicht überschrieben wurden, wurden immer noch übertragen.

Wenn also ein Wert an Position 80 des Datenarrays und die Liste der angeforderten Werte in weniger als 80 geändert wurde, der gleiche Wert jedoch in der neuen Liste enthalten war, würden beide Werte im Datenpuffer für diesen bestimmten Puffer bei jedem vorhanden sein gegebene Zeit.

Der Wert, der aus der Datenbank gelesen wurde, hing von der Zeitabnahme ab, als die Benutzeroberfläche den Wert beantragte.


Die Lösung war schmerzlich einfach. Lesen Sie in der Anzahl der auf dem Datenpuffer eingehenden Elemente (es wurde tatsächlich als Teil des Paketprotokolls enthalten) und lesen Sie den Puffer nicht über diese Anzahl der Elemente hinaus.


Gewonnene Erkenntnisse:

  • Nehmen Sie keine moderne Rechenleistung für selbstverständlich. Es gab eine Zeit, in der Computer Ethernet nicht unterstützten und wenn das Spülen eines Arrays als teuer angesehen werden konnte. Wenn Sie wirklich sehen möchten, wie weit wir gekommen sind, stellen Sie sich ein System vor, das praktisch keine Form der dynamischen Speicherzuweisung hat. Der Executive-Prozess musste den gesamten Gedächtnis für alle Programme in Ordnung bringen, und kein Programm konnte über diese Grenze hinauswachsen. Dh, die Zuweisung von mehr Speicher an ein Programm ohne Neukompilierung des gesamten Systems kann einen massiven Absturz verursachen. Ich frage mich, ob die Leute eines Tages über die Tage vor dem Müll im selben Licht sprechen werden.

  • Stellen Sie bei der Vernetzung mit benutzerdefinierten Protokollen (oder der Bearbeitung von Binärdatendarstellung im Allgemeinen) sicher, dass Sie die Spezifikation lesen, bis Sie jede Funktion jedes Werts verstehen, das über das Rohr gesendet wird. Ich meine, lesen Sie es, bis Ihre Augen weh tun. Menschen behandeln Daten, indem sie einzelne Bits oder Bytes manipulieren, die sehr clevere und effiziente Möglichkeiten haben, Dinge zu tun. Das Fehlen des kleinsten Details könnte das System brechen.

Die Gesamtzeit für die Behebung betrug 2-3 Tage, wobei die meiste Zeit damit verbracht wurde, an anderen Dingen zu arbeiten, als ich damit frustrieren musste.

SIDENOTE: Der betreffende Host -Computer unterstützt Ethernet standardmäßig nicht. Die Karte zum Anfahren wurde maßgeschneidert und nachgerüstet und der Protokollstapel gab es praktisch nicht. Der Entwickler, mit dem ich zusammengearbeitet habe Aber er hat es in weniger als einer Woche gemacht. Er war auch einer der ursprünglichen Projektleiter, die das Betriebssystem in erster Linie entworfen und programmiert hatten. Sagen wir einfach, alles, was er jemals über Computer/Programmierung/Architektur teilen musste, egal wie lange ich gewickelt oder wie viel ich bereits neu bin, würde ich mir jedes Wort anhören. Es gibt nichts Wertvolleres, als mit guten Menschen zu arbeiten, die eine echte Leidenschaft für das haben, was sie tun.

Der Hintergrund

  • In einer geschäftskritischen WCF -Anwendung, die eine Website vorantreibt und Backend -TRASACTIONAL -Verarbeitung bereitstellt.
  • Großvolumenanwendung (Hunderte von Anrufen pro Sekunde)
  • Mehrere Server Mehrere Instanzen
  • Hunderte von bestandenen Unit -Tests und unzähligen QS -Angriffen

Der Käfer

  • Bei der Produktion würde der Server für eine zufällige Zeit gut ausgeführt, dann werden schnell abgebaut und die Box -CPU auf 100%übertragen.

Wie ich es gefunden habe

Zuerst war ich mir sicher, dass dies ein normales Leistungsproblem war, also erstelle ich eine ausgefeilte Protokollierung. Überprüfte die Leistung bei jedem Anruf, der mit den Datenbankleuten über die Nutzung gesprochen wurde, beobachtete die Server für Probleme. 1 Woche

Dann war ich mir sicher, dass ich ein Problem mit Thread -Konkurrenz hatte. Ich habe meine Deadlocks überprüft, um die Situation zu schaffen, um Tools zu erstellen, um zu versuchen, die Situation im Debug zu schaffen. Mit zunehmendem Management -Frustration wandte ich mich an meine Kollegen, wie vorgeschlagen wurde, das Projekt von Grund auf neu zu starten, um den Server auf einen Thread zu beschränken. 1,5 Wochen

Dann sah ich mir an Tess Ferrandez Blog erstellte eine Benutzer -Dump -Datei und hat sie mit Windebug annalisiert, wenn der Server das nächste Mal einen Dump nahm. Fanden heraus, dass alle meine Threads in der Wörterbuchfunktion steckten.

Das lange, der kurze ein kleines Wörterbuch, das gerade den Überblick über das Protokoll für X -Threads -Fehler hielt, wurde nicht synchronisiert.

Wir hatten eine Anwendung, die mit einem Hardware-Gerät sprach, das in einigen Fällen nicht korrekt funktioniert, wenn das Gerät physikalisch gepflanzt würde, bis es zweimal wieder eingesteckt war.

Das Problem stellte sich heraus, dass eine Anwendung, die beim Start -up ausgeführt wurde, gelegentlich Segfauding war, als sie versuchte, aus einem Dateisystem zu lesen, das noch nicht montiert worden war (z. B. wenn ein Benutzer sie so konfiguriert hat, dass sie aus einem NFS -Volumen gelesen wurde). Beim Start der Anwendung sendet die Anwendung einige IOCTLs an den Treiber, um das Gerät zu initialisieren, dann die Konfigurationseinstellungen zu lesen und mehr IOCTLs zu senden, um das Gerät in den richtigen Zustand zu setzen.

Ein Fehler im Treiber führte dazu, dass ein ungültiger Wert auf das Gerät geschrieben wurde, als der Initialisierungsaufruf getätigt wurde. Der Wert wurde jedoch mit gültigen Daten überschrieben, sobald die Anrufe zum Einlegen des Geräts in einen bestimmten Zustand gebracht wurden.

Das Gerät selbst hatte eine Batterie und würde erkennen, ob es durch das Motherboard Strom verloren hat, und würde eine Flagge in den flüchtigen Speicher schreiben, was darauf hinweist Die Anweisung musste gesendet werden, um die Flagge zu löschen.

Das Problem war, dass, wenn die Leistung entfernt wurde, sobald das IOCTLS gesendet wurde, um das Gerät zu initialisieren (und den ungültigen Wert an das Gerät geschrieben), jedoch vor gültigen Daten gesendet werden konnten. Als das Gerät wieder eingeschaltet wurde, wurde das Flag festgelegt und versuchte, die ungültigen Daten zu lesen, die aufgrund der unvollständigen Initalisierung vom Treiber gesendet wurden. Dies würde das Gerät in einen ungültigen Zustand bringen, in dem das ausgestrahlte Flaggen gelöscht worden war, das Gerät jedoch keine weiteren Anweisungen erhalten würde, bis es vom Treiber wieder initialisiert wurde. Der zweite Reset würde bedeuten, dass das Gerät nicht versuchte, die darauf gespeicherten ungültigen Daten zu lesen und die korrekten Konfigurationsanweisungen zu erhalten, sodass er in den richtigen Zustand eingesetzt werden kann (vorausgesetzt, die Anwendung sendet die IOCTLs nicht ).

Am Ende dauerte es ungefähr zwei Wochen, um die genauen Umstände herauszufinden, die das Problem verursachten.

Für ein Universitätsprojekt haben wir ein verteiltes P2P -Knotensystem geschrieben, das Dateien ausgetauscht hat. Dies unterstützte Multicasting, um sich gegenseitig, mehrere Ringe von Knoten und einen Namenserver zu erkennen, sodass einem Client ein Knoten zugewiesen ist.

Geschrieben in C ++, wir haben verwendet Poco Dazu ermöglicht es eine schöne IO-, Socket- und Fadenprogrammierung.


Es gab zwei Fehler, die uns ärgerten und uns viel Zeit verlieren ließen, eine wirklich logische:

Zufällig teilte ein Computer seine Lokalhost -IP anstelle seiner Remote -IP.

Dies führte dazu, dass Clients eine Verbindung zum Knoten auf demselben PC oder denselben Knoten herstellen, um sich mit sich selbst zu verbinden.

Wie haben wir das identifiziert? Als wir die Ausgabe im Namenserver verbesserten, entdeckten wir zu einem späteren Zeitpunkt, als wir die Computer neu starteten, dass unser Skript, um die IP zu geben, falsch war. Zufällig wurde das LO -Gerät zuerst anstelle des ETH0 -Geräts aufgelistet ... wirklich dumm. Jetzt haben wir uns so hartnäckig von ETH0 anfordern, da dies unter allen Universitätscomputern geteilt wird ...


Und jetzt ärgerlicher:

Zufällig würde der Paketfluss zufällig innehalten.
Wenn der nächste Client eine Verbindung herstellt, würde er weitergehen ...

Dies geschah wirklich zufällig und da mehr als ein Computer beteiligt ist, wurde es mehr ärgerlich, dieses Problem zu debuggen Seite.

Mit viel Ausgabe im Code haben wir nur angenommen, dass das Senden der Befehle einwandfrei verläuft,
Dies ließ uns gefragt, wo das eigentliche Problem war ... Es schien, dass die Art und Weise, wie POCO -Umfragen falsch sind, falsch ist und dass wir stattdessen auf verfügbare Charaktere in der eingehenden Steckdose überprüfen sollten.

Wir nahmen an der Annahme, dass dies als einfachere Tests in einem Prototyp mit weniger Paketen funktioniert hat, was dieses Problem nicht verursachte. :-(


Gewonnene Erkenntnisse:

  • Machen Sie keine dummen Annahmen wie die Reihenfolge der Netzwerkgeräte.

  • Frameworks erledigen ihren Job nicht immer (entweder Implementierung oder Dokumentation).

  • Geben Sie genügend Ausgabe im Code an, falls dies nicht zulässig ist, protokollieren Sie erweiterte Details in einer Datei.

  • Wenn der Code nicht getestet wurde (weil es zu schwierig ist), gehen Sie nicht davon aus, dass die Dinge funktionieren.

Ich bin immer noch auf meiner schwierigsten Insektenjagd. Es ist eines davon, manchmal ist es da und manchmal sind es keine Fehler. Deshalb bin ich hier, um 6:10 Uhr am nächsten Tag.

Hintergrund:

  • Kontext: Sprache, Anwendung, Umgebung usw.
    • PHP OS -Handel
  • Wie wurde der Fehler identifiziert?
    • Zufällige Reihenfolge, die einen Teil des Teils für die zufälligen Fehlschläge machen und Probleme umleiten
  • Wer oder was hat den Fehler identifiziert?
    • Kunde, und das Umleitungsproblem war offensichtlich
  • Wie komplex hat der Fehler reproduziert?
    • Ich konnte mich nicht reproduzieren, aber der Kunde konnte es geschafft.

Die Jagd.

  • Was war dein Plan?
    • Debug -Code hinzufügen, Reihenfolge ausfüllen, Daten analisieren, wiederholen
  • Welche Schwierigkeiten haben Sie begegnet?
    • Mangel an wiederholbaren Problemen und schrecklichen Code
  • Wie wurde der beleidigende Code endlich gefunden?
    • Es wurden viele beleidigende Code gefunden. Nur nicht genau das, was ich brauchte.

Das Töten.

  • Wie komplex war die Lösung?
    • sehr
  • Wie haben Sie den Umfang des Fixes bestimmt?
    • Es gab keinen Umfang ... es war überall
  • Wie viel Code war an der Fix involviert?
    • Alles davon? Ich glaube nicht, dass eine Datei unberührt war

Postmortem.

  • Was war die Grundursache technisch? Pufferüberschreitung usw.
    • Schlechte Codierungspraxis
  • Was war die Grundursache von 30.000 Fuß?
    • Ich wuerde eher nicht behaupten, dass...
  • Wie lange dauerte der Prozess letztendlich?
    • für immer und einen Tag
  • Gab es irgendwelche Funktionen, die von der Fix beeinträchtigt wurden?
    • Besonderheit? Oder ist es ein Fehler?
  • Welche Methoden, Werkzeuge, Motivationen haben Sie besonders hilfreich gefunden? ... schrecklich nutzlos?
  • Wenn Sie alles wieder tun könnten? ............
    • Strg+a del

Ich musste ein paar verwirrende Parallelitätsdaten letztes Semseter reparieren, aber der Fehler, der für mich immer noch am meisten auffällt, war in einem textbasierten Spiel, das ich in der PDP-11-Versammlung für eine Hausaufgabe geschrieben habe. Es basierte auf Conways Leben des Lebens und aus irgendeinem seltsamen Grund wurde ein großer Teil der Informationen neben dem Netz ständig mit Informationen überschrieben, die nicht dort hätte sein dürfen. Die Logik war auch ziemlich einfach, also war sie sehr verwirrend. Nachdem ich es ein paar Mal durchgemacht hatte, um wiederzuentdecken, dass die gesamte Logik korrekt ist, bemerkte ich plötzlich, was das Problem war. Dieses Ding: .

In PDP-11 macht dieser kleine Punkt neben einer Zahl es Basis 10 anstelle von 8. Es war neben einer Zahl, die eine Schleife begrenzte 8.

Es fällt mir immer noch auf, weil die Menge an Schaden eine so winzige Ergänzung von 4 Pixelgröße verursacht hat. Was ist die Schlussfolgerung? Codieren Sie nicht in PDP-11-Assembly.

Das Hauptframe-Programm wurde ohne Grund aufgehört zu arbeiten

Ich habe das gerade auf eine andere Frage gepostet.Siehe Beitrag hier

Es geschah, weil sie eine neuere Version des Compilers auf dem Hauptrahmen installiert haben.

Update 06/11/13: (Die ursprüngliche Antwort wurde von OP gelöscht)

Ich habe diese Hauptframe-Anwendung erbelt. Eines Tages, aus heiterem Himmelblau, hörte es auf zu arbeiten. Das ist es ... poof, es hat einfach aufgehört.

Meine Aufgabe war es, es so schnell wie möglich zum Laufen zu bringen. Der Quellcode war zwei Jahre lang nicht geändert worden, aber plötzlich hörte er einfach auf. Ich habe versucht, den Code zu kompilieren und er brach in Zeile xx. Ich schaute mir Zeile XX an und konnte nicht sagen, was Zeile xx Break machen würde. Ich fragte nach den detaillierten Spezifikationen für diese Anwendung und es gab keine. Zeile XX war nicht der Schuldige.

Ich habe den Code ausgedruckt und angefangen, ihn von oben nach unten zu überprüfen. Ich fing an, ein Flussdiagramm von dem zu schaffen, was los war. Der Code war so verworren, dass ich kaum einen Sinn daraus machen konnte. Ich gab es auf und versuchte, es zu fließen. Ich hatte Angst, Änderungen vorzunehmen, ohne zu wissen, wie diese Änderung den Rest des Prozesses beeinflussen würde, zumal ich keine Einzelheiten darüber hatte, was die Anwendung tat.

Also habe ich mich entschlossen, oben im Quellcode zu beginnen und Whitespce- und Zeilenbremsen hinzuzufügen, um den Code lesbarer zu gestalten. In einigen Fällen bemerkte ich, ob sich die Bedingungen zusammenzusetzen, die sich und ORS und ORS nicht deutlich unterschieden, zwischen den Daten und den Daten, in denen die Daten ored wurden. Also fing ich an, Klammern um die und und / oder Bedingungen zu setzen, um sie lesbarer zu machen.

Als ich mich langsam nach unten bewegte, würde ich meine Arbeit regelmäßig retten. Irgendwann versuchte ich, den Code und eine seltsame Sache zu kompilieren. Der Fehler war über die ursprüngliche Codezeile gesprungen und war nun weiter unten. Also fuhr ich fort und speparierte das und und / / / / / / / / / / / / / / / / Noch mit Parens zu speparieren. Als ich fertig wurde, hat es funktioniert. Stelle dir das vor.

Ich beschloss dann, den Operations-Shop zu besuchen und sie zu fragen, ob sie kürzlich neue Komponenten auf dem Hauptrahmen installiert hätten. Sie sagten ja, wir haben kürzlich den Compiler verbessert. Hmmmm.

Es stellt sich heraus, dass der alte Compiler den Ausdruck von links nach rechts bewertete. Die neue Version des Compilers bewertete auch die Ausdrücke von links nach rechts, aber eindeutiger Code bedeutet, dass eine unklare Kombination von AND und ORS nicht gelöst werden konnte.

Lektion Ich habe daraus gelernt ... immer, immer, immer, immer zu getrennten Bedingungen und oder Bedingungen, wenn sie in Verbindung miteinander verwendet werden.

Hintergrund:

  • Kontext:Web-Server (C++), die es Kunden ermöglicht, um den check-in selbst
  • Fehler:Wenn Sie die Seite anfordern, es würde einfach nicht reagiert, wird die ganze farm ist, und die Prozesse getötet werden würde (und neu gestartet), weil Sie zu lange dauerte (nur ein paar Sekunden erlaubt) zu dienen Sie die Seite
  • Einige Benutzer beschweren sich, aber es war sehr sporadisch, so dass meist unbemerkt (Menschen, nur neigen dazu, drücken Sie "Aktualisieren", wenn eine Seite wird nicht bedient).Wir haben beachten Sie die core-dumps though ;)
  • Wir haben eigentlich nie geschafft, zu reproduzieren, in unsere lokale Umgebungen, der bug tauchte ein paar mal in der Test-Systeme, aber nie zeigte sich bei Performance-Tests ??

Die Jagd.

  • Plan:Naja, da hatten wir Speicherabbilder und Protokolle, die wir wollten, um Sie zu analysieren.Da war es Auswirkungen auf die gesamte farm und wir hatten, haben einige Datenbanken, die in der Vergangenheit Probleme wir den Verdacht, dass die Datenbank (single-DB für mehrere Server)
  • Schwierigkeiten:Einen vollständigen server-dump ist riesig, und so sind Sie gelöscht Recht Häufig (nicht genügend Speicherplatz), also mussten wir schnell zu packen, wenn es aufgetreten ist...Wir anhielt.Die Deponien zeigten sich verschiedene Stapel (nie DB-Sachen, so viel für, dass), ist es fehlgeschlagen während der Vorbereitung der Seite selbst (nicht in den früheren Berechnungen), und bestätigt, was die Protokolle zeigten, vorbereiten Seite würden manchmal nehmen eine lange Zeit, auch wenn es nur eine einfache template-engine mit vorab berechneten Daten (traditionellen MVC)
  • Bekommen, um es:Nach einigen weiteren Proben, und einige denken, wir realisiert, dass die Zeit übernommen wurde das Lesen der Daten von der HDD (die Seite Vorlage).Da war es über die ganze farm, die wir zum ersten mal sah für geplante jobs (crontab -, Chargen), aber die Zeiten nie erreicht, von einem Ereignis zu einem anderen...Es kam schließlich zu mir, dass dies immer passiert, ein paar Tage bevor die Aktivierung einer neuen version der software, und ich hatte eine AhAh! moment...es war verursacht durch die Verteilung der software!Die Bereitstellung mehrerer hundert Megabyte (komprimiert) kann eine kleine delle auf der Platte Leistung :/ natürlich ist die Verteilung ist automatisiert und das Archiv geschoben, um allen Servern gleichzeitig (multicast).

Die Tötung.

  • Fix Die Komplexität:wechseln zu kompilierten templates
  • Code Betroffen:keine, eine einfache änderung in der build-Prozess

Postmortal.

  • Ursache:operative Problem oder mangelnde Planung :)
  • Zeitrahmen:es dauerte Monate, bis die Spur einer Angelegenheit von Tagen zu beheben, und testen Sie, vor ein paar Wochen für QA-und Performance-Tests und deployment-keine Eile gibt, da wir wussten, dass die Bereitstellung der Korrektur auslösen würde, die den Fehler...und sonst nichts...ein bisschen pervers wirklich!
  • Unerwünschte Nebenwirkungen:Unmöglichkeit der Schalter Vorlagen zur Laufzeit jetzt, dass Sie gebacken werden in der gelieferten code, wir haben nicht mit dem feature viel, obwohl, da in der Regel Schalt-Vorlagen bedeutet, dass Sie haben mehr Daten zu Gießen.Mithilfe von css ist meist ausreichend für die "kleinen" layout-änderungen.
  • Methoden, tools: gdb + - monitoring!Haben uns einfach mal auf Verdacht die Festplatte, und dann identifizieren Sie die Ursache für die Stacheln der Tätigkeit auf die überwachung graph...
  • In der nächsten Zeit:behandeln Sie alle IO as negative!

Das Schwierigste wurde nie getötet, weil es nie anders reproduziert werden konnte als in der gesamten Produktionsumgebung mit dem Werk in der Fabrik.

Der verrückteste, den ich getötet habe:

Die Zeichnungen drucken Kauderwelsch!

Ich schaue mir den Code an und kann nichts sehen. Ich ziehe einen Job aus der Druckerwarteschlange heraus und untersuche ihn, es sieht gut aus. (Dies war in der DOS-Ära, PCL5 mit eingebettetem HPGL/2-eigentlich sehr gut, um Zeichnungen zu planen .

Rollen Sie den Code zurück, das Problem ist immer noch da.

Schließlich mache ich manuell eine einfache Datei und sende sie an den Drucker-Gibberish. Es stellte sich heraus, dass es überhaupt nicht mein Fehler war, sondern der Drucker selbst. Das Wartungsunternehmen hatte es auf die neueste Version geflitzt, als sie etwas anderes repariert haben und diese neueste Version einen Fehler hatte. Sie zu verstehen, dass sie kritische Funktionen herausgenommen hatten und sie auf eine frühere Version zurückblitzen mussten, war schwieriger, als den Fehler selbst zu finden.

Eine, die noch ärgerlicher war, aber da es nur auf meiner Schachtel war, würde ich nicht den ersten Platz setzen:

Borland Pascal, DPMI -Code, um sich mit einigen nicht unterstützten APIs zu befassen. Führen Sie es gelegentlich aus, normalerweise ging es Boom, um mit einem ungültigen Zeiger umzugehen. Es hat jedoch nie ein falsches Ergebnis erzielt, wie Sie es erwarten würden, wenn Sie auf einen Zeiger stampfen.

DEBUG-Wenn ich den Code einbereitet habe, würde er immer richtig funktionieren, sonst war es genauso instabil wie zuvor. Die Inspektion zeigte immer die richtigen Werte.

Der Schuldige: Es gab zwei.

1) Borlands Bibliothekscode hatte einen großen Fehler: Real -Modus -Zeiger wurden in Zeigervariablen im geschützten Modus gespeichert. Das Problem ist, dass die meisten Real -Modus -Zeiger im geschützten Modus ungültige Segmentadressen haben. Wenn Sie versuchen, den Zeiger zu kopieren, hat er ihn in ein Registerpaar geladen und dann gespeichert.

2) Der Debugger würde niemals etwas über eine so ungültige Last im einstufigen Modus sagen. Ich weiß nicht, was es intern getan hat, aber was dem Benutzer präsentiert wurde, sah völlig korrekt aus. Ich vermute, dass es die Anweisung nicht ausführte, sondern stattdessen simuliert.

Dies ist nur ein sehr einfacher Fehler, den ich irgendwie in einen Albtraum für mich verwandelt habe.

Hintergrund: Ich habe daran gearbeitet, mein eigenes Betriebssystem zu erstellen. Debugging ist sehr schwierig (Trace -Aussagen sind alles, was Sie haben können, und manchmal nicht einmal das)

Fehler: Anstatt zwei Thread -Switches bei Usmodode durchzuführen, würde dies stattdessen allgemeiner Schutzfehler.

The Bug Hunt: Ich habe wahrscheinlich ein oder zwei Wochen damit verbracht, dieses Problem zu beheben. Überall Einfügen von Trace -Aussagen. Untersuchung des generierten Assembly -Code (von GCC). Drucken Sie jeden Wert, den ich konnte.

Das Problem: Irgendwo früh in der Käferjagd hatte ich a platziert hlt Anweisung im CRT0. Der CRT0 ist im Grunde das, was ein Benutzerprogramm für die Verwendung in einem Betriebssystem startet. Dies hlt Anweisungen verursachen einen GPF, wenn er aus dem Benutzermodus ausgeführt wird. Ich habe es dort platziert und im Grunde genommen vergessen. (Ursprünglich war das Problem ein Pufferüberlauf oder ein Speicherzuweisungsfehler)

Das Fix: Entfernen Sie die hlt Anweisung :) Nach dem Entfernen funktionierte alles reibungslos.

Was ich gelernt habe: Wenn ich versuche, ein Problem zu debuggen, verlieren Sie nicht die Korrekturen, die Sie versuchen. Machen Sie regelmäßige Diffs gegen die neueste stabile Quellierungssteuerungsversion und sehen Sie, was Sie in letzter Zeit geändert haben, wenn nichts anderes funktioniert

Lizenziert unter: CC-BY-SA mit Zuschreibung
scroll top