L'analyseur statique PVS-Studio détecte des fragments de code plutôt complexes et délicats contenant des erreurs. Et comment les résoudre n'est pas toujours clair, même pour une personne, et nous allons maintenant considérer quelques exemples. Par conséquent, il est préférable de ne générer aucune hypothèse sur la correction automatique du code.
Parfois, les programmeurs qui commencent à essayer PVS-Studio demandent: pourquoi l'outil ne propose-t-il pas de corriger automatiquement l'erreur? Fait intéressant, les utilisateurs ne posent plus cette question. Après avoir utilisé l'analyseur pendant un certain temps, il devient clair pour eux que pour la grande majorité des erreurs détectées, aucun remplacement automatique n'est possible. Au moins jusqu'à ce que l'intelligence artificielle soit inventée.
La raison en est que PVS-Studio n'est pas un analyseur de style de code. Il ne suggère pas de changement de format ou de nom. Il ne suggère pas (du moins au moment d'écrire ces lignes :) de remplacer tous les NULL dans le code C ++ par nullptr... Bien que ce soit une bonne suggestion, cela n'a presque rien à voir avec le dépannage.
PVS-Studio détecte les erreurs et les vulnérabilités potentielles. De nombreuses erreurs incitent à la réflexion et nécessitent un changement de comportement du programme. Et seul un programmeur peut décider comment corriger telle ou telle erreur.
Après avoir trouvé une erreur, l'analyseur suggérera très probablement de simplifier le code pour que l'anomalie disparaisse, mais cela ne corrigera pas l'erreur elle-même. Il est très difficile de comprendre ce que le code est réellement censé faire et de proposer une solution utile et significative.
Considérez l'erreur que j'ai analysée dans l'article « 31 février ».
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];
}
}
L'analyseur comprend que les deux tests sont vrais. Mais pourquoi, l'analyseur ne comprend pas. Il ne sait rien des jours, des mois et des autres entités. Et apprendre à comprendre tant oh, combien c'est difficile. La seule chose qui peut vraiment être faite est que l'analyseur suggère de simplifier la fonction:
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, que pouvons-nous dire sur des bagatelles, laissez-le proposer un tel remplacement automatique:
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;
}
Cool, mais inutile;). L'analyseur a supprimé le code qui est superflu du point de vue du langage C ++. Et seule une personne peut comprendre si le code est vraiment redondant ( et cela arrive aussi souvent ), ou s'il y a une faute de frappe dans le code et il est nécessaire de remplacer le mois par le jour .
Le lecteur peut dire que j'épaissis et que le remplacement automatique est approprié. Non. Les gens se trompent sur ce point, que pouvez-vous attendre d'un programme sans âme. Regardez, il y a un exemple intéressant d'édition manuelle inattentive qui ne résout rien. Puisqu'une personne ne peut pas, un programme non plus.
En août de cette année virale, j'ai écrit un articleà propos de la vérification de la bibliothèque PMDK. Entre autres choses, l'article a examiné l'erreur de protection contre les débordements incorrecte:
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;
}
Puisque rel_wait est de type non signé, la vérification suivante de rel_wait <0 n'a aucun sens. Avertissement PVS-Studio: V547 [CWE-570] L'expression «rel_wait <0» est toujours fausse. La valeur du type non signé n'est jamais <0. os_thread_windows.c 359
Quelqu'un s'est inspiré de l'article et a commencé à corriger massivement les erreurs qui y étaient décrites: Correction de divers problèmes signalés par l'analyse PVS-Studio .
Et comment a-t-il été suggéré de corriger le code? Assez ingénu: core: simplifie la mise en œuvre de Windows timer .
Mais le code a été simplifié, pas corrigé! Cela a été remarqué et une discussion correspondante a commencé: PROBLÈME: os_thread_windows.c - get_rel_wait () bloquera si abstime est dans le passé .
Comme vous pouvez le voir, même les gens font des erreurs dans les modifications suggérées. Pourquoi essayer les robots.
Quoi qu'il en soit, le désir de corriger automatiquement les erreurs est un désir très étrange. Chaque changement qui corrige un bogue nécessite une attention et une révision du code. De plus, l'analyseur peut donner des faux positifs, ce qui signifie que vous ne pouvez pas du tout éditer ce code. Analyser votre code et gérer les avertissements n'est pas le bon endroit pour se précipiter. Il est préférable de mettre en œuvre une analyse de code régulière et de corriger lentement les bogues qui apparaissent dans le nouveau code.
Si vous souhaitez partager cet article avec un public anglophone, veuillez utiliser le lien de traduction: Andrey Karpov. Pourquoi PVS-Studio n'offre pas de correctifs automatiques .