Статический анализ в GCC 10

Original author: David Malcolm
  • Translation

Я работаю в Red Hat над GCC, GNU Compiler Collection. Для следующего основного релиза GCC, GCC 10, я реализовывал новую опцию -fanalyzer: проход статического анализа для выявления различных проблем во время компиляции, а не во время исполнения.

Я думаю, что лучше выявлять проблемы как можно раньше по мере написания кода, используя компилятор, как часть цикла компиляции-редактирования-отладки, а не использовать статический анализ в качестве дополнительного инструмента «на стороне» (возможно, проприетарного). Поэтому, представляется целесообразным иметь встроенный в компилятор статический анализатор, который видит код в точности такой же, какой видит компилятор — ведь это и есть компилятор.

Этот вопрос, конечно, является огромной проблемой, которую нужно решить. Для этого релиза я сконцентрировался на типах проблем, замеченных в коде на Си, и, в частности, на ошибках двойного освобождения (double-free), но с целью последующего создания фреймворка, который мы сможем расширить в последующих релизах (когда мы сможем добавить больше проверок и поддержку языков, отличных от Си).

Надеюсь, что анализатор обеспечивает приличное количество дополнительной проверки, при этом не являясь слишком накладным. Я стремился к тому, чтобы -fanalyzer «всего лишь» удвоил время компиляции в качестве разумного компромисса между дополнительными проверками. У меня пока не получилось, как вы увидите ниже, но я работаю над этим.

Сейчас код находится в основной ветке GCC для GCC 10 и может быть опробован в Compiler Explorer, он же godbolt.org. Он хорошо работает для малых и средних примеров, но есть ошибки, которые означают, что он не готов к промышленному использованию. Я усердно работаю над исправлениями в надежде, что к моменту выхода GCC 10 (скорее всего, в апреле) эта возможность будет эффективно применима для C-кода.

Пути диагностики


Вот самый простой пример ошибки double-free:

#include <stdlib.h>

void test(void *ptr)
{
  free(ptr);
  free(ptr);
}

GCC 10 с -fanalyzer сообщает об этом следующим образом:
$ gcc -c -fanalyzer double-free-1.c
double-free-1.c: In function ‘test’:
double-free-1.c:6:3: warning: double-‘free’ of ‘ptr’ [CWE-415] [-Wanalyzer-double-free]
    6 |   free(ptr);
      |   ^~~~~~~~~
  ‘test’: events 1-2
    |
    |    5 |   free(ptr);
    |      |   ^~~~~~~~~
    |      |   |
    |      |   (1) first ‘free’ here
    |    6 |   free(ptr);
    |      |   ~~~~~~~~~
    |      |   |
    |      |   (2) second ‘free’ here; first ‘free’ was at (1)
    |

Этот лог показывает, что GCC выучил несколько новых трюков; во-первых, возможность диагностики иметь идентификаторы Common Weakness Enumeration (CWE). В этом примере диагностика double-free помечена тегом CWE-415. Надеемся, что этот тег сделает вывод более понятным, повысит точность и даст вам что-то простое для ввода в поисковых системах. Пока что только диагностика от -fanalyzer маркируется идентификаторами уязвимости CWE.

Если Вы используете GCC 10 с подходящим терминалом (например, свежий gnome-terminal), то CWE-идентификатор — это гиперссылка, ведущая к описанию проблемы. Говоря о гиперссылках, для многих релизов, когда GCC выдает предупреждение, он печатает опцию, регулирующую это предупреждение. Начиная с GCC 10, этот текст опции теперь является гиперссылкой на щелчок (опять же, предполагая достаточно развитый терминал), что должно привести вас к документации по этой опции (для любого предупреждения, а не только для тех, которые относятся к анализатору).

Теперь диагностика GCC может иметь связанную с ними цепочку событий, описывающую путь через код, который инициирует проблему. Учитывая отсутствие потока управления в приведенном выше примере, у него есть только два события, но вы можете увидеть, как второе событие относится к первому в его описании.

Приведем более полный пример. Вы видите проблему в следующем коде? (Подсказка: на этот раз это не двойное освобождение):

#include <setjmp.h>
#include <stdlib.h>

static jmp_buf env;

static void inner(void)
{
  longjmp(env, 1);
}

static void middle(void)
{
  void *ptr = malloc(1024);
  inner();
  free(ptr);
}

