Montag, 10. August 2009

Umfangreiche Debuggingsession


Mit neuen Features gehen neue Fehler einher. Das ist so weit nichts neues. Tippfehler sind da die einfachsten, die erkennt der Compiler, und sie sind schnell behoben.
Gelegentlich bringen neue Features auch Fehler ans Licht, die schon länger existieren, aber bisher nicht zuschlugen. So einen hatte ich jetzt. Besonders unangenehm: Ein Fehler der meistens auftritt, aber nicht immer.

Es war klar, dass dieser irgendwie mit der Datenübertragung zusammenhängen muss. Allerdings sahen sowohl Server, als auch Client Code korrekt aus. Also hole ich Wireshark raus (Schlimmes Hackerprogramm. Ich fühle mich ja ach so böse.) und schneide die Kommunikation mit. Sieht alles ganz gut aus. Das in Frage kommende Datum - ein Bild - ist zu groß für ein Datenpaket, wird daher aufgeteilt. Dieses Vorgehen ist integraler Bestandteil von IP, und sollte daher kein Problem darstellen.

Doch was ist das? Meine Fehlerausgabe reklamiert unerkannte Daten, die genau so aussehen, wie die des zweiten Paketes. Ist nun IP kaputt? Kann doch nicht sein, dann würde ja viel mehr nicht funktionieren.

Die Lösung brachte ein Blick in die Qt Dokumentation. Ich verwende zum einlesen die QIODevice::readLine Funktion. Funktioniert meistens. Die liest eine Zeile, und eine Zeile endet mit '\n'. So weit so gut. Aber eine Zeile endet auch bei: "The end of the device data is detected."
Und das ist eine race condition. Wenn ich es schaffe readLine aufzurufen, bevor das zweite Paket ankommt, wird der Inhalt des ersten Paketes als vollständige Zeile zurückgeliefert.

Race Conditions sind recht unangenehme Fehler. Sie lassen sich fast nur durch hinzufügen eines zusätzlichen Endkriteriums beseitigen. Ich war ja der Meinung, '\n' sei ein solches Kriterium, ich übertrage das Bild ja nicht umsonst Base64 codiert. Ist es aber nach obiger Definition nicht.

Also brauche ich ein weiteres Ende Signal. Das Problem ist, dass ein solches Signal sich in der gesamten Datenübertragung auswirkt, deren allergrößter Teil bereits funktioniert hat, und funktionierenden Code lasse ich gerne stehen.
Hilft aber nichts, wenn es sein muss, wird eben ein Endesignal übertragen, dass dann auf der anderen Seite abgefangen werden will.

Nebeneffekte des Ganzen:


  • Ein paar kleinere Bugs konnten in diesem Prozess ebenfalls eliminiert werden.
  • Die Anzahl der ASSERTs ist merklich angestiegen.
  • Note to self: Dinge die begründet an einer Stelle anders gemacht werden, als überall sonst, dürfen gerne eine Kommentarzeile bekommen. Beim Aufräumen im Code ist sonst ein solcher Grund nicht immer im Hinterkopf präsent und es gibt gar wunderliche Effekte.


Ps.: Qt macht mir das Debuggen nicht gerade leicht. Immernoch halte ich DDD für den Besten mir bekannten Debugger. Aber wenn die Datenaufschlüsselung so aussieht wie in obigem Bild, werde ich daraus nicht wirklich schlau.

Keine Kommentare:

Kommentar veröffentlichen