Скачай PVS-Studio и найди ошибки в С, С++,C# коде
515,56
рейтинг
19 марта 2015 в 17:41

Разработка → Проверка Vim при помощи PVS-Studio в GNU/Linux



Читатель мог бы подумать, что это очередная статья о проверке еще одного проекта из мира свободного ПО, но на самом деле, статья не столько о проверке, сколько о практике использования анализатора PVS-Studio в полностью GNU/Linux окружении. Не случайно выбором проекта для проверки стал Vim, ибо и он в этом деле сослужил свою службу.

Для начала немного о Vim


Vim (http://vim.org) — кроссплатформенный свободный текстовый редактор c 30-летней историей, являющийся наследником редактора vi и пришедший из мира Unix систем.

Vim весьма широко применяется в администрировании и разработке, во многих дистрибутивах GNU/Linux он является редактором по умолчанию. От других текстовых редакторов Vim отличается ориентацией на использование исключительно клавиатуры, текстовый интерфейс, богатыми возможностями расширения через систему написанных на Vim Script плагинов.


Теперь о самой проверке


Одним из вариантов проверки проектов под Linux является интеграция в систему сборки, например, GNU Make. Для проверки vim был выбран именно этот способ. Для каждого вызова компилятора в make-файле был добавлен вызов анализатора. Для удобства этот вызов был обернут в переменную Make подобным образом:
#PVS Studio vars
PVS_CFLAGS = $(ALL_CFLAGS)
PVS_INCFLAGS = -I$(srcdir)
PVS_STUDIO = ~/PVS-Studio/PVS-Studio –cfg \
    ~/PVS-Studio/PVS-Studio_vim.cfg --source-file \
    $< --cl-params $(PVS_CFLAGS) -c $(PVS_INCFLAGS) $<

Далее проект собирается в обычном режиме командой make (при желании можно добавить отдельный target для анализа, например ".analysis"). Результатом, помимо собранного проекта является сырой лог анализатора.

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

С сырым логом работать невозможно. В этом логе множество дублирующихся сообщений (когда один .h-файл включен в несколько .cpp-файлов). Для изменения параметров анализа приходится, после правки конфигурационного файла, запускать проверку заново, что серьезно сказывается на времени для больших проектов. Даже если мы всего лишь хотели, например, отключить предупреждения, относящиеся к файлам из определенной директории. Для решения этой проблемы на C++ была написана утилита log-parser, которая обрабатывает сырой лог PVS-Studio, убирает дублирующиеся сообщения, применяет к сообщениям фильтры из своего файла опций и выводит предупреждения анализатора в одном из поддерживаемых форматов. Утилита работает очень быстро (даже на логах проверки очень больших проектов ее время работы не превышает 2-3 секунд), что дает возможность легко и быстро изменить какие-то параметры анализа и получить новый список сообщений.

При необходимости можно легко добавить новые форматы вывода. На данный момент их два: xml и так называемый errorfile. Насколько я понимаю, официального названия у него и нет, это именно тот формат, в котором выдают сообщения многие программы под Linux, например, grep, ошибки компиляции gcc и т.д. Именно он нам и пригодился.

В отличие от Windows, где подавляющее большинство разработчиков пользуются Visual Studio, в мире GNU/Linux существует множество IDE, текстовых редакторов и прочего со своей долей пользователей. Единого мнения и перевеса сторон нет и каждый выбирает себе инструмент по своему вкусу. Тем не менее, при проверке проектов важно не только получить результаты анализа, но и иметь возможность удобной работы с ними, как эту возможность предоставляет интеграция PVS-Studio с Visual Studio. Формат сообщений ошибок, описанный выше, является своего рода стандартом для Linux программ и большинство редакторов и сред разработки имеют ту или иную его поддержку, но, к сожалению, в большинстве случаев эта поддержка существует лишь для чтения сообщений компилятора из stderr при сборке, в данном же случае гораздо удобнее брать сообщения анализатора из заранее подготовленного файла.

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


Рисунок 1 – Запущенный vim с результатами анализа.

Достаточно после работы анализатора и утилиты обработки лога выполнить vim -q <errorfile>, А затем в открывшемся редакторе выполнить команду создания буфера с ошибками. Например, :cw 20. И вот мы уже получаем комфортную среду для работы с сообщениями анализатора и навигации по коду. Конечно, пришлось потратить несколько часов на изучение самого Vim, так как я в нем ранее не работал, а его принципы использования очень сильно отличаются от более привычных текстовых редакторов. Но в итоге я могу сказать, что весьма проникся удобством его использования и из категории непонятных штуковин для инопланетян он перешел в категорию мощных инструментов для работы. Соответственно, долго с выбором проекта для проверки мучиться не пришлось — конечно же сам Vim. Код vim оказался очень качественным, явных багов в нем не нашлось (хотя стиль написания кода местами довольно спорный, но, думаю, можно сделать скидку на возраст проекта. Тем не менее обнаружилось некоторое количество мест, на которые стоит обратить внимание. Поговорим о них подробнее.

Лишняя проверка


    if (ptr == NULL)
    {
        if (compl_leader != NULL)
            ptr = compl_leader;
        else
            return;  /* nothing to do */
    }
    if (compl_orig_text != NULL)
    {
        p = compl_orig_text;
        for (len = 0; p[len] != NUL && p[len] == ptr[len]; ++len)
        ;
#ifdef FEAT_MBYTE
        if (len > 0)
            len -= (*mb_head_off)(p, p + len);
#endif
        for (p += len; *p != NUL; mb_ptr_adv(p))
            AppendCharToRedobuff(K_BS);
    }
    else
        len = 0;
    if (ptr != NULL)
        AppendToRedobuffLit(ptr + len, -1);

Предупреждение анализатора V595 (1) The 'ptr' pointer was utilized before it was verified against nullptr. Check lines: 3922, 3933.

Указатель ptr уже был проверен на NULL, в случае истинности этого условия ему был присвоен указатель comp_leader, который точно не нулевой. Вторая проверка не требуется.

Странный memset


/*
* If requested, store and reset the global values controlling
* the exception handling (used when debugging). Otherwise avoid
* clear it to a bogus compiler warning when the optimizer
* uses inline functions...
*/
if (flags & DOCMD_EXCRESET)
  save_dbg_stuff(&debug_saved);
else
  vim_memset(&debug_saved, 0, 1);

где debug_saved — объект структуры
struct dbg_stuff
{
    int        trylevel;
    int        force_abort;
    except_T    *caught_stack;
    char_u    *vv_exception;
    char_u    *vv_throwpoint;
    int        did_emsg;
    int        got_int;
    int        did_throw;
    int        need_rethrow;
    int        check_cstack;
    except_T    *current_exception;
};

Сообщение анализатора: V512 (1) A call of the 'memset' function will lead to underflow of the buffer '& debug_saved'.

Сложно сказать, зачем нужно было обнулять только первый байт структуры. Если это используется как какой-то флаг, лучше определить его отдельным полем структуры (можно union).

Подозрительный цикл


/* check for out-of-memory */
for (i = 0; i < num_names; ++i)
{
  if (names[i] == NULL)
  {
    for (i = 0; i < num_names; ++i)
      vim_free(names[i]);
    num_names = 0;
  }
}

Сообщение анализатора: V535 (1) The variable 'i' is being used for this loop and for the outer loop. Check lines: 1893, 1897.

Во внешнем и внутреннем цикле по одному и тому же массиву проходят одним и тем же счетчиком i. Понятно, что при первом же срабатывании условия if (names[i] == NULL) следующий шаг внешнего цикла уже выполняться не будет, но стороннему человеку придется напрячься, чтобы понять этот код верно, а своеобразность его написания наводит на мысли, то ли поведение имел в виду автор. Другими словами, хотя ошибки нет, но код немного пахнет. Пожалуй, оператор 'break' подошел бы для остановки цикла лучше.

Области видимости


char_u *p, *old;
//...
{
    char_u        buffer[BUFLEN + 1];
    //...
    for (p = buffer; p < buffer + len; p += l)
    //...

Предупреждение анализатора: V507 (2) Pointer to local array 'buffer' is stored outside the scope of this array. Such a pointer will become invalid.

Подобных мест в коде в Vim довольно много (к вопросу о стиле). В указателе p, объявленном в самом начале функции (кое-где вообще с глобальной областью видимости) сохраняется указатель на массив, существующий только в меньшей области видимости и который будет удален при выходе из его блока кода. При беглом осмотре мне показалось, что после выхода из области видимости buffer указатель p используется только после присвоения ему нового значения, но ведь где-то можно это и пропустить. С какой целью так делать вместо объявления еще одной переменной внутри области видимости buffer (неужели для экономии места на стеке?), мне не понятно. Такой код плохо поддерживаем и неудобно читаем.

Ошибка с signed и unsigned типами в одном выражении


for (cu = 1; cu <= 255; cu++)
    if (VIM_ISDIGIT(cu))
        regc(cu);

где
#define VIM_ISDIGIT(c) ((unsigned)(c) - '0' < 10)

Предупреждение анализатора: V658 (2) A value is being subtracted from the unsigned variable. This can result in an overflow. In such a case, the '<' comparison operation can potentially behave unexpectedly. Consider inspecting the '(unsigned)(cu) — '0' < 10' expression.

Этот код больше похож на грязный хак. При вычислении выражения ((unsigned) — '0' < 10) результатом вычитания будет значение типа unsigned и при сравнении обе части выражения тоже будут приведены к unsigned. Соответственно, когда переменная cu меньше, чем числовое значение 0, происходит переполнение. В данным случае код ведет себя верно, цель свою (проверка, является ли символ цифрой) выполняет, но не думаю, что есть причины использовать в своем коде подобные приемы без нужды. Цикл можно было сделать от '0' и обойтись без приведения к unsigned.

Указатель инициализирован NULL и нигде не изменяется, притом он используется


char_u    *retval = NULL;
//...
if (round == 2)
  vim_strncpy(retval, s, len); //первое использование retval
//...
if (retval == NULL)
{

Предупреждение анализатора: V595 (1) The 'retval' pointer was utilized before it was verified against nullptr. Check lines: 7903, 7907.

Это уже похоже на ошибку. Анализатор говорит о лишней проверке, но на самом деле проблема прежде всего в другом. Указатель retval инициализирован 0, и я не нашел ни одного места в этой функции, где бы его значение менялось. При этом в него много раз делается strncpy. После чего его внезапно решили проверить на NULL.

Небезопасное использование realloc


/* TODO: check for vim_realloc() returning NULL. */
l->t = vim_realloc(l->t, newlen * sizeof(nfa_thread_T));

Предупреждение анализатора V701 (2) realloc() possible leak: when realloc() fails in allocating memory, original pointer 'l->t' is lost. Consider assigning realloc() to a temporary pointer.

Очень частая ошибка во многих проектах, суть этой ошибки подробно описана в сообщении анализатора. К счастью, судя по комментарию, это скоро исправят. В других местах в коде Vim realloc используется правильно.

Несколько примеров ложных срабатываний


if (ireg_icombine && len == 0)
{
  /* If \Z was present, then ignore composing characters.
   * When ignoring the base character this always matches. */
   if (len == 0 && sta->c != curc)
     result = FAIL;

V560 (2) A part of conditional expression is always true: len == 0.

V571 (2) Recurring check. The 'len == 0' condition was already verified in line 6032.
if (VIsual_active)
{
  if (VIsual_active
      && (VIsual_mode != wp->w_old_visual_mode
      || type == INVERTED_ALL))

V571 (2) Recurring check. The 'VIsual_active' condition was already verified in line 1515.

Есть еще несколько мест с подобными проверками. Особого интереса для обсуждения они не вызывают, в большинстве случаев вреда не несут, но в некоторых может скрываться логическая ошибка, поэтому таким местам стоит уделять внимание.

Просто плохой код, в структуре заполняют только первый байт


#ifdef FEAT_TAG_BINS
  /* This is only to avoid a compiler warning for using search_info
  * uninitialised. */
  vim_memset(&search_info, 0, (size_t)1);
#endif

V512 (1) A call of the 'memset' function will lead to underflow of the buffer '& search_info'.

В комментарии объяснено, зачем это сделано, но способ довольно странный. Есть множество более красивых путей избегания предупреждения компилятора.

Плохая практика использования коротких имен


extern char *UP, *BC, PC;

Предупреждение анализатора: V707 (2) Giving short names to global variables is considered to be bad practice. It is suggested to rename 'UP', 'BC', 'PC' variables.

Подобная практика не редкость в коде Vim. У многих переменных 1- и 2-буквенные имена, зачастую с большой областью видимости, а в данном случае вообще с глобальной. В сочетании с функциями длиной в 500+ строк это приводит к весьма трудночитаемому коду.

Странное присваивание i в условии


int i = 2; /* index in s[] just after <Esc>[ or CSI */
//...
if (n >= 8 && t_colors >= 16
    && ((s[0] == ESC && s[1] == '[')
        || (s[0] == CSI && (i = 1) == 1))
    && s[i] != NUL
    && (STRCMP(s + i + 1, "%p1%dm") == 0
    || STRCMP(s + i + 1, "%dm") == 0)
    && (s[i] == '3' || s[i] == '4'))

Предупреждение анализатора: V560 (2) A part of conditional expression is always true: (i = 1) == 1.

Сложно сказать, ошибка ли это или просто странный способ присвоить i единицу. Писать так явно не стоит.

Заключение


В заключение хотелось бы сказать, что сейчас проверка проектов с помощью PVS-Studio под GNU Linux без использования машины с Windows является вполне реальной и довольно удобной. Помог в этом числе и Vim, за что был подвергнут подобному сценарию проверки первым.

Эта статья на английском


Если хотите поделиться этой статьей с англоязычной аудиторией, то прошу использовать ссылку на перевод: Anton Tokarev. Analyzing Vim by PVS-Studio in GNU/Linux.

Прочитали статью и есть вопрос?

Часто к нашим статьям задают одни и те же вопросы. Ответы на них мы собрали здесь: Ответы на вопросы читателей статей про PVS-Studio и CppCat, версия 2014. Пожалуйста, ознакомьтесь со списком.
Автор: @FoxCanFly
PVS-Studio
рейтинг 515,56
Скачай PVS-Studio и найди ошибки в С, С++,C# коде

Комментарии (61)

  • +4
    Это уже похоже на ошибку. Анализатор говорит о лишней проверке, но на самом деле проблема прежде всего в другом. Указатель retval инициализирован 0, и я не нашел ни одного места в этой функции, где бы его значение менялось. При этом в него делается много раз делается strncpy. После чего его внезапно решили проверить на NULL.

    char_u	*retval = NULL;
    ...
    for (round = 1; round <= 2; ++round)
    {
        ...
        if (lnum < 0 || submatch_mmatch->endpos[no].lnum < 0)
    	return NULL;
    
        ...
        if (s == NULL)
    	break;
        ...
    	if (round == 2)
    	    vim_strncpy(retval, s, len);
    	...
    	if (round == 2)
    	{
    	    STRCPY(retval, s);
    	    retval[len] = '\n';
    	}
    	...
        if (round == 2)
    	STRCPY(retval + len, s);
       	...
        if (round == 2)
    	retval[len] = '\n';
    	...
    	if (round == 2)
    	    STRNCPY(retval + len, reg_getline_submatch(lnum),
    				     submatch_mmatch->endpos[no].col);
    	...
    	if (round == 2)
    	    retval[len] = NUL;
    	...
        if (retval == NULL)
        {
    	retval = lalloc((long_u)len, TRUE);
    	if (retval == NULL)
    	    return NULL;
        }
    }
    

    Доступ по указателю осуществляется только на втором раунде, а аллокация на первом. Такая вот агрессивная оптимизация, чтобы не делать лишней аллокации, если до второго раунда дело не дойдет. Ошибки здесь нет.
    • +3
      Ошибки нет, но качественным кодом я бы это не назвал.
      Неужели нельзя было порезать эти два раунда на две отдельные процедурки, раз уж количество раундов заранее известно?
      • +5
        Внимательно изучив код, я понял, что немного ошибся — это никакая не оптимизация, первый проход — холостой — делается для расчета длины, а второй для операций над строкой, о чем и написано в комментарии (которые мой внутренний парсер давно привык игнорировать)
        /*
        * First round: compute the length and allocate memory.
        * Second round: copy the text.
        */
        

        Так как выделение памяти происходит исходя из расчетной длины, «неоптимизированный» вариант с выделением памяти заранее невозможен.
        А разделение на две процедуры породило бы дублирование кода в обе процедуры, что грозит ошибками в случае его модификации. Однако, сделать его более «качественным» можно было бы, например, заменой абстрактного int round на bool length_calculation_only.
        • +5
          А разделение на две процедуры породило бы дублирование кода в обе процедуры, что грозит ошибками в случае его модификации.
          Я не очень понимаю, что мешает пойти чуть дальше и нарезать эти две процедурки на несколько мелких (которые всё равно заинлайнятся), используемых по необходимости.
          Здесь же по факту одна функция делает две вещи: считает размер и копирует данные. Прямое нарушение single responsibility principle, которое еще и наглядно затрудняет понимание происходящего.
  • +13
    Здорово, какой качественный код у vim'a.
    Фактически ни одного найденного бага, пусть и одним инструментом.
  • +9
    Интересно было бы сравнить с качеством кода neovim.
    • 0
      По-идее, там было много исправлено ошибок, которые нашел Coverity. С другой стороны огромный пласт кода просто переписан с нуля. Но код vim качественным для чтения я бы не назвал.
  • +1
    я могу сказать, что весьма проникся

    Здорово, нашего полку прибыло! :)
  • +3
    В заключение хотелось бы сказать, что сейчас проверка проектов с помощью PVS-Studio под GNU Linux без использования машины с Windows является вполне реальной и довольно удобной.

    Где можно скачать эту версию?
    • +1
      Присоединяюсь к вопросу. Еще в январе EvgeniyRyzhkov говорил, что ни линукс-, ни вайн-версию в ближайшее время ожидать не стоит, ибо нет спроса; и в FAQ у вас до сих пор висит ответ «к сожалению, нет, извините» по этому поводу.
      • 0
        Поддержка Linux развивается в направлении custom-версий. Напишите нам письмо, как сотрудник компании, в которой работаете. Обсудим эти вопросы. Никакой публичной версии нет и пока не планируется.
        • 0
          Ясно. Наверное, вам стоит обновить ответ про Linux-версию в FAQ. А есть ли в планах сделать Windows-версию запускаемой (работающей) из-под Wine?
      • 0
        Голосом из Варкрафта 2: «Кто ко мне взывал?»

        Напишите нам с корпоративного ящика, публичной версии не планируется.
      • –2
        Голосом из Варкрафта 2: «Кто ко мне взывал?»

        Напишите нам с корпоративного ящика, публичной версии не планируется.
  • +3
    Кстати, существует еще и форк: neovim.org/
  • +2
    Лишняя проверка

    Указатель ptr уже был проверен на NULL, в случае истинности этого условия ему был присвоен указатель comp_leader, который точно не нулевой. Вторая проверка не требуется.
    А если была выполнена ветка, помеченная do nothing?
    Области видимости

    С какой целью так делать вместо объявления еще одной переменной внутри области видимости buffer (неужели для экономии места на стеке?), мне не понятно. Такой код плохо поддерживаем и неудобно читаем.
    Возможно, это наследие ранних версий C, где переменные можно было объявлять только в начале функций.
    Ошибка с signed и unsigned типами в одном выражении

    В данным случае код ведет себя верно, цель свою (проверка, является ли символ цифрой) выполняет, но не думаю, что есть причины использовать в своем коде подобные приемы без нужды. Цикл можно было сделать от '0' и обойтись без приведения к unsigned.
    Это считалось оптимизацией (и до сих пор иногда рекомендуется в книжках и интернете), потому что позволяет использовать одно сравнение вместо двух.
    Небезопасное использование realloc

    К счастью, судя по комментарию, это скоро исправят.

    Хммм… код был написан в мае 2013, комментарий автор добавил 10 февраля 2015, но код не исправил, так что вероятно он и дальше так останется.
    • +2
      А если была выполнена ветка, помеченная do nothing?

      Там return.
      • 0
        Самого главного то я и не заметил.
    • +1
      Это считалось оптимизацией (и до сих пор иногда рекомендуется в книжках и интернете), потому что позволяет использовать одно сравнение вместо двух.
      Это и сегодня является вполне себе оптимизацией, но её уже давно умеет делать компилятор:
      $ cat test.cc
      bool is_digit(char c) {
        return (c >= '0') && (c <= '9');
      }
      $ gcc -O3 -S test.cc -o- | c++filt
      	.file	"test.cc"
      	.text
      	.p2align 4,,15
      	.globl	is_digit(char)
      	.type	is_digit(char), @function
      is_digit(char):
      .LFB0:
      	.cfi_startproc
      	subl	$48, %edi
      	cmpb	$9, %dil
      	setbe	%al
      	ret
      	.cfi_endproc
      .LFE0:
      	.size	is_digit(char), .-is_digit(char)
      	.ident	"GCC: (Ubuntu 4.8.2-19ubuntu1) 4.8.2"
      	.section	.note.GNU-stack,"",@progbits
      

      Оставьте ему работу, не засоряйте голову программисту всеми этими мелкими оптимизациями.
      • 0
        Vim до сих пор поддерживает многие старые версии компиляторов. А конкретно эту оптимизацию, к примеру, не умеет современный pcc-1.1.0.
  • 0
    Удалён дубликат
  • 0
    ---A call of the 'memset' function will lead to underflow of the buffer '& debug_saved'.

    а почему программа решила что это memset? пользовательская функция, внутри может быть все что угодно
    • 0
      Анализатор работает с препроцессированными файлами. И если макрос vim_memset объявлент как
      #define vim_memset(ptr, c, size)   memset((ptr), (c), (size))
      то значит это функция memset(). Никакой магии. :)
      • –4
        Это ни о чем не говорит, я могу в линкере легко заменить это чем угодно.

        Собственно часто так и делаю.
        • 0
          Гм… Замените — предупреждения не будет. В чём собственно тогда Ваш вопрос?
    • 0
      По названию и сигнатуре можно предположить, что вероятнее всего это memset. А в случае с макросом еще проще
  • +2
    Я уже задавал этот вопрос в другом вашем посте, но тогда внятного ответа не получил. Почему вы не хотите оформить вызов анализатора как вызов компилятора? Подобно тому, как это делает distcc. Тогда, если сборка проекта позволяет указывать компилятор, никакие файлы править не надо, вызов анализатора сводится к

    СС=«PVS-Studio ...» ./configure && make

    Я очень рад, что так или иначе вы начали поддерживать GNU-style проекты, хотя начиналось всё с «у вас там никто не платит, поэтому не видать вам линукс версии».
    • 0
      А у нас примерно так и работает:

      PVS-Studio.exe --cl-params %ClArgs% --source-file %cppFile% --cfg %cfgPath% --output-file %ExtFilePath%

      cl-params — те самые параметры компилятора.

      Вот только без передачи других параметров пока что-то не можем обойтись. Хотя может и придумаем как это забороть.
      • +1
        Я не совсем это имел ввиду. Когда собирается проект, сконфигурированны через autotools, компилятор берется из переменной среды `CC`. Это позволяет легко менять компилятор на любой, поддерживающий флаги gcc. Например, я хочу собрать программу конкретной версией (более новой, стабильной, другая ветка). Тогда я могу написать:

        CC=/opt/gcc/bin/gcc-1.2.3 ./configure && make

        Это значение потом буквально подставляется во все места вызова компилятора во всех make-файлах. И если бы ваша программа так умела, то применение анализатора было бы делом пары секунд.

        Еще хочу заметить, что когда программа принимает какие-то параметры, но не использует их сама, а передает дальше, обычно используют строку `--`, чтобы разделить «свои» и «не свои» аргументы. Например:

        PVS-Studio --pvs-flag1 --pvs-flag2 — -Wall -ffast-math -o test


        Тут все, что идет после `--`, передается gcc.

        Если вам нужна помощь с интеграцией вашего инструмента с open-source — пишите, я с радостью помогу (бесплатно).
        • 0
          Про CC я понимаю. Нам по разным причинам хочется передавать еще часть своих параметров (--source-file и --output-file). Что придумать, чтобы решить этот вопрос?
          • 0
            Ну, --source-file вы и так можете получить, ведь вам доступны все параметры командной строки, включая имена файлов для компиляции. Кстати, gcc умеет компилировать сразу несколько файлов, вам тоже было бы неплохо так уметь. Насчет --output-file — почему бы брать имя исходного файла с вашим расширением? Например, если компилируется test.cpp, то вы можете записывать в test.pvslog. К сожалению, ничего другого посоветовать не могу.
            • 0
              Ну, --source-file вы и так можете получить


              Но для этого придется парсить строку.

              Кстати, gcc умеет компилировать сразу несколько файлов


              Мы тоже умеем.

              почему бы брать имя исходного файла с вашим расширением?


              Потому что это один лог на все файлы.
              • 0
                Соединить логи в один можно там, где работает линковщик.
                • 0
                  Так идея то нарушается! Ведь смысл в том, чтобы не править makefile.
                  • 0
                    Линковщик тоже можно подменить через переменную окружения LD, по аналогии с CC.
                    wiki.wxwidgets.org/Cross-Compiling_Under_Linux#environment_variables
                  • 0
                    В чем нарушается то?

                    ${CC} ${CCFLAGS} -c -o $@ $<
                    =>
                    PVS-Studio -cc=gcc — ${CCFLAGS} -c -o $@ $<

                    На выходе получим $@ и $@.pvs

                    ${LD} -o ${TARGET} ${OBJS} ${LIBS}
                    =>
                    PVS-Studio -ld=gcc — -o ${TARGET} ${OBJS} ${LIBS}

                    На выходе получаем ${TARGET} и готовый лог
                    • 0
                      Да, похоже так можно сделать. Попробуем, спасибо.
              • –1
                Для парсинга командной строки в линуксе есть, так что это совсем не сложно. Зачем вам один файл, я не очень понимаю. Наверно, я не понял вашу задумку в целом. Как пользователю мне было бы неудобно смотреть весь лог в поисках ошибок для конкретного файла. Vim читает stderr, так что вы можете дублировать туда.
                • +2
                  Мне кажется вы теоретик. Извините если не прав, но все, кто пользовался хоть раз статическим анализом типа lint говорили какой там отстой что при проверке каждого нового файла он выдает сообщения на одну и ту же .h-ку много раз. И как круто, что в PVS-Studio единый лог, где дубликаты фильтруются.
              • 0
                Если вы хотите хранить состояние, типа «сделать первый проход, вывести все ошибки, а во втором проходе какие-то убрать, какие-то добавить», то в этом случае создается обычно sqlite база в корне проекта.
                • 0
                  Создается один лог с полным списком сообщений. А затем его специальной утилитой можно преобразовывать с кучей фильтров: показать все ошибки с таким-то кодом, все ошибки из такой-то папки и т.п.
  • +1
    Вот тут кто-то проверял vim 7.4 в coverity: code.google.com/p/vim/issues/detail?id=333

    Упомянутый neovim, кстати, им проверяют на регулярной основе — scan.coverity.com/projects/2227
  • –1
    Так как получить linux-бету для пощупать?
    • +1
      Написать нам с корпоративного e-mail и обсудить условия контракта.
      • 0
        А публичная бета не ожидается? :) []
  • –2
    Традиционный вопрос: баги разработчикам заслали?
    • +2
      Да. Нас уже поблагодарили. Правда особенно не за что. В общем то ничего интересного не нашлось в этот раз.
      • –1
        Спасибо.
  • 0
    Можно узнать, почему категорически не планируется публичных версий под Linux?
    • 0
      У нас нет законченного продукта под Linux. Сейчас это на уровне alpha-версии. Соответственно выкладывать на публику это не имеет смысла, так как требуется набор напильников для запуска.
      • 0
        То есть, все-таки что-то планируется, просто позже, когда продукт дойдет до кондиции?
        • 0
          Не факт. Возможно по результатам первых продаж мы решим убить это направление.
          • 0
            Побуду занудой (раз уж на комментарий выше мне так никто и не ответил) и снова вас спрошу: почему бы не сделать Windows-версию (которая вполне себе перспективная, и которую явно никто не собирается убивать) поддерживающей работу из-под Wine? На первый взгляд это кажется проще, чем разрабатывать consumer-grade версию для GNU/Linux, и хоть как-то обрадует не-Windows пользователей и (возможно) потенциальных новых клиентов вашего бизнеса.
            • 0
              Ответ простой — спроса нет. Ни на версию на Wine, ни на версию для Linux. Всего пара команд отписалась в почту с интересом.
              • 0
                Да-да, вы мне так в январе и ответили, что нет спроса. Я, наверное, недостаточно четко выразился: речь не про Windows-версию, обернутую в Wine для непосредственного запуска в линуксе и готовую к проверке нативных проектов под Unix/Linux. Это как раз понятно, что большой труд, мало кому нужный одновременно.

                Я лишь про то, чтобы допилить обычную Windows-версию для запуска под вайном (версия 5.21 вываливается с Internal Error: Invalid escape sequence: '\b'), чтобы проверять вендовые же проекты без необходимости устанавливать Windows. Эта задача, на мой взгляд, вполне решаема. Никакой специальной вайн-версии не появляется — просто ваша обычная вендовая версия начинает работать под вайном (ничего про Linux при этом не зная).

                Уж если Photoshop CS2 вполне так работает, почему PVS-Studio не может? :-)
                • +2
                  Слушайте, эта проблема не стоит стольких комментариев, сколько Вы уже написали. Если это действительно вас беспокоит, то вопрос решается ОЧЕНЬ просто. Пишите нам в поддержку: «Я лицензионный пользователь PVS-Studio, лицензия такая-то. У меня вот тут немного не работает — допилите, пожалуйста.» И все. В абсолютно рабочем порядке такие доработки скорее всего будут сделаны.
                  • +1
                    Я не являюсь вашим лицензионным пользователем, и не имею никакого права требовать что-то от вашего саппорта. Мне интересен ваш продукт, но прежде чем говорить с руководством о перспективах приобретения, мне нужно будет не то что доказать, что покупка оправдана, но хотя бы продемонстрировать возможность запуска не-из-под Windows. Увы, сделать этого я не могу.

                    Кроме того, даже если бы я был лицензионным пользователем, нет никаких гарантий, что вы не ответите «извините, мы не обещали работу в Wine; вы же покупали версию для Windows? Там (нативно) всё работает? Ну вот видите, а наша (и ваша) поддержка распространяется исключительно на неё».

                    И последнее: имхо, «в абсолютно рабочем порядке такие доработки» обычно делаются просто потому, что неработающая в Wine user-space программа это странно: либо баг в программе (значит, надо пофиксить), либо в Wine (хорошо бы заслать bug report). В конце-концов, ведь для того, чтобы зарепортить проблему в публичной, ознакомительной версии, не должна требоваться покупка, правда?
                    • –2
                      К сожалению, поддержка Wine не в приоритете.
            • 0
              А смысл? Основную часть (анализатор) нужно ещё умудриться написать некросплатформенно, консольный UI тоже, а вот что придётся допиливать, так это ложные срабатывания из‐за заголовочных файлов, диагностики для несколько другого набора стандартных функций, … Это уже где‐то представители компании объясняли — сделать код кроссплатформенным легко. Научить анализатор работать с linux‐специфичными вещами сложнее.
              • 0
                Смысл, например, в том, чтобы проверять свой код PVS-студией, не устанавливая при этом Windows. Я не предлагаю «научить анализатор работать с linux‐специфичными вещами», пусть это будет моей головной болью — как бы так подсунуть свой код, чтобы PVS-студия его успешно проверила (посчитав вендовым). А вот ставить Windows и/или возиться с виртуалками я не хочу.

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

Самое читаемое Разработка