In Abschnitt 5.5.5 fordert die IEC 62304 für Software der Klassen B und C lapidar: „Der Hersteller soll Software-Unit-Verifikation durchführen und die Ergebnisse dokumentieren“. Für ein besseres Verständnis sind dabei zwei Fragen zu beantworten: Was versteht die IEC 62304 unter einer Software-Unit und was bedeutet Verifikation im Sinne dieser Norm?

Was ist eine Software-Unit?

Bild 1: Eine Software-Unit im Sinne der IEC 62304 ist ein Software-Element auf der untersten Ebene eines Software-Systems.

Bild 1: Eine Software-Unit im Sinne der IEC 62304 ist ein Software-Element auf der untersten Ebene eines Software-Systems. Hitex

Abschnitt 3.25 definiert eine Software-Unit als ein Software-Element („item“), das sich auf der untersten Ebene des Software-Systems befindet und das nicht weiter unterteilt wird (Bild 1); Abschnitt 3.28 wiederholt dies sinngemäß. Allerdings gibt die zugehörige Notiz an, dass der Hersteller die Granularität der Software-Units definiert. In Abschnitt B.5.4 kommt noch ein weiteres Merkmal für eine Software-Unit hinzu: Software-Units können separat getestet werden. Insgesamt charakterisiert die Norm eine Software-Unit also dadurch, dass sie zu Testzwecken nicht weiter unterteilt ist und sich sinnvoll separat testen lässt. Dass der Hersteller die Granularität der Software-Units selbst bestimmen kann, schwächt diese Charakterisierung allerdings ab. Der Grund dafür ist, dass die IEC 62304 universell einsetzbar sein soll, unabhängig beispielsweise vom Umfang der Software oder der Programmiersprache. Dies legt aber auch Verantwortung in die Hände des Herstellers: Er sollte die Granularität vernünftig wählen und weder zu große noch zu kleine Units spezifizieren.

Es ist verlockend, die gesamte Software in nur wenige, große Units aufzuteilen, in der (falschen) Annahme, dadurch den Unit-Testaufwand zu reduzieren. Das Gegenteil ist richtig: Durch übergroße Units steigt die Komplexität und der Aufwand des Tests, weil das „teile und herrsche“-Prinzip, welches dem Unit-Test zugrunde liegt, nicht ausreichend umgesetzt wird. Abgesehen von dieser Freiheit des Herstellers, legt die Programmiersprache fest, was eine Software-Unit ist: Für die Programmiersprache C ist es eine Funktion im Sinne von C, für die objektorientierten Programmiersprachen wie C++, Java, C# ist es eine Methode, für Programmiersprachen wie Ada oder Pascal eine Prozedur beziehungsweise Funktion.

Bei medizinischer Software für eingebettete Systeme ist oftmals C die Programmiersprache der Wahl, weshalb der Beitrag im Folgenden von dieser Sprache ausgeht. Die Software-Architektur legt fest, welche Units beziehungsweise Funktionen (im Sinne von C) existieren und welche Anforderungen sie erfüllen sollen. Eine gute Software-Architektur stellt somit sicher, dass die Units nicht zu groß ausfallen und dass sie schmale Schnittstellen zu anderen Units besitzen. Mehrere kleine Funktionen lassen sich zu einer Unit zusammenfassen.

Bild 2: Die zwei Funktionen is_value_in_range() und absolute() lassen sich zu einer Software-Unit zusammenfassen.

Bild 2: Die zwei Funktionen is_value_in_range() und absolute() lassen sich zu einer Software-Unit zusammenfassen. Hitex

In Bild 2 ruft die Funktion is_value_in_range() die Funktion absolute() auf. Obwohl sich sowohl is_value_in_range() als auch absolute() isoliert testen lassen, ist es vertretbar, die beiden Funktionen zu einer Unit zusammenzufassen, da absolute() sehr übersichtlich ist. Zudem würde ein Fehler in absolute() mit hoher Wahrscheinlichkeit beim Test von is_value_in_range() auffallen.

Was bedeutet Verifikation?

Abschnitt 3.33 der IEC 62304 definiert Verifikation als „Bestätigung durch Bereitstellung eines objektiven Nachweises, dass spezifizierte Anforderungen erfüllt wurden“. Die Anforderungen für die Software-Units entstehen bei der Aufteilung der Software in Units, was Abschnitt 5.4.1 der Norm fordert. Diese Aufteilung korrespondiert mit der Dekomposition der Anforderungen für die Gesamt-Software. Auch Aspekte der Risiko-Analyse fließen in diese Aufteilung ein. Dadurch entsteht zwangsläufig eine mehr oder weniger genaue Beschreibung der Funktionalität, die eine Software-Unit haben soll. Für Software der Klasse C fordert Abschnitt 5.4.2 für jede Software-Unit ein derartig detailliertes Design, dass die korrekte Implementierung möglich ist. Abschnitt 5.4.3 fordert zusätzlich ein so detailliertes Design für alle Schnittstellen der Software-Unit zu externen Komponenten (Hardware oder Software) als auch für alle Schnittstellen zwischen Software-Units, dass sich jede Software-Unit und ihre Schnittstellen korrekt implementieren lassen. Die Designs sind zu dokumentieren – insbesondere für Software der Klasse C liegen damit die Anforderungen ausreichend detailliert vor.

