Erfolgreiche ePaper selbst erstellen
Machen Sie aus Ihren PDF Publikationen ein blätterbares Flipbook mit unserer einzigartigen Google optimierten e-Paper Software.
208<br />
10 <strong>Race</strong> <strong>Conditions</strong><br />
onsmechanismen und alle gemeinsam benutzten Variablen modelliert und dazu<br />
speichert, ob diese lesend und/oder schreibend benutzt werden. In diesem Graphen<br />
werden dann alle möglichen Programmpfade eines Threads durchlaufen<br />
und auf Basis dieser Traversierung kommt ein dynamischer Algorithmus zum<br />
Einsatz, zum Beispiel Eraser. Klingt bis jetzt nicht so schwierig. Der Teufel steckt<br />
aber im Detail.<br />
Statische Werkzeuge haben speziell bei der Verwendung von Zeigern Probleme.<br />
Sie können dann nicht immer feststellen, ob eine Variable von zwei<br />
Threads gemeinsam verwendet wird und müssen sich dann auf Heuristiken stützen,<br />
die zum Beispiel versuchen, über den Typ zu ermitteln, ob die Dereferenzierung<br />
potenziell zur Laufzeit die gleiche Adresse betreffen kann. Semaphore können<br />
binär (als Locks) verwendet werden oder als Zähler mit einem potenziell von<br />
0 oder 1 verschiedenen Zählerstand. Auch da muss das Werkzeug eine Annahme<br />
treffen, die zum Beispiel nach bekannten Design-Mustern für die Verwendung als<br />
Zähler sucht. Eine weitere Problemstellung – und nicht die einzige – ist das<br />
Erkennen, wann Code parallel ausgeführt wird. Enthält der Code Zeiger auf<br />
Unterprogramme (Function Pointers), so kann es sehr schwer werden, festzustellen,<br />
in welchem Thread-Kontext eine Prozedur ausgeführt wird. Auch hier müssen<br />
dann wieder Heuristiken herhalten.<br />
Wegen der Notwendigkeit des Einsatzes von Heuristiken neigen statische<br />
Analysewerkzeuge zu deutlich mehr Falschwarnungen als dynamische Verfahren.<br />
Ein Großteil der Intelligenz von statischen Werkzeugen steckt daher in Mechanismen<br />
zur Ausfilterung und Priorisierung dieser Falschwarnungen.<br />
Andere statische Verfahren verwenden anstelle des Kontrollflussgraphen abstrakte<br />
Interpretation (siehe auch Kapitel 11 für ein weiteres Anwendungsbeispiel<br />
von abstrakter Interpretation), und es gibt auch Ansätze mit Model Checking<br />
und formalen Korrektheitsbeweisen. Es ist davon auszugehen, dass die formalen<br />
Methoden bei großen Anwendungen schwer durchführbar sind. Ein Werkzeug<br />
zur statischen Data-<strong>Race</strong>-Analyse in C ist zum Beispiel das gratis erhältliche<br />
LockLint, Teil von Oracle Solaris Studio.<br />
10.3.2 Vergleich zur dynamischen Data-<strong>Race</strong>-Analyse<br />
Im Gegensatz zu den dynamischen Verfahren ist es bei statischen Verfahren nicht<br />
notwendig, Testtreiber zu schreiben. Das ist von großem Vorteil, wenn man Systeme<br />
analysiert, für die es keine umfassenden Systemtests mit hoher struktureller<br />
Testabdeckung gibt oder wenn Testhardware nicht immer zur Hand ist. Der Test<br />
von Linux ist ein klassisches Beispiel: unzählige Hardware-Treiber. Für dynamische<br />
Tests müsste immer die jeweilige Hardware parat sein!<br />
Nachdem der Code zur Analyse nicht instrumentiert werden muss, spielen<br />
Platz- oder Laufzeitprobleme am Zielsystem keine Rolle. Die Ersparnis der<br />
Erstellung der Testtreiber wird aber teilweise durch den hohen Aufwand bei der