Warnung C26430
Das Symbol wird nicht auf Nullwerte für alle Pfade getestet.
C++ Core Guidelines: F.23: Verwenden Sie die Klasse not_null<T>, um anzugeben, dass „NULL“ kein gültiger Wert ist.
Wenn Code jemals Zeigervariablen auf NULL überprüft, sollte dies konsistent erfolgen, und es sollten alle Zeiger auf alle Pfade überprüft werden. Manchmal ist die übermäßig aggressive Überprüfung auf NULL immer noch besser als die Möglichkeit eines harten Absturzes in einem der komplizierten Branches. Im Idealfall sollte dieser Code so umgestaltet werden, dass er weniger komplex ist (indem er in mehrere Funktionen aufgeteilt wird) und auf Markierungen wie gsl::not_null
basiert. Diese Markierungen ermöglichen es dem Code, Teile des Algorithmus zu isolieren, die sichere Annahmen zu gültigen Zeigerwerten machen können. Die Regel TEST_ON_ALL_PATHS
hilft dabei, Stellen zu finden, an denen NULL-Überprüfungen inkonsistent sind (d. h. Annahmen können eine Überprüfung erfordern). Es kann auch vorkommen, dass tatsächlich Fehler gefunden werden, bei denen ein potenzieller NULL-Wert NULL-Überprüfungen in einigen Codepfaden umgehen kann.
Hinweise
Bei dieser Regel wird erwartet, dass Code eine Zeigervariable dereferenziert, sodass eine NULL-Überprüfung (oder Erzwingung eines Nicht-NULL-Werts) gerechtfertigt wäre. Wenn keine Dereferenzierung stattfindet, wird die Regel ausgesetzt.
Die aktuelle Implementierung behandelt nur einfache Zeiger (oder ihre Aliase) und erkennt keine intelligenten Zeiger, obwohl NULL-Überprüfungen auch für intelligente Zeiger gelten.
Eine Variable wird als eine auf NULL überprüfte Variable markiert, wenn sie in den folgenden Kontexten verwendet wird:
- als Symbolausdruck in einer Branchbedingung (z. B. in
if (p) { ... }
) - in nicht bitweisen logischen Vorgängen
- in Vergleichsvorgängen, bei denen ein Operand ein konstanter Ausdruck ist, der als null ausgewertet wird
Implizite NULL-Überprüfungen werden angenommen, wenn ein Zeigerwert von einem der folgenden Elemente zugewiesen wird:
- Zuordnung, die mit der Ausgabe von
operator new
durchgeführt wird - Zeiger, der von einem mit
gsl::not_null
gekennzeichneten Typ abgerufen wurde
Beispiel
Bei einem inkonsistenten Test tritt ein logischer Fehler auf.
void merge_states(const state *left, const state *right) // C26430
{
if (*left && *right)
converge(left, right);
else
{
// ...
if (!left && !right) // Logic error!
discard(left, right);
}
}
Bei einem inkonsistenten Test tritt ein logischer Fehler auf (korrigiert).
void merge_states(gsl::not_null<const state *> left, gsl::not_null<const state *> right)
{
if (*left && *right)
converge(left, right);
else
{
// ...
if (*left && *right)
discard(left, right);
}
}
Heuristik
Wenn sichergestellt wird, dass eine Dereferenzierung eines Zeigers nicht NULL ist, erfordert diese Regel nicht, dass bei jeder Dereferenzierung zuvor eine NULL-Überprüfung durchgeführt wird. Stattdessen ist vor der ersten Dereferenzierung des Zeigers eine NULL-Überprüfung erforderlich. Die folgende Funktion löst C26430 nicht aus:
void f(int* p)
{
if (p)
*p = 1;
*p = 2;
}
Die folgende Funktion generiert C26430, da es einen Pfad zum Zuweisen von *p
ohne NULL-Überprüfung gibt:
void f(bool b, int* p)
{
if (b && p)
*p = 1;
*p = 2;
}
Die Regeln C26822 und C26823 gelten für das Dereferenzieren eines (potenziellen) NULL-Zeigers.
Diese Regel bietet keine vollständige Datenfluss-Nachverfolgung. Sie kann zu falschen Ergebnissen führen, wenn indirekte Überprüfungen verwendet werden (z. B. wenn eine Zwischenvariable einen NULL-Wert enthält und später in einem Vergleich verwendet wird).