GTK: Как выглядит первый запуск анализатора в цифрах

    Внедрение статического анализатора в проект для некоторых людей выглядит непреодолимой преградой. Почему-то очень распространено мнение, что объём выданных результатов анализа при первом запуске настолько велик, что рассматривается только два варианта: не связываться с этим или переключить всех людей на исправление предупреждений. В этой статьей попробуем развеять этот миф, проведя внедрение и настройку анализатора на проекте GTK.

    Введение

    GTK – кроссплатформенная библиотека элементов интерфейса. Недавно состоялся релиз GTK 4, что стало хорошим инфоповодом изучить качество кода проекта с помощью статического анализатора кода PVS-Studio. Такая деятельность для нас является регулярной, и нам часто приходится настраивать анализатор с нуля на многих проектах перед исследованием качества кода. В этой заметке я поделюсь опытом быстрой настройки PVS-Studio на C++ проекте.

    Анализ GTK

    Первые результаты

    Получаем свой первый отчёт анализатора и видим следующие результаты для диагностик общего назначения:

    4 (Fails) + 1102 (High) + 1159 (Medium) + 3093 (Low) = 5358 предупреждений.

    Далее быстро прокручиваем отчёт, выявляем всплески неинтересных предупреждений и принимаем решение для дальнейшей настройки анализатора.

    Исключаем директории

    Рассмотрим такое предупреждение:

    V530 [CWE-252] The return value of function 'g_strrstr_len' is required to be utilized. strfuncs.c 1803

    /* Testing functions bounds */
    static void
    test_bounds (void)
    {
      ....
      g_strrstr_len (string, 10000, "BUGS");
      g_strrstr_len (string, 10000, "B");
      g_strrstr_len (string, 10000, ".");
      g_strrstr_len (string, 10000, "");
      ....
    }
    

    Это код тестов, причём не относящихся непосредственно к GTK, поэтому составляем список директорий для исключения из анализа и перезапускаем PVS-Studio.

    При следующем запуске из анализа будут исключены следующие директории:

    gtk/_build/
    gtk/subprojects/
    gtk/tests/
    gtk/testsuite/
    

    Открываем отчёт и получаем следующий результат:

    2 (Fails) + 819 (High) + 461 (Medium) + 1725 (Low) = 3007 предупреждений.

    Ещё один положительный эффект, который мы получили после такой настройки, — это ускорение анализа.

    Исключаем макросы

    Макросы, пожалуй, - одна из основных причин аномального количества срабатываний у некоторых диагностик. Поверхностно смотрим наш отчёт и замечаем множество подобных предупреждений:

    V501 There are identical sub-expressions '* (& pipe->ref_count)' to the left and to the right of the '^' operator. gdkpipeiostream.c 65

    static GdkIOPipe *
    gdk_io_pipe_ref (GdkIOPipe *pipe)
    {
      g_atomic_int_inc (&pipe->ref_count);
    
      return pipe;
    }
    

    Вносить изменения в макросы обычно сложнее всего - вряд ли за это кто-то возьмётся в компании. Первое время точно нет. Поэтому воспользуемся механизмом отключения диагностик на них. Быстро просмотрев отчёт, составляем такой файл настроек:

    #V501
    //-V:g_atomic_int_:501
    #V547
    //-V:GTK_IS_:547
    //-V:GDK_IS_:547
    //-V:G_IS_:547
    //-V:G_VALUE_HOLDS:547
    #V568
    //-V:g_set_object:568
    

    Всего несколько строчек, которые покрывают большинство проблемных макросов для V501, V547 и V568.

    Смотрим результат:

    2 (Fails) + 773 (High) + 417 (Medium) + 1725 (Low) = 2917 предупреждений.

    Отключаем диагностики

    Некоторые диагностики изначально выдают неподходящие предупреждения для конкретного проекта. Рассмотрим предупреждение V1042:

    V1042 [CWE-1177] This file is marked with copyleft license, which requires you to open the derived source code. main.c 12

    Это очень полезная диагностика для проектов с закрытым кодом, чтобы случайно не включить в них код с недопустимой лицензией. Но для GTK это неинтересная диагностика, поэтому отключим её и получим скорректированный результат:

    2 (Fails) + 164 (High) + 417 (Medium) + 1725 (Low) = 2308 предупреждений.

    Изучаем фейлы

    В проекте имеются 2 предупреждения типа Fails:

    • V002 Some diagnostic messages may contain incorrect line number in this file. gdkrectangle.c 1

    • V002 Some diagnostic messages may contain incorrect line number in this file. gdktoplevelsize.c 1

    Эта диагностика предупреждает, что срабатывания на этих файлах могут указывать не на те строки кода, которые нужно. Обычно разница составляет 1-2 строки, и происходит это из-за неверного раскрытия макросов компилятором. По нашему опыту, чаще всего за этим был замечен компилятор MSVC.

    Эти предупреждения можно просто проигнорировать.

    Выводы

    Итоговый результат такой:

    164 (High) + 417 (Medium) + 1725 (Low) = 2306 предупреждений.

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

    V501 There are identical sub-expressions 'G_PARAM_EXPLICIT_NOTIFY' to the left and to the right of the '|' operator. gtklistbase.c 1151

    static void
    gtk_list_base_class_init (GtkListBaseClass *klass)
    {
      ....
      properties[PROP_ORIENTATION] =
        g_param_spec_enum ("orientation",
                           P_("Orientation"),
                           P_("The orientation of the orientable"),
                           GTK_TYPE_ORIENTATION,
                           GTK_ORIENTATION_VERTICAL,
                           G_PARAM_READWRITE |
                           G_PARAM_EXPLICIT_NOTIFY |  // <=
                           G_PARAM_EXPLICIT_NOTIFY);  // <=
      ....
    }
    

    Это отличный результат! И показатели других диагностик тоже значительно выросли. Мизерными настройками удалось уменьшить отчёт анализатора на целых 57%. Соответственно, показатель верных предупреждений к ложным тоже значительно вырос.

    Кстати, это одна из причин, по которой в интернете отсутствуют сравнения результатов разных анализаторов кода. Потому что нет единого мнения, стоит ли показывать работу анализатора как есть, или всё же надо провести первичную настройку. А у всех анализаторов свои механизмы для этого, что многократно усложняет сложность задачи сравнения.

    А теперь время передать эстафету моему коллеге Андрею Карпову.

    Примечание Андрея Карпова

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

    Конечно, моя задача проще и сильно отличается от процесса настройки и внедрения анализатора в реальный проект. Мне достаточно поверхностно пробежаться по списку предупреждений и выписать явные ошибки, игнорируя ложные срабатывания или непонятные предупреждения в сложных участках кода. При реальном использовании понадобится больше времени, чтобы настроить анализатор, точечно подавить ложные срабатывания, улучшить макросы и так далее. Но на самом деле, это не страшно. Например, в статье про проверку проекта EFL Core Libraries я показал, что можно достаточно легко настроить анализатор, чтобы он выдавал всего 10-15% ложных предупреждений. Согласитесь, неплохо, когда на каждые 1-2 ложных срабатывания вы исправляете 8-9 ошибок.

    Ну и не забывайте, что вам всегда доступен механизм массового подавления срабатываний анализатора. Это позволяет начать быстро использовать анализатор даже в большом проекте. Все предупреждения объявляются техническим долгом и пока не показываются. И команда начинает работать только с предупреждениями, относящимися к новому или изменённому коду. Подробнее про это предлагаю почитать в статье "Как внедрить статический анализатор кода в legacy проект и не демотивировать команду".

    Спасибо за внимание и приходите через пару недель читать статью про найденные ошибки.

    Если хотите поделиться этой статьей с англоязычной аудиторией, то прошу использовать ссылку на перевод: Svyatoslav Razmyslov. GTK: The First Analyzer Run in Figures.

    PVS-Studio
    Статический анализ кода для C, C++, C# и Java

    Комментарии 5

      +1
      MC^2 != (MC)^2
        0
        More — нечто неисчисляемое. В математике возможны такие действия, но с ходу не вспомню, как называется.
          0
          Вспомните пожалуйста :-) Очень интересно :-)
            0
            Тоже где-то была информация в голове, но пока все безрезультатно

            Сообщите, если узнаете первее)
        –2
        Ой вей. Писал я на GTK лет 6 назад. Нужно было интерфейс навернуть на Си программу (эмулятор клиента для сервера). Скажу одно — дико неудобная вещь. Особенно если писать интерфейс на Си — код становится похож на мантру ввиду огромного количества макросов. Вроде как был PyGTK — но это не тру. Документация — отдельный сорт говнеца, для эстетов.
        Сама структура компонент GTK выглядит архаично и бессвязно. И всегда есть 1000 и 1 способ выстрелить себе в ногу.

        Помучился пару дней — плюнул. Написал с нуля на Qt — при этом получил удовольствие от процесса. Ну и бонусом к использованию Qt — все собралось под Windows без каких либо ухищрений. Про документацию и говорить нечего.

        В целом — GTK плохо. Qt — хорошо. Я правда не знаю, как там сейчас с лицензиями для «не OSE» проектов, но более чем уверен, для большинства задач Qt — на 100 голов лучше.

        P.S. Я думаю, что GTK — кусок г-на.

        Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

        Самое читаемое