Zum Inhalt springen

Programmfehler

aus Wikipedia, der freien Enzyklopädie
Dies ist eine alte Version dieser Seite, zuletzt bearbeitet am 22. Mai 2005 um 18:51 Uhr durch Romankawe (Diskussion | Beiträge) (Arten von Programmfehlern: zirkellink entfernt). Sie kann sich erheblich von der aktuellen Version unterscheiden.

Ein Programmfehler oder Softwarefehler, im englischen auch einfach Bug (Wanze, Käfer, Insekt; Aussprache: Bagg) genannt, ist ein Ausdruck aus dem EDV-Bereich. Ein Programmfehler tritt in Computerprogrammen auf, wenn der Programmierer einen bestimmten Zustand in der Programmlogik nicht berücksichtigt hat, oder wenn die Laufzeitumgebung an sich fehlerhaft arbeitet. Auch Unvollständigkeit, Fehler, Ungenauigkeiten, Mehrdeutigkeiten o. ä. in der Spezifikation des Programms können zu Bugs führen, bzw. als solche interpretiert werden. Es gibt eine Regel, nach der ein Computerprogramm ab einer bestimmten Größe immer auch Programmfehler beinhaltet. Die Anzahl von Fehlern zur Lebenszeit eines komplexen System verhält sich nach der sogenannten Badewannenkurve. Diese besagt, dass für neue Produkte auch die Zahl der Fehler hoch ist. Die Fehler werden zum Großteil behoben, wonach eine Phase mit wenig Fehlern erreicht wird. Gegen Ende der Nutzungszeit steigt, selbst bei Software, die Zahl der Fehler wieder an. Um Bugs in Programmen besser verstehen zu können, gibt es Programme, sogenannte Debugger, mit denen man ein Programm, welches man analysiert, schrittweise ablaufen lassen kann und sich sämtliche internen Zustände (Variablen) des Programmes anzeigen lassen kann.

Arten von Programmfehlern