void outer(void)
{
  int i;

  i = setjmp(env);
  if (i == 0)
    middle();
}

Вот что сообщает GCC -fanalyzer, который показывает межпроцедурный поток управления с помощью ASCII-вывода:

$ gcc -c -fanalyzer longjmp-demo.c
longjmp-demo.c: In function ‘inner’:
longjmp-demo.c:8:3: warning: leak of ‘ptr’ [CWE-401] [-Wanalyzer-malloc-leak]
    8 |   longjmp(env, 1);
      |   ^~~~~~~~~~~~~~~
  ‘outer’: event 1
    |
    |   18 | void outer(void)
    |      |      ^~~~~
    |      |      |
    |      |      (1) entry to ‘outer’
    |
  ‘outer’: event 2
    |
    |   22 |   i = setjmp(env);
    |      |       ^~~~~~
    |      |       |
    |      |       (2) ‘setjmp’ called here
    |
  ‘outer’: events 3-5
    |
    |   23 |   if (i == 0)
    |      |      ^
    |      |      |
    |      |      (3) following ‘true’ branch (when ‘i == 0’)...
    |   24 |     middle();
    |      |     ~~~~~~~~
    |      |     |
    |      |     (4) ...to here
    |      |     (5) calling ‘middle’ from ‘outer’
    |
    +--> ‘middle’: events 6-8
           |
           |   11 | static void middle(void)
           |      |             ^~~~~~
           |      |             |
           |      |             (6) entry to ‘middle’
           |   12 | {
           |   13 |   void *ptr = malloc(1024);
           |      |               ~~~~~~~~~~~~
           |      |               |
           |      |               (7) allocated here
           |   14 |   inner();
           |      |   ~~~~~~~
           |      |   |
           |      |   (8) calling ‘inner’ from ‘middle’
           |
           +--> ‘inner’: events 9-11
                  |
                  |    6 | static void inner(void)
                  |      |             ^~~~~
                  |      |             |
                  |      |             (9) entry to ‘inner’
                  |    7 | {
                  |    8 |   longjmp(env, 1);
                  |      |   ~~~~~~~~~~~~~~~
                  |      |   |
                  |      |   (10) ‘ptr’ leaks here; was allocated at (7)
                  |      |   (11) rewinding from ‘longjmp’ in ‘inner’...
                  |
    <-------------+
    |
  ‘outer’: event 12
    |
    |   22 |   i = setjmp(env);
    |      |       ^~~~~~
    |      |       |
    |      |       (12) ...to ‘setjmp’ in ‘outer’ (saved at (2))
    |

Вышеизложенное довольно многословно, хотя, возможно, так это и должно быть для того, чтобы передать, что происходит, учитывая использование setjmp и longjmp. Я надеюсь, что описание достаточно понятно: происходит утечка памяти, когда вызов longjmp разворачивает стек обратно в outer мимо точки очистки в middle, не вызывая очистки.

Если вам не нравится ASCII-вывод, показанный выше, вы можете просматривать события как отдельную диагностику «ноты» при помощи -fdiagnostics-path-format=separate-events:

$ gcc -c -fanalyzer -fdiagnostics-path-format=separate-events longjmp-demo.c
longjmp-demo.c: In function ‘inner’:
longjmp-demo.c:8:3: warning: leak of ‘ptr’ [CWE-401] [-Wanalyzer-malloc-leak]
    8 |   longjmp(env, 1);
      |   ^~~~~~~~~~~~~~~
longjmp-demo.c:18:6: note: (1) entry to ‘outer’
   18 | void outer(void)
      |      ^~~~~
In file included from longjmp-demo.c:1:
longjmp-demo.c:22:7: note: (2) ‘setjmp’ called here
   22 |   i = setjmp(env);
      |       ^~~~~~
longjmp-demo.c:23:6: note: (3) following ‘true’ branch (when ‘i == 0’)...
   23 |   if (i == 0)
      |      ^
longjmp-demo.c:24:5: note: (4) ...to here
   24 |     middle();
      |     ^~~~~~~~
longjmp-demo.c:24:5: note: (5) calling ‘middle’ from ‘outer’
longjmp-demo.c:11:13: note: (6) entry to ‘middle’
   11 | static void middle(void)
      |             ^~~~~~
longjmp-demo.c:13:15: note: (7) allocated here
   13 |   void *ptr = malloc(1024);
      |               ^~~~~~~~~~~~
longjmp-demo.c:14:3: note: (8) calling ‘inner’ from ‘middle’
   14 |   inner();
      |   ^~~~~~~
longjmp-demo.c:6:13: note: (9) entry to ‘inner’
    6 | static void inner(void)
      |             ^~~~~
longjmp-demo.c:8:3: note: (10) ‘ptr’ leaks here; was allocated at (7)
    8 |   longjmp(env, 1);
      |   ^~~~~~~~~~~~~~~
longjmp-demo.c:8:3: note: (11) rewinding from ‘longjmp’ in ‘inner’...
In file included from longjmp-demo.c:1:
longjmp-demo.c:22:7: note: (12) ...to ‘setjmp’ in ‘outer’ (saved at (2))
   22 |   i = setjmp(env);
      |       ^~~~~~

или вообще выключить их с помощью -fdiagnostics-path-format=none. Есть также формат вывода JSON.

Все новые диагностики имеют название вида -Wanalyzer-SOMETHING: Мы уже видели -Wanalyzer-double-free и -Wanalyzer-malloc-leak выше. Все эти диагностики включаются, когда включен -fanalyzer, но их можно выборочно отключить с помощью вариантов -Wno-analyzer-SOMETHING (например, с помощью прагм).

Какие новые предупреждения будут?


Наряду с детектированием double-free, проводятся проверки на утечки malloc и fopen:

#include <stdio.h>
#include <stdlib.h>

void test(const char *filename)
{
  FILE *f = fopen(filename, "r");
  void *p = malloc(1024);
  /* do stuff */
}

$ gcc -c -fanalyzer leak.c
leak.c: In function ‘test’:
leak.c:9:1: warning: leak of ‘p’ [CWE-401] [-Wanalyzer-malloc-leak]
    9 | }
      | ^
  ‘test’: events 1-2
    |
    |    7 |   void *p = malloc(1024);
    |      |             ^~~~~~~~~~~~
    |      |             |
    |      |             (1) allocated here
    |    8 |   /* do stuff */
    |    9 | }
    |      | ~
    |      | |
    |      | (2) ‘p’ leaks here; was allocated at (1)
    |
