
O analisador estático PVS-Studio detecta fragmentos de código bastante complexos e complicados contendo erros. E como corrigi-los nem sempre é claro até mesmo para uma pessoa, e agora consideraremos alguns exemplos. Portanto, é melhor não gerar quaisquer suposições sobre a correção automática de código.
Às vezes, os programadores que começam a experimentar o PVS-Studio perguntam: por que a ferramenta não se oferece para corrigir o erro automaticamente? Curiosamente, os usuários não fazem mais essa pergunta. Depois de usar o analisador por algum tempo, eles percebem que, para a grande maioria dos erros detectados, nenhuma substituição automática é possível. Pelo menos até que a inteligência artificial seja inventada.
A razão é que o PVS-Studio não é um analisador de estilo de código. Não sugere alterações de formatação ou nomenclatura. Ele não sugere (pelo menos no momento da redação deste artigo :) substituir todos os NULLs no código C ++ por nullptr... Embora seja uma boa sugestão, não tem quase nada a ver com a solução de problemas.
PVS-Studio detecta erros e vulnerabilidades potenciais. Muitos erros são instigantes e exigem uma mudança no comportamento do programa. E apenas um programador pode decidir como corrigir este ou aquele erro.
Tendo encontrado um erro, o analisador provavelmente irá sugerir simplificar o código para que a anomalia desapareça, mas isso não irá corrigir o erro em si. Entender o que o código realmente deve fazer e sugerir uma correção útil e significativa é muito difícil.
Considere o erro que analisei no artigo " 31 de fevereiro ".
static const int kDaysInMonth[13] = {
0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
};
bool ValidateDateTime(const DateTime& time) {
if (time.year < 1 || time.year > 9999 ||
time.month < 1 || time.month > 12 ||
time.day < 1 || time.day > 31 ||
time.hour < 0 || time.hour > 23 ||
time.minute < 0 || time.minute > 59 ||
time.second < 0 || time.second > 59) {
return false;
}
if (time.month == 2 && IsLeapYear(time.year)) {
return time.month <= kDaysInMonth[time.month] + 1;
} else {
return time.month <= kDaysInMonth[time.month];
}
}
O analisador entende que ambos os testes são verdadeiros. Mas por que, o analisador não entende. Ele não sabe nada sobre dias, meses e outras entidades. E ensinar a entender isso ah, como é difícil. A única coisa que realmente pode ser feita é o analisador sugerir simplificar a função:
bool ValidateDateTime(const DateTime& time) {
if (time.year < 1 || time.year > 9999 ||
time.month < 1 || time.month > 12 ||
time.day < 1 || time.day > 31 ||
time.hour < 0 || time.hour > 23 ||
time.minute < 0 || time.minute > 59 ||
time.second < 0 || time.second > 59) {
return false;
}
if (time.month == 2 && IsLeapYear(time.year)) {
return true;
} else {
return true;
}
}
Ou, o que podemos dizer sobre ninharias, deixe-o oferecer uma substituição automática:
bool ValidateDateTime(const DateTime& time) {
if (time.year < 1 || time.year > 9999 ||
time.month < 1 || time.month > 12 ||
time.day < 1 || time.day > 31 ||
time.hour < 0 || time.hour > 23 ||
time.minute < 0 || time.minute > 59 ||
time.second < 0 || time.second > 59) {
return false;
}
return true;
}
Legal, mas inútil;). O analisador removeu o código redundante do ponto de vista da linguagem C ++. E só uma pessoa pode entender se o código é realmente redundante ( e isso também acontece com frequência ), ou se há um erro de digitação no código e é necessário substituir mês por dia .
O leitor pode dizer que estou engrossando e que a substituição automática é apropriada. Não. As pessoas se enganam nisso, o que se pode desejar de um programa sem alma. Veja, há um exemplo interessante de edição manual desatenta que na verdade não corrige nada. Visto que um homem não pode, nem um programa pode.
Em agosto deste ano viral, escrevi um artigosobre como verificar a biblioteca PMDK. Entre outras coisas, o artigo considerou o erro de proteção incorreta contra estouro:
static DWORD
get_rel_wait(const struct timespec *abstime)
{
struct __timeb64 t;
_ftime64_s(&t);
time_t now_ms = t.time * 1000 + t.millitm;
time_t ms = (time_t)(abstime->tv_sec * 1000 +
abstime->tv_nsec / 1000000);
DWORD rel_wait = (DWORD)(ms - now_ms);
return rel_wait < 0 ? 0 : rel_wait;
}
Como rel_wait é do tipo sem sinal, a verificação subsequente para rel_wait <0 não tem sentido. Aviso do PVS-Studio: V547 [CWE-570] A expressão 'rel_wait <0' é sempre falsa. O valor do tipo sem sinal nunca é <0. os_thread_windows.c 359
Alguém se inspirou no artigo e começou a consertar maciçamente os erros descritos nele: Corrija vários problemas relatados pela análise do PVS-Studio .
E como foi sugerido corrigir o código? Muito simples: núcleo: simplifica a implementação do Windows Timer .

Mas o código foi simplificado, não corrigido! Isso foi percebido e uma discussão correspondente começou: PROBLEMA: os_thread_windows.c - get_rel_wait () irá bloquear se abstime está no passado .
Como você pode ver, até as pessoas cometem erros nas edições sugeridas. Por que experimentar robôs.
De qualquer forma, o desejo de corrigir erros automaticamente é um desejo muito estranho. Cada mudança que corrige um bug requer atenção e revisão do código. Além disso, o analisador pode fornecer falsos positivos, o que significa que você não pode editar esse código. Analisar seu código e lidar com avisos não é o lugar para se apressar. É melhor implementar a análise de código regular e corrigir lentamente os bugs que aparecem no novo código.

Se você deseja compartilhar este artigo com um público que fala inglês, por favor, use o link de tradução: Andrey Karpov. Por que o PVS-Studio não oferece correções automáticas .