Einen Verifikationsprozess für Software-Units (Strategien, Methoden und Prozeduren) fordert Abschnitt 5.5.2 der Norm. Die Verifikation kann durch Testen erfolgen, wobei die Testprozeduren für Software der Klassen B und C auf Angemessenheit hin zu evaluieren sind. Beispiele für Akzeptanzkriterien von Software-Units nennt Abschnitt 5.5.3: Implementiert der Software-Code Anforderungen, inklusive der Risikokontrollmaßnahmen? Ist der Software-Code frei von Widersprüchen zum Interface-Design der Software-Unit? Ist der Software-Code konform mit Programmierverfahren und Codier-Standards?

Nachverfolgbarkeit

Zur Überprüfung der Implementierung der Anforderungen an die Software-Unit im Software-Code lassen sich Testfälle erstellen. Werden diese Testfälle bestanden, werden Anforderungen implementiert. Die IEC 62304 fordert dabei jedoch nicht explizit, dass alle Anforderungen durch den Software-Code implementiert sein müssen. Sollen Risikokontrollmaßnahmen (beispielsweise die Überprüfung von Parametern) im Software-Code implementiert werden, lassen sich diese wie Anforderungen behandeln. Die Zuordnung von Anforderungen zu Testfällen erfolgt oft in einer matrixartigen Darstellung.

Bild 3: Zuordnung von Anforderungen zu Testfällen im Unit-Test-Werkzeug Tessy.

Bild 3: Zuordnung von Anforderungen zu Testfällen im Unit-Test-Werkzeug Tessy. Hitex

Bild 3 zeigt die Link-Matrix des Unit-Test-Werkzeugs Tessy. Jede Zeile enthält eine Anforderung, jede Spalte einen Testfall. Die Markierungen an den Kreuzungspunkten geben an, dass der betreffende Testfall eine Anforderung prüft. Der Anforderung in der letzten Zeile (Negative length) ist offensichtlich kein Testfall zugeordnet. Die Zuordnungen etabliert der Anwender, eine automatische Zuordnung ist im Allgemeinen nicht möglich.

Interface-Design

Bild 4: Das Interface der Software-Unit func().

Bild 4: Das Interface (links) und ein Testfall (rechts) der Software-Unit func(). Hitex

Auch der Nachweis, dass der Software-Code ohne Widersprüche zum Interface-Design der Software-Unit ist, lässt sich mithilfe des Werkzeugs Tessy erbringen. Es ermittelt und stellt das Interface aus dem Software-Code dar. Eine Interface-Beschreibung beinhaltet die Struktur und die Semantik des Interfaces. Der linke Teil von Bild 4 zeigt die von Tessy ermittelte Interface-Struktur der Software-Unit func(): Das Interface besteht aus der globalen Variablen m, die durch die Software-Unit geschrieben, aber nicht gelesen wird (Passierrichtung OUT); m ist somit ein Ergebnis der Software-Unit. Die Software-Unit hat einen Parameter k, den die Software-Unit nur liest (Passierrichtung IN) und der deshalb eine Eingabe für die Software-Unit darstellt. Ferner existiert ein Return-Wert, der eine Ausgabe der Software-Unit darstellt, da er von der Software-Unit zurückgegeben wird (Passierrichtung OUT). Zur Struktur des Interfaces gehören ebenfalls die Datentypen der Variablen. Liegt die vorgegebene Interface-Beschreibung nicht in maschinenlesbarer Form vor, ist ein Review zum Abgleich des im Software-Code implementierten Interfaces mit der vorgegebenen Interface-Beschreibung notwendig.

Die Semantik des Interfaces ergibt sich aus dem Verhalten der Software-Unit, was sich insbesondere dadurch manifestiert, welche Ausgabewerte aufgrund bestimmter Eingabewerte entstehen. Dieses Verhalten der Software-Unit lässt sich durch Testfälle überprüfen, für die die Anforderungen an die Software-Unit bekannt sein müssen. Die rechte Seite in Bild 4 zeigt einen bereits durchgeführten Testfall. Der Parameter k hatte vor dem Test den Wert 1, die globale Variable m hat nach dem Test den Wert 2 und der Return-Wert der Software-Unit ist bei diesem Testfall 3. Der grüne Hintergrund symbolisiert dabei, dass die Ausgabewerte den Erwartungen entsprechen. Um zu verstehen, weshalb diese Ausgabewerte korrekt sind, müssen die im Test geprüften Anforderungen allerdings bekannt sein.

Codier-Standards

Eck-DAten