leak.c:9:1: warning: leak of FILE ‘f’ [CWE-775] [-Wanalyzer-file-leak]
    9 | }
      | ^
  ‘test’: events 1-2
    |
    |    6 |   FILE *f = fopen(filename, "r");
    |      |             ^~~~~~~~~~~~~~~~~~~~
    |      |             |
    |      |             (1) opened here
    |......
    |    9 | }
    |      | ~
    |      | |
    |      | (2) ‘f’ leaks here; was opened at (1)
    |

Контроль использования памяти после ее освобождения:

#include <stdlib.h>

struct link { struct link *next; };

int free_a_list_badly(struct link *n)
{
  while (n) {
    free(n);
    n = n->next;
  }
}

$ gcc -c -fanalyzer use-after-free.c
use-after-free.c: In function ‘free_a_list_badly’:
use-after-free.c:9:7: warning: use after ‘free’ of ‘n’ [CWE-416] [-Wanalyzer-use-after-free]
    9 |     n = n->next;
      |     ~~^~~~~~~~~
  ‘free_a_list_badly’: events 1-4
    |
    |    7 |   while (n) {
    |      |         ^
    |      |         |
    |      |         (1) following ‘true’ branch (when ‘n’ is non-NULL)...
    |    8 |     free(n);
    |      |     ~~~~~~~
    |      |     |
    |      |     (2) ...to here
    |      |     (3) freed here
    |    9 |     n = n->next;
    |      |     ~~~~~~~~~~~
    |      |       |
    |      |       (4) use after ‘free’ of ‘n’; freed at (3)
    |

Контроль освобождения указателя не на кучу (heap):

#include <stdlib.h>

void test(int n)
{
  int buf[10];
  int *ptr;

  if (n < 10)
    ptr = buf;
  else
    ptr = (int *)malloc(sizeof (int) * n);

  /* do stuff.  */

  /* oops; this free should be conditionalized.  */
  free(ptr);
}

$ gcc -c -fanalyzer heap-vs-stack.c
heap-vs-stack.c: In function ‘test’:
heap-vs-stack.c:16:3: warning: ‘free’ of ‘ptr’ which points to memory not on the heap [CWE-590] [-Wanalyzer-free-of-non-heap]
   16 |   free(ptr);
      |   ^~~~~~~~~
  ‘test’: events 1-4
    |
    |    8 |   if (n < 10)
    |      |      ^
    |      |      |
    |      |      (1) following ‘true’ branch (when ‘n <= 9’)...
    |    9 |     ptr = buf;
    |      |     ~~~~~~~~~
    |      |         |
    |      |         (2) ...to here
    |      |         (3) pointer is from here
    |......
    |   16 |   free(ptr);
    |      |   ~~~~~~~~~
    |      |   |
    |      |   (4) call to ‘free’ here
    |

Контроль использования функции, которая, как известно, небезопасна для использования внутри обработчика signal:

#include <stdio.h>
#include <signal.h>

extern void body_of_program(void);

void custom_logger(const char *msg)
{
  fprintf(stderr, "LOG: %s", msg);
}

static void handler(int signum)
{
  custom_logger("got signal");
}

int main(int argc, const char *argv)
{
  custom_logger("started");

  signal(SIGINT, handler);

  body_of_program();

  custom_logger("stopped");

  return 0;
}

$ gcc -c -fanalyzer signal.c
signal.c: In function ‘custom_logger’:
signal.c:8:3: warning: call to ‘fprintf’ from within signal handler [CWE-479] [-Wanalyzer-unsafe-call-within-signal-handler]
    8 |   fprintf(stderr, "LOG: %s", msg);
      |   ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  ‘main’: events 1-2
    |
    |   16 | int main(int argc, const char *argv)
    |      |     ^~~~
    |      |     |
    |      |     (1) entry to ‘main’
    |......
    |   20 |   signal(SIGINT, handler);
    |      |   ~~~~~~~~~~~~~~~~~~~~~~~
    |      |   |
    |      |   (2) registering ‘handler’ as signal handler
    |
  event 3
    |
    |cc1:
    | (3): later on, when the signal is delivered to the process
    |
    +--> ‘handler’: events 4-5
           |
           |   11 | static void handler(int signum)
           |      |             ^~~~~~~
           |      |             |
           |      |             (4) entry to ‘handler’
           |   12 | {
           |   13 |   custom_logger("got signal");
           |      |   ~~~~~~~~~~~~~~~~~~~~~~~~~~~
           |      |   |
           |      |   (5) calling ‘custom_logger’ from ‘handler’
           |
           +--> ‘custom_logger’: events 6-7
                  |
                  |    6 | void custom_logger(const char *msg)
                  |      |      ^~~~~~~~~~~~~
                  |      |      |
                  |      |      (6) entry to ‘custom_logger’
                  |    7 | {
                  |    8 |   fprintf(stderr, "LOG: %s", msg);
                  |      |   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
                  |      |   |
                  |      |   (7) call to ‘fprintf’ from within signal handler
                  |

Наряду и с другими предупреждениями.

Что остаётся сделать?


В существующем виде проверка хорошо работает на малых и средних примерах, но есть две проблемные области, с которыми я сталкиваюсь при масштабировании до реального кода на Си.

Во-первых, в моем коде контроля состояний есть ошибки. Внутри чекера есть классы для абстрактного описания состояния программы. Чекер исследует программу, строя направленный граф пар (точка, состояние) с логикой упрощения состояния и слияния состояний в точках соединения потока управления.

Теоретически, если состояние становится слишком сложным, проверяющий должен перейти в наименее определенное состояние, но при таком подходе возникают ошибки, приводящие к взрыву числа состояний в заданной точке, что затем приводит к тому, что проверяющий работает медленно, в конце концов, достигая предела безопасности, и не исследует программу полностью. Чтобы исправить это, я переписал кишки кода управления состоянием. Надеюсь, что на следующей неделе перепишу master.

Далее, даже если мы полностью исследуем программу, пути через код, генерируемый анализатором -fanalyzer, иногда бывают абсурдно многословны. Самое худшее, что я видел, это путь из 110 событий для использования неинициализированных данных, сообщаемых при компиляции самого GCC. Я думаю, что это ложноположительное срабатывание, и очевидно, что неразумно ожидать от пользователей, что они пройдут через что-то подобное.

Анализатор пытается найти кратчайший возможный путь через граф (точка, состояние), генерирует из него цепочку событий, а затем пытается упростить эту цепочку. Фактически, он применяет серию peephole оптимизаций к цепочке событий, чтобы получить минимальную цепочку, которая демонстрирует проблему.

Недавно я реализовал способ фильтрации несущественных ребер потока управления из пути, который должен помочь, и работаю над аналогичным патчем для устранения избыточных межпроцедурных ребер.

В качестве конкретного примера я попробовал анализатор на реальной ошибке (пусть и пятнадцатилетней давности) -CVE-2005-1689, уязвимость double-free в krb5 1.4.1. Он корректно идентифицирует ошибку без ложных срабатываний, но на данный момент на выходе stderr 170 строк. Вместо того, чтобы показывать вывод в строке здесь, вы можете посмотреть его по этой ссылке.

Первоначально это было 1187 строк. Я исправлял различные ошибки и реализовывал больше упрощений, чтобы довести его до 170 строк. Частично проблема в том, что free выполняется с помощью макроса krb5_xfree, а код печати пути показывает, как каждый макрос расширяется каждый раз, когда происходит событие внутри макроса. Возможно, в выводе следует показывать расширение макроса только один раз за диагностику. Также первые несколько событий в каждой диагностике — это межпроцедурная логика, которая на самом деле неактуальна для пользователя (я работаю над исправлениями этого). С этими изменениями вывод должен быть значительно короче.

Может быть, лучший интерфейс мог бы выдавать отдельный HTML-файл, по одному на предупреждение, и выдавать «заметку» с указанием места расположения дополнительной информации?

Я хочу дать конечному пользователю достаточно информации о предупреждении, но не перегружая его. Есть ли лучшие способы представить это? Дайте мне знать в комментариях.

Как опробовать


GCC 10 появится в Fedora 32, которая должна выйти через пару месяцев.

Для простых примеров кода можно поиграться с новым GCC онлайн на godbolt.org (выберите gcc «trunk» и добавьте -fanalyzer в опции компилятора).

Удачи!

Далее добавлено переводчиком из форумов.

Dlang, комментарии Уолтера Брайта на Hacker News


Это соответствует продвижению [моей] идеи сделать для D по умолчанию @ safe, и реализовать систему Владения/Заимствования @ live.

Либо мы вскочим на этот автобус, либо он нас переедет.

Double-free's можно отслеживать, выполняя анализ потока данных (DFA) в функции. Именно так D делает это в своей зарождающейся реализации системы владения/заимствования. Это можно сделать и без DFA, получив только 90% правильных результатов и имея множество ложных срабатываний.

В прошлом я использовал много статических чекеров, и процент ложных срабатываний был достаточно высок, чтобы отказаться от их использования. Вот почему D использует DFA, чтобы дать 100% положительных сигналов при 0% ложных срабатываний (Прим.пер. здесь имеется в виду, что все обнаруженные утечки — 100% утечки, а не то, что отлавливаются 100% всех возможных). Я знал, что это будет возможно, потому что компиляторы использовали DFA при проходе оптимизации.

Чтобы отслеживание заработало, нельзя просто отслеживать события для функции, называемой «free». В конце концов, обычное дело — писать свои собственные аллокаторы памяти, и компилятор не будет знать, что это такое. Следовательно, должен быть какой-то механизм, чтобы сообщить компилятору, когда параметр функции типа указатель «потребляется» вызываемой функцией, и когда он просто «одолжен» ей (отсюда и номенклатура системы «Владелец/заемщик»).

Одна из трудностей, которую можно преодолеть с помощью D, заключается в том, что существует несколько сложных семантических конструкций, которые необходимо разбить на их компонентные операции с указателями. Я заметил, что Rust упростил эту проблему, упростив язык :-).

Но как только это сделано, оно работает, и работает удовлетворительно хорошо.

Обратите внимание, что ничто из этого не является критикой того, что делает GCC 10, потому что в статье не хватает подробностей, чтобы сделать обоснованные выводы. Но я рассматриваю это как часть общей тенденции, что люди устали от ошибок безопасности памяти в языках программирования, и очень приятно видеть прогресс на всех фронтах.

Комментарий Тимона Гера для понимания D из форума обсуждения на Dlang.org


@ live не является системой владения/заимствования, хотя она действительно основывается на концепциях, связанных с владением и заимствованием.

Система собственности/заимствования навязывает семантику собственности в коде @ safe, @ live — нет. Это только линтер для @ system и @ trusted кода без гарантий безопасности.

Similar posts

AdBlock has stolen the banner, but banners are not teeth — they will be back

More
Ads

Comments 26

  • UFO just landed and posted this here
      0

      Компиляторы со временем сделают ненужными специализированные статические анализаторы, или будут вечно догонять?

        0
        DFA анализ компилятора гораздо круче, чем набор эвристик в линтере. Либо же линтер станет сложнее в разработке (и дороже) компилятора.
          0
          PVS-Studio использует DFA.
            +1
            Не хочу спорить, но можно просто прогнать примеры из статьи через их линтер (особенно интересно с setjump или signal).

            Я думаю, что их бизнес пострадает от появления бесплатных настолько мощных возможностей, встроенных в компилятор. Когда GCC10 войдет в мейнстримный Linux.

            Любопытно, сколько ошибок тогда обнаружится?
              0

              Достаточно мощный clang static-analyzer давно есть, однако ж...


              Да и простые ворнинги компилятора включают не везде.

                +1
                Я думаю, что их бизнес пострадает от появления бесплатных настолько мощных возможностей, встроенных в компилятор

                Не пострадает по двум причинам.
                1. Кролики — это не только ценный мех, но и три — четыре килограмма диетического, легкоусвояемого мяса. PVS-Studio – это не только поиск ошибок в коде, но и развитая инфраструктура. Например, это интеграция с такими системами, как SonarQube, PlatformIO, Azure DevOps, Travis CI, CircleCI, GitLab CI/CD, Jenkins, Visual Studio. Это развитые механизмы массового подавления предупреждений, что позволяет быстро начать использовать PVS-Studio даже в большом старом проекте. Это рассылка уведомлений. Это поддержка клиентов. И так далее, и так далее.
                2. PVS-Studio тоже не стоит на месте. Собственно, у нас многие компиляторы и заимствуют. Тот же GCC. Пруфов не будет, но это было. Просто как-то нет смысла ловить кого-то за руку. Ну, если только случайно. Почему нет смысла ловить, так это потому, что улучшение диагностических возможностей идёт всем на пользу. Мир программ становится лучше. А нас это держит в тонусе и заставляет активно наращивать мощности.
                0
                Спасибо, что поддержали ответом. Хотел добавить, что есть более свежая статья на эту тему "Технологии, используемые в анализаторе кода PVS-Studio для поиска ошибок и потенциальных уязвимостей". И доклад "Как работает анализ Data Flow в статическом анализаторе кода".
                  0
                  Прекрасно что Вы здесь! Отлавливает ли PVS-Studio ошибки в примерах в этой статье?

                  Повторюсь, особенно интересно с примерами setjump или signal.
              0

              Часть эвристик может быть не понадобится, но совсем не исключит. Учитывая размеры кодовых баз самих компиляторов — никто не без греха и баги есть везде. Реализации отличные от референсной в этом плане создают конкуренцию, что хорошо сказывается на развитии как языка, так и компиляторов и окружающего разработку инструментария.

                +1
                Компиляторы со временем сделают ненужными специализированные статические
                анализаторы, или будут вечно догонять?

                ИМХО бессмысленно их противопоставлять. В самом начале статьи указано
                ключевое отличие:


                Я стремился к тому, чтобы -fanalyzer «всего лишь» удвоил время компиляции в качестве
                разумного компромисса между дополнительными проверками. У меня пока не получилось

                Даже если и получится, то при добавлении новых проверок (список сейчас какой-то очень маленький по сравнению с clang static-analyzer) время снова существенно возрастет,
                вот это и отличие статического анализатора и компилятора и от этого никуда не уйдешь.


                Больше статически проверок -> неудобно запускать во время компиляции -> используется
                как отдельный компонент / статический анализатор


                Большинство статических анализаторов созданы на основе существующих компиляторов, тот же PVS и все они отдельные инструменты, а не часть компиляторов.

                  0

                  Ну, как сказать… Код из GCC 10:
                  tree
                  vn_reference_lookup_pieces (....)
                  {
                    struct vn_reference_s vr1;
                    ....
                    vr1.set = set;
                    vr1.set = base_set;
                    ....
                  }
                  

                  Предупреждение PVS-Studio: V519 The 'vr1.set' variable is assigned values twice successively. Perhaps this is a mistake. Check lines: 3448, 3449. tree-ssa-sccvn.c 3449
                  :)

                  +1
                  Интересно, есть какая-то возможность пометить собственные функции как malloc и free? Зачастую во встраиваемых проектах, где сейчас часто и применяется C приходится писать свой, либо использовать альтернативный аллокатор/деаллокатор. То же самое касается fopen и т.д… Что если я не использую стандартную библиотеку?
                    0
                    Насчёт GCC не знаю, но в анализатор PVS-Studio можно (см. раздел «Как задать псевдоним для системной функции»). И кстати, на подходе статья по проверку GCC 10 :).
                      0
                      А существовали ли ошибки в GCC 10, которые были обнаружены/исправлены в ходе компилации его исходного кода с помощью GCC 10 с -fanalyzer? И было бы интересно сравнить долю ложных срабатываний на исходном коде GCC 10 у PVS-Studio и самого GCC 10.
                        +1
                        К сожалению, не получится ничего сравнить. Анализатор GCC разрабатывается с учетом кода GCC и настроен под его особенности. И наоборот, стиль написания кода GCC подстроен под анализатор GCC. Это естественно, уменьшать шум чтобы иметь возможность пользоваться.

                        PVS-Studio при первом запуске (без настроек) проиграет. Собственно, так и есть. В статье, которая скоро будет, я пишу, что PVS-Studio сходит с ума от всех этих макросов. Это не проблема. Но нужна настройка. Просто я хотел пояснить, что сравнить, это намного сложнее чем может казаться. Сравнение требует настройки и плюс тут возникает вопрос, где в этой настройки для честности остановиться. В общем, задача нерешаема :).
                    +4

                    Лучшая реклама PVS-Studio. Даже если GCC-овый находит больше, работа с его выводом убивает.

                      +2
                      Спасибо за перевод и внимание к теме статьи!

                      Хочу сказать про PVS-Studio. Когда в компиляторе от Microsoft появился статический анализ С++, все говорили что теперь PVS-Studio умрет. Затем появился статический анализ в clang. И стало понятно, что теперь-то точно умрет PVS-Studio. Потом появился Roslyn. Сомнений в смерти PVS-Studo для C# не оставалось ни у кого, ведь теперь любой может делать свои анализаторы! Бесплатно! Да и при живом-то Resharper. PVS-Studio для Java при наличии IntelliJ идея тоже не самая очевидная. Теперь вот в GCC появился статический анализ…

                      Крах PVS-Studio очевиден уже почти всем. Только две категории людей об этом не знают. Разработчики PVS-Studio и их клиенты. Скажите уже им кто-нибудь!

                      P.S. Мы приветсвуем появление статического анализа в GCC. Чем больше разработчиков узнает об этой технологии, тем больше у нас работы.
                        0
                        Про «умрет» и конкретно про PVS-Studio в статье ни слова. Ваш комментарий немного мимо.

                        И лично я думаю, что нет, не умрет, т.к. умеет много чего, например отлавливать ошибки копипасты и подобные — которые к статическому анализу отношения не имеют.
                          0

                          Когда-нибудь PVS-Studio таки помрет. Вопрос только в том, когда и как.
                          Понятно, что это произойдет не в ближайшем будущем, хотя бы потому, что компиляторам еще догонять и догонять.
                          И не факт, что его похоронит именно какой-нибудь компилятор, в который будет включен полновесный статический анализатор.
                          Вполне возможно, это будет что-то вроде ИИ, который будет следить за кодом в реальном масштабе времени и пинать программиста (удар током через клавиатуру :) ) за ляпы, ошибки и подозрительные конструкции (весьма далекое будущее).
                          Другой вариант, что его убьет то, что программистов почти полностью заменит что-то автоматическое, которое будет программировать сразу в машинных кодах и будет само себе анализатором возможных проблем.

                          –1
                          О, классно, теперь это больше похоже на Rust)
                              –1
                              Очень слабая статья, не имеющая отношения к статическому анализу. Кликбейт?
                                +5
                                Очень слабый комментарий…
                                  –1
                                  Ну я рассчитывал, что вы развернуто ответите на вопрос выше, который по теме.

                                  Но вы (или PVS), видимо, не смогли пройти этот тест.

                          Only users with full accounts can post comments. Log in, please.