Handbuch zur dynamischen Ablaufverfolgung in Solaris

Zeigersicherheit

Als C- oder C++-Programmierer hat Sie der vorangehende Abschnitt möglicherweise ein wenig erschreckt, da Sie wissen, dass die falsche Verwendung von Zeigern in einem Programm zum Programmabsturz führen kann. DTrace ist eine robuste, sichere Umgebung für die Ausführung von D-Programmen, in der diese Fehler keine Programmabstürze verursachen können. Es ist zwar möglich, dass Sie ein fehlerhaftes D-Programm schreiben, doch ungültige D-Zeigerzugriffe bewirken weder, dass DTrace noch der Betriebssystemkernel fehlschlagen oder abstürzen. Stattdessen werden ungültige Zeigerzugriffe von der DTrace-Software erkannt, die Instrumentation deaktiviert und das Problem gemeldet, sodass Sie es beheben können.

Wenn Sie schon einmal ein Java-Programm geschrieben haben, wissen Sie wahrscheinlich, dass Java aus genau diesem Sicherheitsgrund keine Zeiger unterstützt. In D sind Zeiger jedoch erforderlich, da sie einen wesentlichen Bestandteil der Betriebssystemimplementierung in C darstellen. Deshalb bietet DTrace die gleiche Art von Sicherheitsmechanismen, die in der Programmiersprache Java die Beschädigung fehlerhafter Programme durch sich selbst oder andere Programme verhindern. Der Fehlermeldemechanismus in DTrace funktioniert ähnlich wie die Laufzeitumgebung in Java, die Programmierfehler erkennt und eine Ausnahme meldet.

Lassen Sie uns zur Betrachtung der Fehlerbehandlung und -meldung in DTrace absichtlich ein fehlerhaftes D-Programm mit Zeigern schreiben. Geben Sie das folgende D-Programm in einen Texteditor ein und speichern Sie es unter dem Namen badptr.d:


Beispiel 5–1 badptr.d: Veranschaulichung der Fehlerbehandlung in DTrace

BEGIN
{
	x = (int *)NULL;
	y = *x;
	trace(y);
}

Das Programm badptr.d erzeugt einen D-Zeiger namens x, der auf int zeigt. Das Programm weist dem Zeiger den speziellen, für ungültige Zeiger stehenden Wert NULL zu, der ein integrierter Aliasname für die Adresse 0 ist. Die Adresse 0 ist stets als ungültig vereinbart, sodass NULL in C- und D-Programmen dafür als Repräsentationswert eingesetzt werden kann. Mit einem Cast-Ausdruck wird NULL explizit in einen Zeiger auf eine Ganzzahl umgewandelt. Anschließend dereferenziert das Programm den Zeiger über den Ausdruck *x und weist das Ergebnis einer weiteren Variable y zu, bevor es schließlich die Ablaufverfolgung von y versucht. Wenn das D-Programm ausgeführt wird, erkennt DTrace bei der Ausführung der Anweisung y = *x einen ungültigen Zeigerzugriff und meldet den Fehler:


# dtrace -s badptr.d
dtrace: script '/dev/stdin' matched 1 probe
CPU     ID                    FUNCTION:NAME
dtrace: error on enabled probe ID 1 (ID 1: dtrace:::BEGIN): invalid address
(0x0) in action #2 at DIF offset 4
dtrace: 1 error on CPU 0
^C
#

Ein weiteres Problem, das durch Programme mit ungültigen Zeigern verursacht werden kann, ist ein Ausrichtungsfehler. Gemäß der Architekturkonvention werden essenzielle Datenobjekte wie Ganzzahlen im Speicher auf Grundlage ihrer Größe angeordnet. So werden beispielsweise 2-Byte-Ganzzahlen an Adressen ausgerichtet, die Vielfache von 2 sind, 4-Byte-Ganzzahlen an Vielfachen von 4 und so weiter. Wenn Sie einen Zeiger auf eine 4-Byte-Ganzzahl dereferenzieren und die Zeigeradresse ein ungültiger Wert und kein Vielfaches von 4 ist, schlägt der Zugriff mit einem Ausrichtungsfehler fehl. Ausrichtungsfehler in D weisen nahezu immer darauf hin, dass ein Zeiger aufgrund eines Fehlers im D-Programm einen ungültigen oder fehlerhaften Wert besitzt. Ändern Sie im Quellcode von badptr.d die Adresse NULL in (int *)2 ab, um einen Ausrichtungsfehler zur Veranschaulichung zu erzeugen. Da int eine 4-Byte-Ganzzahl und 2 kein Vielfaches von 4 ist, verursacht der Ausdruck *x einen DTrace-Ausrichtungsfehler.

Näheres zum DTrace-Fehlermechanismus finden Sie unter Der Prüfpunkt ERROR.