Die Norm IEC 62304 verlangt vom Hersteller, seinem Software-System eine Software-Sicherheits-Klasse zuzuordnen, abhängig vom Gefahrenpotenzial (für Personen) und dem akzeptablen Risiko.

  • Klasse A: Das Software-System kann nicht zu einer gefährlichen Situation beitragen oder die gefährliche Situation birgt kein inakzeptables Risiko.
  • Klasse B: Das Software-System kann zu einer gefährlichen Situation beitragen und die gefährliche Situation birgt inakzeptables Risiko und der mögliche Schaden ist nicht-ernsthafte Verletzung.
  • Klasse C: Das Software-System kann zu einer gefährlichen Situation beitragen und die gefährliche Situation birgt inakzeptables Risiko und der mögliche Schaden ist Tod oder ernsthafte Verletzung.

Diese Klassendefinitionen gelten sinngemäß auch für Software-Units.

Das Kriterium Codier-Standards verfolgt den Zweck, für Verständlichkeit, Spracheinschränkungen und Steuerung der Komplexität zu sorgen (Abschnitt B.5.5). Um die Verständlichkeit zu erhöhen ist es sinnvoll, einen Codier-Stil einzuhalten. Dieser könnte beispielsweise Vorgaben zur Namensgebung von Variablen oder zu Einrückungen oder zum Setzen von geschweiften Klammern beinhalten. Diese Vorgaben erleichtern das Verstehen von Software-Code, beispielsweise bei einem Review.

Leider sind diese Regeln von Firma zu Firma (und manchmal von Projekt zu Projekt) unterschiedlich, sodass eine automatische Prüfung durch ein Commercial-of-the-Shelf-Werkzeug (COTS) schwierig ist. Uneinheitliche Einrückungen können den Aufwand beim Review und bei der Wartung erhöhen, verursachen jedoch kein Fehlverhalten der Software. Ein potenzielles Fehlverhalten der Software soll durch vorgefertigte Standards oder Regelwerke verhindert werden. Beispiele dafür sind der CERT-C-Coding-Standard des Software Engineering Institute (SEI) der Carnegie Mellon Universität in Pittsburgh, der Joint-Strike-Fighter-Air-Vehicle-Standard (JSF AV) für C++ von Lockheed Martin aus dem Jahr 2005 oder die Misra-Regeln der Motor Industry Software Reliability Association, aktuell in ihrer dritten Version Misra-C:2012. In Deutschland sind Letztere sehr populär und in der Automobil-Industrie weit verbreitet.

Bild 5: Das statische Analyse-Werkzeug Klocwork hat ein potenzielles Problem im Software-Code von f3() entdeckt und markiert.

Bild 5: Das statische Analyse-Werkzeug Klocwork hat ein potenzielles Problem im Software-Code von f3() entdeckt und markiert. Hitex

Die Regeln sollen die Gefährlichkeit der Sprache C einschränken, beispielsweise durch die Vermeidung von unspezifiziertem, undefiniertem und Compiler-abhängigem Verhalten. In der Programmiersprache C gestaltet es sich zusätzlich recht einfach, Code zu schreiben, der nicht das erwartete Verhalten bewirkt. Ein Beispiel dafür zeigt Bild 5. Der Rückgabewert der Software-Unit f3() ist hier nicht wie erwartet 382, sondern 380, da der Variablen b nicht der Wert zehn sondern der Wert acht zugewiesen ist. Grund hierfür ist die führende Null von „010“, die diese in eine oktale Konstante verwandelt. Um derartigen Missverständnissen vorzubeugen, verbieten die Misra-C:2012-Regeln den Gebrauch von oktalen Konstanten ganz.

Das statische Analysewerkzeug Klocwork hat diese Regelverletzung in Zeile 49 entdeckt und markiert. Statische Analysewerkzeuge übernehmen auch die Aufgabe, Maße für die Komplexität der Software zu ermitteln. So ist es möglich, die in Abschnitt B.5.5 der IEC 62304 geforderte Steuerung der Komplexität durchzuführen, indem eine Kontrolle erfolgt, dass bestimmte Metriken oder Maße festgelegte Werte nicht überschreiten. Ein einfaches Maß hierfür ist Lines-of-Code (LOC), das die Anzahl der Code-Zeilen in einer Software-Unit angibt. Durch Überwachen dieser Größe lässt sich vermeiden, dass übergroße Software-Units entstehen. Ein Maß, das häufig zur Beurteilung der Komplexität zum Einsatz kommt, ist die zyklomatische Komplexität nach McCabe. Sie korreliert mit der Anzahl der binären Entscheidungen im Software-Code und gibt die Anzahl der vollständigen, linear unabhängigen Pfade durch den Code an, berücksichtigt allerdings keine Berechnungen oder zusammengesetzten Entscheidungen.

Weitere Akzeptanzkriterien

Abschnitt 5.5.4 der Norm beinhaltet weitere Akzeptanzkriterien für Software der Klasse C, beispielsweise bezüglich des Daten- und Kontrollflusses oder der Verwendung von Grenzwerten in den Testfällen. Gänzlich abwesend in der IEC 62304 sind jedoch Kriterien, die beispielsweise die Messung der durch die Tests der Software-Unit erreichten Codeüberdeckung betreffen. Andere Normen wie die IEC 61508 oder die ISO 26262 legen besonders auf die Messung der Codeüberdeckung großen Wert.