Aviso C26430
O símbolo não é testado quanto à nulidade em todos os caminhos.
Principais diretrizes do C++: F.23: Use um not_null<T> para indicar que "nulo" não é um valor válido
Se o código sempre verifica se as variáveis de ponteiro são nulas, ele deverá fazê-lo de forma consistente e validar os ponteiros em todos os caminhos. Às vezes, a verificação excessivamente agressiva de nulo ainda é melhor do que a possibilidade de uma falha grave em uma das ramificações complicadas. Idealmente, esse código deve ser refatorado para ser menos complexo (dividindo-o em várias funções) e depender de marcadores como gsl::not_null
. Esses marcadores permitem que o código isole partes do algoritmo que podem fazer suposições seguras sobre valores de ponteiro válidos. A regra TEST_ON_ALL_PATHS
ajuda a encontrar locais em que as verificações de nulidade são inconsistentes (o que significa que as suposições podem exigir revisão). Ou, ela encontra erros reais em que um valor nulo em potencial pode ignorar as verificações de nulidade em alguns dos caminhos de código.
Comentários
Esta regra espera que o código desreferencie uma variável ponteiro de modo que uma verificação de nulo (ou a garantia de um valor não nulo) seja justificada. Se não houver desreferência, a regra será suspensa.
A implementação atual lida apenas com ponteiros simples (ou seus aliases) e não detecta ponteiros inteligentes, embora as verificações de nulidade também sejam aplicáveis a ponteiros inteligentes.
Uma variável é marcada como verificada quanto a nulidade quando é usada nos seguintes contextos:
- como uma expressão de símbolo em uma condição de ramificação, por exemplo, em
if (p) { ... }
; - em operações lógicas não bit a bit;
- em operações de comparação em que um operando é uma expressão constante avaliada como zero.
Verificações implícitas de nulo são assumidas quando um valor de ponteiro é atribuído a partir de:
- uma alocação realizada com o lançamento
operator new
; - um ponteiro obtido de um tipo marcado com
gsl::not_null
.
Exemplo
teste inconsistente revela erro lógico
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);
}
}
teste inconsistente revela erro lógico – corrigido
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);
}
}
Heurística
Ao garantir que uma desreferência de um ponteiro não seja nula, esta regra não exige que cada desreferência tenha uma verificação de nulo prévia. Em vez disso, ela exige uma verificação de nulidade antes da primeira desreferência do ponteiro. A função a seguir não dispara o C26430:
void f(int* p)
{
if (p)
*p = 1;
*p = 2;
}
A função a seguir gera C26430 porque há um caminho para atribuir *p
sem uma verificação de nulidade:
void f(bool b, int* p)
{
if (b && p)
*p = 1;
*p = 2;
}
As regras C26822 e C26823 se aplicam à desreferência de um ponteiro (possivelmente) nulo.
Essa regra não faz o acompanhamento completo do fluxo de dados. Ela pode produzir resultados incorretos nos casos em que são usadas verificações indiretas, como quando uma variável intermediária contém um valor nulo e é usada posteriormente em uma comparação.