Avertissement C26430
Le symbole n’est pas testé pour la valeur Null sur tous les chemins d’accès.
C++ Core Guidelines : F.23 : utiliser un <T> not_null pour indiquer que « null » n’est pas une valeur valide
Si le code cherche une valeur null dans les variables de pointeur, il doit le faire de manière cohérente et valider les pointeurs sur tous les chemins. Parfois, une recherche excessive d’une valeur null est toujours meilleure que la possibilité d’un blocage dur dans l’une des branches complexes. Dans l’idéal, ce code doit être refactorisé pour être moins complexe (en le fractionnant en plusieurs fonctions) et pour s’appuyer sur des marqueurs comme gsl::not_null
. Ces marqueurs permettent au code d’isoler des parties de l’algorithme qui peuvent faire des hypothèses fiables sur les valeurs de pointeur valides. La règle TEST_ON_ALL_PATHS
permet de trouver des emplacements où les recherches de valeur null sont incohérentes (ce qui signifie que les hypothèses peuvent nécessiter une révision). Ou, elle peut trouver des bogues réels où une valeur null potentielle peut contourner les recherches de valeur null dans certains chemins de code.
Notes
Cette règle s’attend à ce que le code déréférence une variable de pointeur afin qu’une recherche de valeur null (ou l’application d’une valeur non null) soit justifiée. En l’absence de déréférencement, la règle est suspendue.
L’implémentation actuelle gère uniquement les pointeurs simples (ou leurs alias) et ne détecte pas les pointeurs intelligents, même si les recherches de valeur null s’appliquent également aux pointeurs intelligents.
Une variable est marquée comme vérifiée pour la valeur null lorsqu’elle est utilisée dans les contextes suivants :
- en tant qu’expression de symbole dans une condition de branche, par exemple, dans
if (p) { ... }
; - dans les opérations logiques n’étant pas au niveau du bit ;
- dans les opérations de comparaison où un opérande est une expression constante qui prend la valeur zéro.
Les recherches de valeur null implicites sont supposées lorsqu’une valeur de pointeur est affectée depuis :
- une allocation effectuée avec la levée de
operator new
; - un pointeur obtenu à partir d’un type marqué avec
gsl::not_null
.
Exemple
des tests incohérents révèlent une erreur logique
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);
}
}
des tests incohérents révèlent une erreur logique : corrigé
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);
}
}
Heuristique
Lorsque vous vérifiez qu’un déréférencement de pointeur n’est pas null, cette règle ne nécessite pas que tous les déréférencement aient subi une recherche de valeur null préalablement. Au lieu de cela, cela nécessite une recherche de valeur null avant le premier déréférencement du pointeur. La fonction suivante ne déclenche pas C26430 :
void f(int* p)
{
if (p)
*p = 1;
*p = 2;
}
La fonction suivante génère l’erreur C26430, car il existe un chemin d’accès pour affecter *p
sans recherche de valeur null :
void f(bool b, int* p)
{
if (b && p)
*p = 1;
*p = 2;
}
Les règles C26822 et C26823 s’appliquent au déréférencement d’un pointeur (éventuellement) null.
Cette règle n’effectue pas de suivi de flux de données complet. Elle peut produire des résultats incorrects dans les cas où des vérifications indirectes sont utilisées, par exemple lorsqu’une variable intermédiaire contient une valeur null et est utilisée ultérieurement dans une comparaison.