Zum Inhalt springen

Programmfehler

Diese Seite befindet sich derzeit im Review-Prozess
aus Wikipedia, der freien Enzyklopädie
Dies ist eine alte Version dieser Seite, zuletzt bearbeitet am 30. Januar 2005 um 13:59 Uhr durch Wachs (Diskussion | Beiträge). 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 selber 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. Auch nichtinitialisierte Variablen führen im Programmablauf zu undefinierten, meist nicht reproduzierbaren Zuständen. Um bugs in Programmen besser zu verstehen zu können gibt es Programme, sogennante Debugger mit dennen man ein Programm welches man analysiert schrittweise ablaufen lassen kann und sich sämtliche internen Zustände(Variablen) des Programmes anzeigen 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.
  • Heisenbugs tretten nur unter ganz bestimmten Randdedingungen auf und sind somit schwer zu reproduzieren und damit zu beheben.
  • Regressionsbug oder kurz Regression ist ein Fehler der in einer früheren Programmversion bereits behobenen waren, 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 unrichtiger 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.

Vermeidung und Behebung von Programmfehlern

Fehlern in Computerprogrammen wird auf vielfältige Art und Weise begegnet.

Zum Einen versucht man, Programmfehler durch bestimmte Methoden während der verschiedenen Phasen der Software-Entwicklung von vornherein zu vermeiden. Unter anderem gehören dazu das Vier-Augen-Prinzip mittels regelmäßiger Code-Reviews, Paarprogrammierung und gemeinsamem Code-Besitz sowie die gute Planung, Analyse und Entwurf.

Zum Anderen will man Programmfehler möglichst schnell, zuverlässig und einfach finden. Dazu zählt u. a. das Debugging (engl. = „Entwanzung“) mit Hilfe speziell dafür entwickelter Werkzeuge, genannt Debugger und die Einplanung spezieller Test-Phasen. Tests sind Prozeduren und Programme, die einen Programmfehler reproduzierbar auslösen sollen, um sie einzugrenzen und zu vermeiden, sie dienen sowohl zur Vermeidung als auch zum Auffinden von Programmfehlern.

Manche Softwareanbieter führen diese 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.

Weiters 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ässlich aufspüren. Beispiele sind das frei erhältliche Tool Valgrind und das kommerzielle Purify. Eine weitere Kategorie von Prüfprogrammen umfaßt Anwendungen, die Quell- oder Binärcode statis analysieren und etwa nicht geschlossene Ressourcen und andere Probleme auffinden und melden können. Darunter fallen etwa Findbugs, lint und Splint.

Die Abwesenheit von Softwarefehlern kann im allgemeinen Fall nicht mathematisch bewiesen werden, sondern sie muss soweit wie möglich durch aufwändige Tests belegt werden. Tests können jedoch praktisch niemals alle Fehler einer Software finden. Vor allem da manchmal sogar unentschieden ist, ob ein spezielles Verhalten der Anwendung einen Fehler darstellt.

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.

Des weiteren birgt sie das Problem, dass die Korrektheit eines Programms nur gegen eine entsprechend formalisierte Spezifikation beweiesen werden kann. Eine solche Spezifikation zu erstellen kann jedoch im Einzelfall ähnlich kompliziert und Fehlerträchtig sein, wie die Programmierung des Programms selbst. Dadurch wird das Problem der Fehlervermeidung folglich lediglich von der Software auf die Spezifikation verlagert.

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 – bei im jeweiligen Paradigma unerfahrenen Programmierern entsteht allerdings oft eher der gegenteilige Effekt.

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 Enwicklung und der Daten während des Programmablaufs.

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.

Siehe auch: Debugging, Debugger, Ada (Programmiersprache)

Das Wort „Bug“

Die Bezeichnung Bug – der englische Ausdruck für einen Programmfehler – entstand angeblich, als 1945 eine Motte in einem der ersten Computer einen Kurzschluss verursacht hatte. US Navy Captain Grace Murray Hopper, eine Pionierin der Computerwissenschaft, entdeckte den Bug und klebte die Motte in ihr Logbuch ein, das heute am Smithsonian Institute aufbewahrt wird. Daraufhin behaupteten Programmierer oft scherzhaft, es sei wohl wieder ein Insekt, wenn ihre Programme fehlerhaft waren, bis der Ausdruck Bug schließlich allgemein gebräuchlich wurde.

Eine andere Version zur Entstehung von „debugging“: Das merkwürdige Wort debugging kommt angeblich aus den Tagen der ersten Computer. Damals waren Computer noch riesige Schränke voll Relais oder Vakuumröhren. Wenn nur ein einziges Teil dieser komplizierten Maschinen ausfiel, stand der ganze Computer still und der Fehler musste erst behoben werden, bevor die Verarbeitung weiter gehen konnte. Angeblich waren des öfteren kleine Käfer (englisch bug) für die Schäden verantwortlich, die sich in den Computern herumtrieben und Teile beschädigten oder Kurzschlüsse verursachten. Deshalb bezeichnet man auch heute im Englischen noch Fehler in Programmen oder Hardware als Bug (Aussprache bagg) und das Suchen und Beheben der Fehler heißt Debugging, die eingedeutschte Form Debuggen.

Diese angebliche Herkunft ist aber falsch; das Wort „Bug“ wurde in der gleichen Bedeutung bereits im 19. Jahrhundert nachgewiesen; seine Herkunft gilt unter Etymologen bislang als ungeklärt.

Siehe auch: Moderne Legende

Das Wort „Bug“ bezieht sich streng genommen auf Programmfehler. Durch die Existenz sogenannter Bugreporting-Tools wie z. B. Bugzilla oder Mantis hat sich der Begriff aber verbreitert. Bugs sind dann nicht mehr zwingend Programmfehler, sondern können auch Wünsche („RFE“s) der Nutzer oder allgemeine Vorgänge sein. Etwa wird in sogenannten Metabugs alle im Rahmen des evolutionären Entwicklungmodells zu erledigenden Punkte erwähnt. Ein bug ist dann ein Element einer Aufgabenliste für eine Programmversion. Manche Open Source Projekte wie z. B. OpenOffice sprechen deshalb lieber von „Issues“, weil dieser Ausdruck treffender den Sachverhalt umschreibt.

Siehe auch

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