In der Softwaretechnik wird zwischen folgenden Typen von Fehlern in Programmen unterschieden:

  • Bohrbugs sind Fehler, die leicht zu reproduzieren sind, da sie immer auftreten. Der Name ist vermutlich im scherzhaften Gegensatz zu den Heisenbugs entstanden.
  • Heisenbugs treten nur unter ganz bestimmten Randbedingungen auf, sind somit schwer zu reproduzieren und damit zu beheben. Benannt sind sie vermutlich nach der Heisenbergschen Unschärferelation.
  • Regressionsbug oder kurz Regression ist ein Fehler, der in einer früheren Programmversion bereits behobenen wurde, der aber in einer späteren Programmversion wieder auftaucht.
  • Laufzeitfehler (Bugs) sind alle Arten von Fehlern, die auftreten, während das Programm abgearbeitet wird. Da diese Fehler die Programmlogik und damit die Bedeutung des Programmcodes betreffen, spricht man hier auch von semantischen Fehlern. Ihre Ursache liegt in den meisten Fällen in einer inkorrekten Implementierung der gewünschten Funktionalität im Programm. Gelegentlich tritt als Ursache auch eine ungeeignete Laufzeitumgebung auf (z. B. eine falsche Betriebssystem-Version). Laufzeitfehler können sich auf die unterschiedlichsten Arten zeigen. Oftmals zeigt das Programm ungewünschtes Verhalten, im Extremfall wird die Ausführung des Programms abgebrochen („Absturz“), oder das Programm geht in einen Zustand über, wo es keine Benutzereingaben mehr akzeptiert („Einfrieren“, „Hängen“). Wird in Programmiersprachen ohne Garbage Collection (etwa C oder C++) Speicher nach der Verwendung nicht mehr freigegeben, so wird durch das Programm auf Dauer immer mehr Speicher belegt. Diese Situation wird Memory leak genannt. Aber auch in Programmiersprachen mit Garbage Collection (etwa Java oder C#) können ähnliche Probleme auftreten, wenn zum Beispiel Objekte unkontrolliert in einer Liste angesammelt werden.
  • Designfehler sind Fehler im Grundkonzept, entweder bei der Definition der Anforderungen an die Software, oder bei der Entwicklung des Softwaredesigns, auf dessen Grundlage das Programm entwickelt wird. Fehler bei der Anforderungsdefinition beruhen oft auf mangelnder Kenntnis des Fachgebietes, für das die Software geschrieben wird oder auf Missverständnissen zwischen Nutzern und Entwicklern. Fehler direkt im Softwaredesign hingegen sind oft auf mangelnde Erfahrung der Softwareentwickler oder auf Folgefehler durch Fehler in der Anforderungsspezifikation zurückzuführen. In anderen Fällen ist das Design historisch gewachsen und wird mit der Zeit unübersichtlich, was wiederum zu Designfehlern bei Weiterentwicklungen des Programms führen kann. Vielen Programmierern ist das Softwaredesign auch lästig, sodass oftmals ohne richtiges Konzept direkt entwickelt wird, was dann insbesondere bei steigendem Komplexitätsgrad der Software unweigerlich zu Designfehlern führt. Sowohl für Fehler in der Anforderungsdefinition als auch im Softwaredesign kommen darüber hinaus vielfach Kosten- oder Zeitdruck in Frage.

Bugreporting-Tools wie zum Beispiel Bugzilla oder Mantis erfassen neben Programmfehlern auch Wünsche der Nutzer (Request For Enhancement) oder allgemeine Vorgänge. Bei manchen Projekten spricht man dann zum Beispiel von Metabugs, wo ein Bug ein Element einer Aufgabenliste darstellt. Bei einigen Projekten spricht man stattdessen von „Issues“ (Angelegenheiten), da sich dieser Ausdruck nicht auf Programmfehler beschränkt.

Vermeidung und Behebung von Programmfehlern

Je früher in einem Entwicklungprozess der Fehler auftritt und je später er entdeckt wird, umso aufwendiger wird es den Fehler zu beheben.

Zum Zeitpunkt der Planung

Am wichtigsten ist eine gute und geeignete Planung des Entwicklungsprozess. Hierfür gibt es bereits etliche Prozessmodelle aus denen ein geeignetes ausgewählt werden kann.

Zur Analysephase

Ein Problem ist das die Korrektheit eines Programms nur gegen eine entsprechend formalisierte Spezifikation bewiesen werden kann. Eine solche Spezifikation zu erstellen kann jedoch im Einzelfall ähnlich kompliziert und fehlerträchtig sein, wie die Programmierung des Programms selbst.

Auch die Entwicklung immer abstrakterer Programmierparadigmen und Programmierstile wie die objektorientierte Programmierung, Design By Contract und die aspektorientierte Programmierung dienen unter anderem der Fehlervermeidung und Vereinfachung der Fehlersuche. Aus den zur Verfügung stehenden Techniken für das Problem ist eine geeignete auszuwählen. Ein wichtiger Punkt hierbei ist aber auch das für das jeweiligen Paradigma erfahrene Programmierer zur Verfügung stehen müssen, sonst entsteht oft der gegenteilige Effekt.

Zur Designphase

Software-Experten sind sich darüber einig, dass praktisch jedes nicht-triviale Programm Fehler enthält. Deshalb wurden Techniken entwickelt, mit Fehlern innerhalb von Programmen tolerant umzugehen. Zu diesen Techniken gehören defensives Programmieren, Ausnahmebehandlung, Redundanz und die Überwachung von Programmen (z. B. durch Watchdog- timer, sowie die Plausibilisierung des Programmes während der Entwicklung und der Daten während des Programmablaufs.

Bei der Programmierung

Darüberhinaus werden eine Reihe fortgeschrittener Anwendungen angeboten, die entweder den Quellcode oder den Binärcode analysieren und versuchen, häufig gemachte Fehler automatisiert zu finden. In diese Kategorie fallen etwa Programme zur Ausführungsüberwachung, die üblicherweise fehlerhafte Speicherzugriffe und Memory leaks zuverlässig aufspüren. Beispiele sind das frei erhältliche Tool Valgrind und das kommerzielle Purify. Eine weitere Kategorie von Prüfprogrammen umfasst Anwendungen, die Quell- oder Binärcode statisch analysieren und etwa nicht geschlossene Ressourcen und andere Probleme auffinden und melden können. Darunter fallen etwa Findbugs, lint und Splint.

Beim Testen

Es ist durchaus sinnvoll das der Test vor dem eigentlichen Programm entwickelt wird. Damit wird erreicht das nicht ein Test geschrieben wird der zu dem bereits geschriebenen Programm passt. Dies kann durch Ermittlung von Testfällen anhand der Spezifikation bereits während der Analyse- bzw. Designphase erfolgen. Die Ermittlung von Testfällen in diesem frühen Stadium der Softwareentwicklung ermöglicht zudem die Prüfung der Anforderungen an das Programm auf Testbarkeit und Vollständigkeit. Die anhand der Spezifikation ermittelten Testfälle stellen die Basis für die Abnahmetests und können kontinuierlich über den gesamten Entwicklungsprozess verfeinert werden.

Manche Softwareanbieter führen Test-Phasen teilweise öffentlich durch und geben Betaversionen heraus, um die unvorhersehbar vielfältigen Nutzungsbedingungen verschiedener Anwender durch diese selbst testen und kommentieren zu lassen. Dies nennt man scherzhaft auch „Bananensoftware“, weil sie erst beim Kunden reift.

Fehlerfreiheit

In Spezialfällen ist ein Beweis der Fehlerfreiheit eines Programms möglich. Diese Technik findet in der Praxis aufgrund des immensen Aufwandes jedoch äußerst selten Anwendung. Insbesondere in Bereichen, in denen der Einsatz von Software mit hohen finanziellen, wirtschaftlichen oder menschlichen Risiken verbunden ist, wie z. B. bei militärisch oder medizinisch genutzer Software oder in der Luft- und Raumfahrt, verwendet man zudem eine Verifizierung genannte Methode, bei der die Korrektheit einer Software formal-mathematisch nachgewiesen wird. Dieser Methode sind allerdings enge Grenzen gesetzt und sie ist daher bei komplexen Programmen praktisch unmöglich, teilweise auch theoretisch unmöglich anzuwenden; siehe auch Berechenbarkeit.

Folgen von Programmfehlern

Die Folgen eines Programmfehlers können außerordentlich sein:

  • 1962 führte ein fehlender Bindestrich in einem Fortran-Programm zum Verlust der Venus-Sonde Mariner 1, welche über 80 Millionen US-Dollar gekostet hatte.
  • Zwischen 1985 und 1987 gab es mehrere Unfälle mit dem medizinischen Bestrahlungsgerät Therac-25. Infolge einer Überdosis, die durch fehlerhafte Programmierung und fehlende Sicherungsmaßnahmen verursacht wurde, mussten Organe entfernt werden, ein Patient verstarb drei Wochen nach der Bestrahlung.
  • 1996 wurde der Prototyp der Ariane 5-Rakete der Europäischen Raumfahrtbehörde eine Minute nach dem Start zerstört, weil Programmcode, der von der Ariane 4 übernommen wurde und nur für einen (von der Ariane 4 nicht überschreitbaren) Bereich funktionierte, die Steuersysteme zum Erliegen brachte, nachdem ebendieser Bereich von der Ariane 5 überschritten wurde.
  • 1999 verpasste die NASA-Sonde Climate Orbiter den Landeanflug auf den Mars, weil die Programmierer das falsche Maßsystem verwendeten – Yard statt Meter. Die NASA verlor dadurch die mehrere hundert Millionen Dollar teure Sonde.

Das Wort „Bug“

Das Wort „Bug“ wurde schon im 19. Jahrhundert für kleine Fehler in mechanischen und elektrischen Teilen verwendet. So soll Thomas Edison 1878 an seinen Freund Tivadar Puskás einen Brief über die Entwicklung seiner Erfindungen geschrieben haben, in dem er Bugs als kleine Störungen und Schwierigkeiten bezeichnete („… that “Bugs”—as such little faults and difficulties are called—show themselves …“).

Einer Legende zufolge ist die Bezeichnung in der Anfangszeit der Computer entstanden, als Insekten in den großen Maschinen die Funktionsweise der Relais störten und Kurzschlüsse verursachten. Die Erfindung des Begriffs wird oft der Computerpionierin Grace Hopper zugesprochen. Diese verbreitete die Geschichte, am 9. September 1945, manche Quellen sprechen auch von 1947, habe eine Motte in einem Relais des Computers Mark II Aiken Relay Calculator zu einer Fehlfunktion geführt. Die Motte wurde entfernt und in das Logbuch mit den Worten „First actual case of bug being found.“ geklebt. Die entsprechende Seite des Logbuchs wurde bis Anfang der 1990er Jahre am Naval Surface Warfare Center Computer Museum der US-Navy in Dahlgren, Virginia, aufbewahrt. Seitdem ist die Logbuch-Seite mit der Motte am Smithsonian Institute.

Siehe auch: moderne Legende

Reproduzierbarkeit von Programmfehlern

Manchmal sind Programmfehler nur äußerst schwer oder gar nicht zuverlässig reproduzierbar.

Der Grund ist oft, dass der Einsatz eines Analysewerkzeuges verhindert, dass der Fehler auftritt, weil sich die Rahmenbedingungen, insbesondere das zeitliche Verhalten, dadurch ändern. Solche Fehler treten in nebenläufigen Umgebungen vermehrt auf. Eine besonders häufige Ursache dafür sind Wettlaufsituationen wegen mangelnder Synchronisation (genauer: Sequentialisierung).

Im Programmiererjargon spricht man dabei manchmal scherzhaft von "Heisenbug", und im Gegensatz dazu bei immer reproduzierbaren Fehlern von "Bohrbug".

Heisenbugs and Bohrbugs: Why are they different? (PDF, Englisch)


Literatur

  • William E. Perry: Software Testen, Mitp-Verlag, November 2002, ISBN 3826608879
  • Elfriede Dustin, Jeff Rashka, John Paul: Software automatisch testen, Springer, Berlin, Januar 2001, ISBN 3540676392
  • Cem Kaner, Jack Falk, Hung Q. Nguyen: Testing Computer Software, John Wiley & Sons, Juni 1999, ISBN 0471358460