После появления переводной статьи про Статический анализ в GCC 10, и ожидаемой реакции присутствующих здесь представителей разработчика коммерческого статического анализатора PVS-Studio, у меня возник вопрос: «Почему же представители отказываются проверить свой продукт на таких простых примерах для статического анализа, и не скрывают ли они чего?»
Собственно, пришлось сделать это самому.
Обнаружена с диагностикой:
V586 The 'free' function is called twice for deallocation of the same memory space. Inspect the first argument. Check lines: 5, 6. 1_dbl_free.c 6
Пройден
Непонятная ругань на константу в malloc, но ошибка обнаружена — недоступный код и неиспользованная память:
V118 malloc() function accepts a dangerous expression in the capacity of an argument. 2_longjump.c 13
V779 Unreachable code detected. It is possible that an error is present. 2_longjump.c 15
V799 The 'ptr' variable is not used after memory has been allocated for it. Consider checking the use of this variable. 2_longjump.c 13
Пройден
Обнаружены:
V118 malloc() function accepts a dangerous expression in the capacity of an argument. 3_fopen.c 7
V773 Visibility scope of the 'f' file handle was exited without closing the file. A resource leak is possible. 3_fopen.c 9
V773 Visibility scope of the 'p' pointer was exited without releasing the memory. A memory leak is possible. 3_fopen.c 9
V799 The 'p' variable is not used after memory has been allocated for it. Consider checking the use of this variable. 3_fopen.c 7
Пройден
Баг обнаружен:
V774 The 'n' pointer was used after the memory was released. 4_use_after_free.c 9
V591 Non-void function should return a value. 4_use_after_free.c 11
Пройден
Выданы предупреждения, не относящиеся к ошибке:
V104 Implicit conversion of 'n' to memsize type in an arithmetic expression: sizeof (int) * n 5_free_nonheap.c 11
V799 The 'ptr' variable is not used after memory has been allocated for it. Consider checking the use of this variable. 5_free_nonheap.c 11
Провален
Провален
Хотя это настолько специфическая диагностика, что я бы не ставил ее в укор.
Далее я прошелся по перечню диагностик в GCC 10 и дописал примеры, потому дальнейшие тесты с исходниками.
PVS не обнаружил этих ошибок
GCC 10 обнаружил double-fclose но не обнаружил free для закрытого хендла.
Провален
PVS не заметил ничего, GCC10 отработал верно
Провален
Провален обоими участниками, хотя в простых случаях GCC обнаруживает такое, но это еще не функция -fanalyzer (а может еще не реализована).
Провален
Похоже, еще не работают в GCC10 -fanalyzer.
PVS такое отлавливает, как много раз уже демонстрировалось.
Пройден
Статический анализ в PVS-Studio определенно есть.
Хотя и не без некоторых недостатков, но и им стоит пользоваться, тем более, что будут обнаружены и многие человеческие ошибки, не только из области статического анализа.
Andrey2008 Ды, неинтересно мне это. Поймал/не поймал синтетическую ошибку, это ничего не говорит о возможностях анализатораДолжны же они как то прогонять юнит-тесты своего продукта и как, если не на таких синтетических простых примерах?!
Собственно, пришлось сделать это самому.
Тест №1. Самый простой пример ошибки double-free
Обнаружена с диагностикой:
V586 The 'free' function is called twice for deallocation of the same memory space. Inspect the first argument. Check lines: 5, 6. 1_dbl_free.c 6
Пройден
Тест №2. longjmp() мимо free()
Непонятная ругань на константу в malloc, но ошибка обнаружена — недоступный код и неиспользованная память:
V118 malloc() function accepts a dangerous expression in the capacity of an argument. 2_longjump.c 13
V779 Unreachable code detected. It is possible that an error is present. 2_longjump.c 15
V799 The 'ptr' variable is not used after memory has been allocated for it. Consider checking the use of this variable. 2_longjump.c 13
Пройден
Тест №3. Утечки malloc() и незакрытые файлы fopen()
Обнаружены:
V118 malloc() function accepts a dangerous expression in the capacity of an argument. 3_fopen.c 7
V773 Visibility scope of the 'f' file handle was exited without closing the file. A resource leak is possible. 3_fopen.c 9
V773 Visibility scope of the 'p' pointer was exited without releasing the memory. A memory leak is possible. 3_fopen.c 9
V799 The 'p' variable is not used after memory has been allocated for it. Consider checking the use of this variable. 3_fopen.c 7
Пройден
Тест №4. Контроль использования памяти после ее освобождения
Баг обнаружен:
V774 The 'n' pointer was used after the memory was released. 4_use_after_free.c 9
V591 Non-void function should return a value. 4_use_after_free.c 11
Пройден
Тест №5. Контроль освобождения указателя не на кучу (heap)
Выданы предупреждения, не относящиеся к ошибке:
V104 Implicit conversion of 'n' to memsize type in an arithmetic expression: sizeof (int) * n 5_free_nonheap.c 11
V799 The 'ptr' variable is not used after memory has been allocated for it. Consider checking the use of this variable. 5_free_nonheap.c 11
Провален
Тест №6. Недопустимый вызов внутри обработчика signal()
Провален
Хотя это настолько специфическая диагностика, что я бы не ставил ее в укор.
Далее я прошелся по перечню диагностик в GCC 10 и дописал примеры, потому дальнейшие тесты с исходниками.
Тест №7. Двойное закрытие файла и освобождение закрытого FILE*
PVS не обнаружил этих ошибок
GCC 10 обнаружил double-fclose но не обнаружил free для закрытого хендла.
#include <stdlib.h>
void closefile(FILE* f) {
fclose(f);
}
void test(const char *filename) {
FILE *f = fopen(filename, "r");
void *p = malloc(1024);
/* do stuff */
closefile(f);
fclose(f);
free (p);
free(f); // <- UB
}
Провален
Тест №8. longjmp() на устаревший стек
PVS не заметил ничего, GCC10 отработал верно
#include <setjmp.h>
#include <stdlib.h>
static jmp_buf env;
static int i;
static void inner(void) {
longjmp(env, 1);
}
static void middle(void) {
inner();
}
void outer(void) {
i = setjmp(env);
}
void outer_x2(void) {
outer();
if (i == 0)
middle();
}
Провален
Тест №9. Возврат указателя на стековую переменную
Провален обоими участниками, хотя в простых случаях GCC обнаруживает такое, но это еще не функция -fanalyzer (а может еще не реализована).
#include<stdlib.h>
struct str1 {
char buf[10];
};
struct str1 * ret(int sel)
{
struct str1 var1, *pval;
if(sel == 1)
pval = &var1;
else if(sel != 1)
pval = (struct str1 *)malloc(1000);
return pval;
}
Провален
Тест №10. Диагностики tainted-array-index и use-of-uninitialized-value
Похоже, еще не работают в GCC10 -fanalyzer.
PVS такое отлавливает, как много раз уже демонстрировалось.
Пройден
Вывод
Статический анализ в PVS-Studio определенно есть.
Хотя и не без некоторых недостатков, но и им стоит пользоваться, тем более, что будут обнаружены и многие человеческие ошибки, не только из области статического анализа.
fougasse
Не умаляя достоинств PVS (и рискуя получить из плюсомёта) ребята оттуда изначально плохо реагировали на любую критику.
Помню еще на rsdn любые неудобные вопросы вызывали реакцию "собаки лают, караван идёт" с намёком, что вопрошающий именно эта собака, и просто не понимает о чём говорит.
Попытки сравнить ребят с бесплатным cppcheck тоже не вызывали восторга со стороны Андрея и коллег.
Понимаю, что одно мнение погоды не делает, и компания деньги на бутерброды с маслом заработает и без еще пары клиентов, но я во всех компаниях где работал(в Европе) принципиально не упоминаю их продукт, если речь идёт о анализе кода.
Ребятам бы подтянуть скилл общения, хотя, как мне кажется, их подход устраивает и этого и не требует.
0xd34df00d
Ну только тут дело такое, что где-то вы не упомянули, где-то в двух компаниях за последние 5 лет я либо не упомянул, либо прямо отговаривал, и вот уже четыре клиента потеряно.
fougasse
Я думаю, что клиентов отпугнула бы и "цена по запросу". Не в курсе, как оно сейчас, но раньше — это тоже было предметом дискуссий и ответов со стороны PVS в стиле "вы не понимаете, нам нормально, у нас покупают, проходите, не задерживайте".
Siemargl Автор
стоимость не тема данной статьи и дискуссии
мы тут из любви к искусству
fougasse
Мы тут обсуждаем общее отношение к другим мнениям.
И оно грубовато-надменное.
Siemargl Автор
Ну -1 к карме я уже получил =)
Andrey2008
Пойду поправлю справедливость. +1.
Siemargl Автор
Спс, я надеюсь и свой функционал улучшите до 10/10.
Но кроме этого, есть проблема false positives, даже если просто включать варнинги в компиляторе, не касаемо PVS, а для всех — в т.ч стандартных настроек MSVS.
Я не знаю, как с этим бороться, а это отличный демотиватор выключить все проверки.
technic93
Аннотациями. Типа в комментарии к коду // disbale warning-x, ибо то и то. Конкретный синтаксис свой может быть, обычно через #pragma.
a-tk
Если вешать аннотации под каждый инструмент, шума будет слишком много.
Andrey2008