Статический анализ: ошибки в медиаплеере и безглючная аська

    Продолжу экскурсию по ошибкам в программах и демонстрацию полезности статического анализа кода.

    Это мой последний пост про пока недоступную для скачиванию версию PVS-Studio. Планирую, что через неделю вы уже сможете попробовать первую beta-версию с новым набором правил общего назначения.

    Рассмотрим два проекта. Первый — Fennec Media Project. Это универсальный медиа-плеер ориентированный на воспроизведение аудио и видео в высоком разрешении. В комплект исходных кодов входит множество модулей расширения (plugins) и кодеков, но анализироваться будет только сам плеер. Исходный код последней на данный момент версии 1.2 Alpha доступен здесь.

    Второй проект — qutIM. Это кроссплатформенный клиент мгновенного обмена сообщениями с открытым исходным кодом. Был проанализирован код на момент начала ноября 2010 года. Набор исходных кодов был предоставлен мне одним из разработчиков, но вы также можете скачать исходный код с официального сайта. Этот разработчик, кстати, присутствует здесь — gorthauer87.



    Fennec Media Project. Небольшой нормальный проект, содержащий нормальное количество ошибок. Вот первая ошибка. Или первые две ошибки, смотря как считать. В общем, в двух местах вместо переменной 'b' используется переменная 'a'.

    int fennec_tag_item_compare(struct fennec_audiotag_item *a,
      struct fennec_audiotag_item *b)
    {
      int v;
      if(a->tsize && a->tsize)
        v = abs(str_cmp(a->tdata, a->tdata));
      else
        v = 1;
      return v;
    }

    PVS-Studio указал на этот код, так как условие «a->tsize && a->tsize» явно подозрительно.

    Диагностическое сообщение и местоположение ошибки в коде:
    V501 There are identical sub-expressions to the left and to the right of the '&&' operator: a -> tsize && a -> tsize media library.c 1076
    А теперь родное и милое сердцу каждого программиста — лишние точки с запятой. Вот первый фрагмент:

    int settings_default(void)
    {
      ...
      for(i=0; i<16; i++);
        for(j=0; j<32; j++)
        {
          settings.conversion.equalizer_bands.boost[i][j] = 0.0;
          settings.conversion.equalizer_bands.preamp[i]   = 0.0;
        }
    }

    Сообщение PVS-Studio и местоположение коде:
    V529 Odd semicolon ';' after 'for' operator. settings.c 483
    Второй фрагмент:

    int trans_rest(transcoder_settings *trans)
    {
      ...
      for(i=0; i<16; i++);
      {
        trans->eq.eq.preamp[i]   = 0.0;
        for(j=0; j<32; j++)
        {
          trans->eq.eq.boost[i][j] = 0.0;
        }
      }
    }

    Сообщение PVS-Studio и местоположение коде:
    V529 Odd semicolon ';' after 'for' operator. settings.c 913
    Есть еще третий и четвертый фрагмент с ';'. Но приводить здесь не буду. Все однотипно и неинтересно.

    Дальше не совсем ошибка, но почти. Вместо функции _beginthreadex используется CreateThread. Вызовов CreateThread в Fennec несколько, но приведу только один пример:

    t_sys_thread_handle sys_thread_call(t_sys_thread_function cfunc)
    {
      unsigned long tpr = 0;
      unsigned long tid = 0;
      return (t_sys_thread_handle)
        CreateThread(0, 0, cfunc, &tpr, 0,&tid);
    }

    Предупреждение PVS-Studio и местоположение коде:
    V513 Use _beginthreadex/_endthreadex functions instead of CreateThread/ExitThread functions. system.c 331
    Вдаваться сейчас вглубь вопроса, почему следует использовать _beginthreadex/_endthreadex вместо CreateThread/ExitThread, не буду. Напишу совсем кратко, а подробные обсуждения данного вопроса можно почитать здесь, здесь и здесь.

    В священном писании (в MSDN) сказано:

    A thread in an executable that calls the C run-time library (CRT) should use the _beginthreadex and _endthreadex functions for thread management rather than CreateThread and ExitThread; this requires the use of the multi-threaded version of the CRT. If a thread created using CreateThread calls the CRT, the CRT may terminate the process in low-memory conditions.

    В общем лучше подстраховаться и всегда вызывать именно _beginthreadex/_endthreadex. Кстати именно так рекомендует поступать и Джеффри Рихтера в шестой главе «Windows для профессионалов: создание эффективных Win32-приложений с учетом специфики 64-разрядной версии Windows» / Пер. с англ. — 4-е изд.

    Обнаружилось несколько неудачных использований функции memset. Кстати, я до недавнего времени думал, что беспокойство, связанное с использованием memset, memcmp, memcpy — дело прошлого. Мол, это раньше так писали, но сейчас все знают про опасности, аккуратны с этими функциями, используют sizeof(), используют контейнеры из STL и так далее. А сейчас все розовое и мягкое. Оказывается, что нет. Я за последний месяц столько ляпов с этими функциями насмотрелся. Так что все эти ошибки по-прежнему цветут и пахнут.

    Вернемся в Fennec. Первый memset:

    #define uinput_size       1024
    typedef wchar_t letter;
    
    letter  uinput_text[uinput_size];
    
    string basewindows_getuserinput(const string title,
      const string cap, const string dtxt)
    {
      memset(uinput_text, 0, uinput_size);
      ...
    }

    Диагностика PVS-Studio и местоположение коде:
    V512 A call of the 'memset' function will lead to a buffer overflow or underflow. base windows.c 151
    На первый взгляд с «memset(uinput_text, 0, uinput_size);» все хорошо. И возможно даже и было хорошо, в те времена, когда тип 'letter' был 'char'. Но теперь это 'wchar_t' и как результат мы чистим только половину буфера.

    Второй неудачный memset:

    typedef wchar_t letter;
    letter name[30];
    
    int Conv_EqualizerProc(HWND hwnd,UINT uMsg,
      WPARAM wParam,LPARAM lParam)
    {
      ...
      memset(eqp.name, 0, 30);
      ...
    }

    Воистину магические числа — это зло. Вроде и не сложно написать «sizeof(eqp.name)». Но упорно не пишем и продолжаем вновь и вновь отстреливать себе ногу :).

    Диагностика PVS-Studio и местоположение коде:
    V512 A call of the 'memset' function will lead to a buffer overflow or underflow. base windows.c 2892
    Ну и еще в одном месте такая шибка есть:
    V512 A call of the 'memset' function will lead to a buffer overflow or underflow. transcode settings.c 588
    Возможно, иногда в каких-то программах вы замечали, что диалоги открытия/сохранения файлов работают со странностями или в полях доступных расширений присутствует какая-то чушь. Сейчас вы узнаете, откуда у этого растут ноги.

    В Windows API есть структуры, в которых указатели на строки должны заканчиваться двойным нулем. Наиболее используемым является член lpstrFilter в структуре OPENFILENAME. Этот параметр на самом деле указывает на набор строк, разделенных символом '\0'. А для того чтобы узнать, что строки закончились и нужны два нуля в конце.

    Вот только это очень просто забыть. Фрагмент кода:

    int JoiningProc(HWND hwnd,UINT uMsg,
      WPARAM wParam,LPARAM lParam)
    {
      ...
      OPENFILENAME  lofn;
      memset(&lofn, 0, sizeof(lofn));
      ...
      lofn.lpstrFilter = uni("All Files (*.*)\0*.*");
      ...
    }

    Сообщение PVS-Studio и местоположение коде:
    V540 Member 'lpstrFilter' should point to string terminated by two 0 characters. base windows.c 5309
    Будет диалог работать нормально или нет, зависит от того, что будет расположено в памяти после строки «All Files (*.*)\0*.*». По правильному здесь следовало написать «All Files (*.*)\0*.*\0». Один ноль явно указали мы, еще один ноль добавит компилятор.

    Аналогичная беда и с другими диалогами.

    int callback_presets_dialog(HWND hwnd, UINT msg,
      WPARAM wParam, LPARAM lParam)
    {
      ...
      // SAVE
      OPENFILENAME lofn;
      memset(&lofn, 0, sizeof(lofn));
      ...
      lofn.lpstrFilter = uni("Equalizer Preset (*.feq)\0*.feq");
      ...
      ...
      // LOAD
      ...
      lofn.lpstrFilter = uni("Equalizer Preset (*.feq)\0*.feq");
      ...
    }
    int localsf_show_save_playlist(void)
    {
      OPENFILENAME  lofn;
      memset(&lofn, 0, sizeof(lofn));
      ...
      lofn.lpstrFilter = uni("Text file (*.txt)\0*.txt\0M3U file\0*.m3u");
      ...
    }

    Диагностика PVS-Studio и местоположение в коде:
    V540 Member 'lpstrFilter' should point to string terminated by two 0 characters. base windows.c 986
    V540 Member 'lpstrFilter' should point to string terminated by two 0 characters. base windows.c 1039
    V540 Member 'lpstrFilter' should point to string terminated by two 0 characters. shared functions.c 360
    Теперь подозрительная функция. Очень подозрительная. Впрочем, действительно тут ошибка или просто неудачно написано, я не знаю:

    unsigned long ml_cache_getcurrent_item(void)
    {
      if(!mode_ml)
        return skin.shared->audio.output.playlist.getcurrentindex();
      else
        return skin.shared->audio.output.playlist.getcurrentindex();
    }

    Диагностика PVS-Studio и местоположение в коде:
    V523 The 'then' statement is equivalent to the 'else' statement. media library window.c 430
    Я не стал заниматься анализом разнообразный модулей расширений, идущих вместе с Fennec. Но там не меньше разных грустных мест. Приведу только пару примеров. Фрагмент кода из проекта Codec ACC.

    void MP4RtpHintTrack::GetPayload(...)
    {
      ...
      if (pSlash != NULL) {
        pSlash++;
        if (pSlash != '\0') {
          length = strlen(pRtpMap) - (pSlash - pRtpMap);
          *ppEncodingParams = (char *)MP4Calloc(length + 1);
          strncpy(*ppEncodingParams, pSlash, length);
        }
    }

    Как следует из диагностического сообщения PVS-Studio:
    V528 It is odd that pointer to 'char' type is compared with the '\0' value. Probably meant: *pSlash != '\0'. rtphint.cpp 346
    здесь забыли разыменовать указатель. Получается, что мы делаем бессмысленное сравнение указателя с 0. Должно было быть: «if (*pSlash != '\0')».

    Фрагмент кода из проекта Decoder Mpeg Audio:

    void* tag_write_setframe(char *tmem,
      const char *tid, const string dstr)
    {
      ...
      if(lset)
      {
        fhead[11] = '\0';
        fhead[12] = '\0';
        fhead[13] = '\0';
        fhead[13] = '\0';
      }
      ...
    }

    Диагностическое сообщение PVS-Studio и местоположение в коде:
    V525 The code containing the collection of similar blocks. Check items '11', '12', '13', '13' in lines 716, 717, 718, 719. id3 editor.c 716
    Вот оно зло метода Copy-Paste :).

    В целом на проекте Fennec Media Project анализ общего назначения в PVS-Studio показал себя очень хорошо. Анализ был выполнен с низким процентом ложных срабатываний. Всего PVS-Studio указал на 31 фрагмент кода. При этом в 19 местах код действительно следует поправить.

    Теперь перейдем к проекту qutIM.

    Вот с эти проектом PVS-Studio потерпел поражение. Несмотря на то, что проект достаточно крупный (около 200 тысяч сток), анализатор PVS-Studio не смог выявить в нем ошибок. Хотя они конечно есть. Они везде и всегда есть :). И разработчики qutIM с этим не спорят, так как в некоторых случаях qutIM умудряется падать.

    Приходится засчитать одно очко «команде ошибок».

    Что это означает? Это означает:

    1) Проект qutIM очень качественный проект. И хотя он тоже содержит ошибки, но они весьма редки и слишком высокого уровня для статического анализа (по крайней мере, для PVS-Studio).

    2) PVS-Studio предстоит еще долгий путь развития и обучения более высокоуровневым диагностикам. Теперь стало более очевидно к чему стремиться. Цель — найти в qutIM хотя бы парочку настоящих ошибок.

    Выдал ли что-то PVS-Studio для проекта qutIM? Выдал. Но немного и почти все ложные срабатывания. Из представляющего хоть какой-то интерес, можно выделить только следующее.

    A) Используются функции CreateThread.

    B) Найдено несколько странных функций. Потом один из авторов qutIM сообщил, что это забытые заглушки. Странность в том, что одна имеет имя save(), другая cancel(), но их содержимое идентично:

    void XSettingsWindow::save()
    {
      QWidget *c = p->stackedWidget->currentWidget();
      while (p->modifiedWidgets.count()) {
        SettingsWidget *widget = p->modifiedWidgets.takeFirst();
        widget->save();
        if (widget != c)
          widget->deleteLater();
      }
      p->buttonBox->close();
    }
    
    void XSettingsWindow::cancel()
    {
      QWidget *c = p->stackedWidget->currentWidget();  
      while (p->modifiedWidgets.count()) {
        SettingsWidget *widget = p->modifiedWidgets.takeFirst();
        widget->save();
        if (widget != c)
          widget->deleteLater();
      }  
      p->buttonBox->close();
    }

    Диагностика PVS-Studio:
    V524 It is odd that the 'cancel' function is fully equivalent to the 'save' function (xsettingswindow.cpp, line 256). xsettingswindow.cpp 268
    Надеюсь было интересно, и вы скоро захотите попробовать PVS-Studio 4.00 Beta. Конечно, PVS-Studio пока находит мало ошибок общего вида, но ведь это только начало. При этом исправление даже одной единственной ошибки на этапе кодирования может сэкономить массу нервов заказчикам, тестерам и программистам.



    P.S. Еще раз хочу поблагодарить всех, кто принял участие в обсуждении топика "Собираю страшненькое от программистов" и поделился примерами. Многое со временем войдет в PVS-Studio. Спасибо!
    PVS-Studio
    Static Code Analysis for C, C++, C# and Java

    Comments 69

    • UFO just landed and posted this here
        +1
        Супер, очень интересно.
        А не могли бы вы привести пример ложного срабатывания?
          +1
          Пример ложного срабатывания в Fennec:

          case get_window_playlist:
          	*((HWND*)rdata) = window_ml;
          	return 1;
          
          case get_window_vis:
          	*((HWND*)rdata) = window_vis;
          	return 1;
          
          case get_window_eq:
          	*((HWND*)rdata) = window_eq;
          	return 1;
          
          case get_window_ml:
          	*((HWND*)rdata) = window_ml;
          	return 1;
          


          Сообщение:

          V525 The code containing the collection of similar blocks. Check items 'window_ml', 'window_vis', 'window_eq', 'window_ml' in lines 744, 748, 752, 756. skin.c 744

          В общем не понравилось, что два раза используем переменную window_ml. Но так и должно быть.

          Это «средний» пример. Бывает глупее. :)
            +28
            Я согласен, кстати с PVS Studio
            Надо вот так:
            case get_window_playlist:
            case get_window_ml:
            	*((HWND*)rdata) = window_ml;
            	return 1;
            
            case get_window_vis:
            	*((HWND*)rdata) = window_vis;
            	return 1;
            
            case get_window_eq:
            	*((HWND*)rdata) = window_eq;
            	return 1;
            
              0
              Ладно, признаюсь, я слукавил. :) Я выбрал ложное срабатывание, которое имеет какой-то смысл. Вот другие примеры (не из Fennec):

              1) Буковки не понравились
              ml_head->sign[0]       = 'f';
              ml_head->sign[1]       = 'm';
              ml_head->sign[2]       = 'l';
              ml_head->sign[3]       = 'f';


              V525 The code containing the collection of similar blocks. Check items ''f'', ''m'', ''l'', ''f'' in lines 1171, 1172, 1173, 1174.

              2) Функции не понравились
              __int64 GetFilePos() const { return FilePos; };
              __int64 GetViewFilePos() const { return FilePos; };


              V524 It is odd that the 'GetViewFilePos' function is fully equivalent to the 'GetFilePos' function (viewer.hpp, line 226).

              Можно конечно написать одну через другую, но от этого совсем не станет лучше.


              3) Циклы не понравились
              for(c = lb; c <= ub; c++)
              {
                if (!(xlb <= xlat© && xlat© <= ub))
                {
                  Range * r = new Range(xlb, xlb + 1);
                  for (c = lb + 1; c <= ub; c++)
                  {
                    r = doUnion(r, new Range(xlat©, xlat© + 1));
                  }
                  return r;
                }
              }


              V535. The variable 'c' is being used for this loop and for the outer loop

              Хоть два цикла по одной переменной, это не страшно, так как мы потом сразу сделаем return r;.
                0
                последнее — брейнфак какой-то. рефакторинг не помешал бы, однозначно.
                  +1
                  Последнее, мне кажется, должно быть по силам статическому анализу. Если это не так, опять-таки интересно было бы послушать почему.
                  Но код все равно пахнет.
                    0
                    >> Но код все равно пахнет.

                    Золотые Ваши слова.

                    Суть статического анализа состоит в том, чтобы найти код, который подозрителен и желательно просмотреть его глазами. Если инструмент такой код находит — то значит инструмент работает. Конечно всем нам хотелось бы иметь внятную диагностику, но это уже не всегда получается.
                      0
                      По силам. Можно улучшить диагностику, добавив исключение на подобные случаи. Но все дырки не залепишь. Ложные срабатыванию будут все равно.
                      0
                      хотелось бы посмотреть что такое Range, так как подозреваю что new не нужен, возврат по значению был бы более профитным…
                        0
                        Это к делу не относится.
                    +1
                    вообще-то он совершенно правильный.
                    в сообщении говорится о похожести этих блоков, я бы переписал вот так:
                    /*switch(x) {
                        case get_window_ml:
                            *((HWND*)rdata) = window_ml;
                            return 1;
                        // похожие кейсы
                    }*/
                    //делаем проверку на х, только меняем логику, блабла
                    *((HWND*)rdata) = x;
                    return 1;
                    
                      0
                      там когда x == get_window_ml: значение должно подставится window_ml
                        0
                        точно, ошибся
                  –2
                  Картинка для привлечения внимания вызывает непередаваемое чувство омерзения. Это чей же воспалённый мозг сумел такое изобразить…
                    +3
                    Японский художник Ryohei Hase
                      0
                      Спасибо, очень понравилось. Вспоминается Сальвадор Дали, при просмотре некоторых из его творений.
                      +2
                      По многочисленным просьбам (в личной почте) картинку убрал. И что в ней такого…
                        0
                        Картинка классная, а монстр жуткий :)
                      0
                      Кстати, такой вопрос: в Qt используется такая вещь, как автоматическое удаление дочерних объектов, наследуемых от QObject (а наследниками QObject являются почти все Qt-классы). Т.е. если при создании объекта я укажу ему в качестве «родителя» другой объект, то созданный объект будет удалён вместе с родителем. Схематично это выглядит так:

                      QObject* parent = new QObject();
                      for ( int i = 0; i < 10; ++i ) {
                          QObject* child = new QObject(parent);
                      }
                      delete parent;
                      // there's no memory leak here!
                      

                      Одно из двух: либо в QutIM на этот механизм не полагаются, и на каждый new аккуратно ручками вызывается delete, либо PVS-Studio корректно обрабатывает эти случаи. Какой из вариантов верный? :)

                      Я почему спрашиваю — потому что далеко не каждый статический анализатор умеет это обрабатывать (cppcheck, к примеру, не умеет).
                        0
                        Ручками я ничего не удаляю, но мне кажется, что просто PVS видит, что указатели на эти объекты куда-то передаются и не считает их брошеными. Хотя я иногда делаю финты ушами типа:
                        connect(o,SIGNAL(finished()),o,SLOT(deleteLater());

                        Очень сомневаюсь, что какой-либо статический анализатор поймет, что объект o никуда не утек, а просто ждет завершения некого действия.
                        ЗЫ
                        На досуге можно сравнить количество низкоуровневых операций типа memset в проектах. А еще посмотреть как указатели упаковываются (у нас в тип данных qptrdiff, который гарантировано равен размеру указателя на платформе).
                        ЗЗЫ
                        Поднастроил уровень предупреждений в gcc и нашел в qutIM'е пару тройку старых добрых багов с отсутствием виртуального деструктора и отсутствия явного вызова parent конструктора у тех классов, где он должен быть вызван (в данном случае QSharedData). Странно, что PVS такую ерунду не заметил.
                          0
                          Поднастроил уровень предупреждений в gcc и нашел в qutIM'е пару тройку старых добрых багов с отсутствием виртуального деструктора и отсутствия явного вызова parent конструктора у тех классов, где он должен быть вызван (в данном случае QSharedData). Странно, что PVS такую ерунду не заметил.

                          Мы не идем по пути дублирования предупреждений, которые может выдать и компилятор. Усилий много, а пользы почти никакой. Раз хочется попробовать статический анализ, то для начала можно повысить уровень предупреждений в компиляторе. :)
                            0
                            Тем не менее, часто хочется видеть сразу все ошибки в одном месте. Фактически же можно наверное пытаться скомпилить проект и ошибки от компилятора тоже закидывать в отчет?
                              0
                              *то есть предупреждения (хотя в данном контексте их как ошибки скорее нужно воспринимать)
                                0
                                В лоб так делать — идея плохая. Но можно подумать, быть может, что-то альтернативное будет хорошо.
                              0
                              >Поднастроил уровень предупреждений в gcc и нашел в qutIM'е пару тройку старых добрых багов...

                              Я сейчас собираю исключительно с "-Wall -Werror -Wextra" — в своё время помогло найти пару хороших таких ошибок.
                                0
                                Ла я тоже, но оказалось, что эти флаги по просту не для всех подпроектов применялись из за банальной опечатки.
                              0
                              Мы (пока) не пытаемся искать ошибки утечки памяти. Это дело очень сложное и требует отдельного большого исследования и работы. Не все сразу.

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

                              Касательно QT. Если мы будем пытаться что-то искать, то естественно придется учитывать особенности наиболее популярных библиотек STL, QT, BOOST,…
                              +3
                              Здорово. А обновление базы определяемых ошибок возможно отдельно, как у антивирусов, или только через установку новой версии?
                                0
                                Только через установку новых версий. Хотя идея интересная, надо будет в дальнейшем подумать.
                                  +1
                                  Вряд ли это целесообразно. У антивирусов апдейты несколько раз в день, а у нас раз в месяц в среднем. При нашем объеме дистрибутива в 10-12Mb это не проблема.

                                  А модуль автообновления встроен в программу, так что она сама предложит скачать новую версию, если та уже вышла.
                                  +2
                                  >> P.S. Еще раз хочу поблагодарить всех кто принял участие в обсуждении топика «Собираю страшненькое от программистов» и поделился примерами. Многое со временем войдет в PVS-Studio. Спасибо!

                                  а в связи с этим, бесплатный community edition будет??))
                                    +2
                                    Анализ общего назначения будет бесплатен. Каждый сможет скачать и попробовать без ограничений новый набор правил.

                                    А как дальше пойдет развития загадывать рано. Может спонсора найдем и тогда так и останемся бесплатными и может даже станем open source. Быть может захотим продавать. Сейчас рано думать. Слабоваты мы. В начале надо увеличить базу ошибок, понравиться людям и так далее.
                                      0
                                      open source при работе на windows, имхо, лишковат.
                                        +4
                                        Зависит от спонсора. Вот если бы Google или Intel изъявили желание подарить миру open source интрумент типа нашего, то мы бы изъявили желание помочь в этом.
                                      0
                                      а в связи с этим, бесплатный community edition будет??))

                                      Что-то появилось на тему бесплатности: Как использовать PVS-Studio бесплатно :).
                                      +1
                                      [оффтоп]Уберите, пожалуйста, эту страшную картинку из начала поста, очень ссыкотно[/оффтоп]
                                        +2
                                        Точно. Напоминает SCP-173-
                                          0
                                          Вот зачем, зачем вы показали ЭТО? :(
                                            0
                                            Мискузи! :)
                                              0
                                              Черд… я спать теперь боюсь.
                                            • UFO just landed and posted this here
                                                0
                                                Вы правы. И не собираюсь :)
                                            0
                                            Andrey2008, я бы молчал если бы этот топик не был на главной >_
                                              0
                                              Большое спасибо!
                                              0
                                              1600 евро? И много берут?
                                                +1
                                                Берут понемногу. 64-битные ошибки ищут.
                                                Это совсем не дорого по сравнения с…
                                                  0
                                                  Кстати по 1600 евро особо много и не обязательно даже, чтобы было уже хорошо.
                                                  0
                                                  Может кто-нибудь расскажет про другие проекты по стат анализу кода и краткие отзывы о них, тема интересная, полезная.
                                                    +1
                                                    Это не так просто как кажется. Очень мало инструментов можно скачать и попробовать, очень скудная публичная документация.
                                                    +6
                                                    Удачный заголовок поста.
                                                      0
                                                      Это кстати печально. Я подозреваю, что это несколько нам портит рейтинг, озлобляет на наши письма спамфильтры и так далее. Я уже даже жаловался немного на это.
                                                        +1
                                                        Вам смешно, а у нас знаете какие проблемы со спам-фильтрами из-за этого…
                                                          0
                                                          А я тут прочитал заголовок как «Студенческий анализ кода» и в итоге задумался…
                                                          +1
                                                          Только что закончил ловить противную багу, в нативной либе под Android.

                                                          Если упростить проблема была следующая

                                                          CSprite* a = spriteFactory->createSprite()
                                                          CSprite* b = a;

                                                          /и где-то в различных методах

                                                          delete a;
                                                          delete b;

                                                          Поймает такое?

                                                          В реальноcти был такой говно метод

                                                          void grDeleteSprite(CSprite *Spr)
                                                          {
                                                          CSpriteExt *Sprite = (CSpriteExt*) Spr;
                                                          if(!Sprite) return;
                                                          if( (--Sprite->count)>0 ) return;
                                                          if(Sprite->count<0) return;
                                                          Sprite = SpriteLib.Detach( Sprite );
                                                          if(Sprite) delete Sprite;
                                                          }
                                                          При создании через фабрику одинаковые спрайты кэшировались и увеличивался счетчик, при присваивании напрямую счетчик оставался.
                                                            0
                                                            мда, как-то они перемудрили с обычными shared объектами, Александреску на них не хватает)
                                                              0
                                                              Знакомые строки, к сожалению. Мир тесен (:
                                                                0
                                                                Сейчас никаких диагностик на лики/двойное удаление и т.п. нет. Кстати в этом направлении очень даже хорош динамический анализ в Parallel Studio.
                                                                  0
                                                                  Или тогда уж делать нормальный разделяемый объект или же тогда делать нормальный RAII, я вот мечтаю о каком-нибудь формальной проверялки паттернов проектирования, чтобы она указывала где явно юзается говнопаттерн.
                                                                  0
                                                                  А есть ли какие-нибудь планы по выпуску PVS-Studio для платформ отличных от Windows и не привязанных к Visual Studio?
                                                                    0
                                                                    Планы есть. Денег нет.
                                                                    0
                                                                    К нам не очень часто обращаются с подобными вопросами, поэтому честно говоря интереса не видно.

                                                                    С другой стороны это довольно реально (технических сложностей нет), было бы кому это нужно. Знаете таких? Мы готовы к разработке специализированного решения для конкретного заказчика.
                                                                      0
                                                                      Скажем так. Я работаю в компании разрабатывающую различные приборы.
                                                                      Для некоторых ПО пишется без ОС во всевозможных средах производителей плат и процессоров.
                                                                      Для некоторых — на базе линукса и соответственно в линуксе.
                                                                      На данный момент мы применяем cppcheck для проверки C++ кода. Если бы Ваша система дала реальное увеличение качества тестирования за разумные деньги… было бы что обсуждать по крайней мере.
                                                                      Однако я не могу найти реальное сравнение работы PVS по сравнению с другими системами синтаксического анализа. Да и 6000 евро… хм… без сравнения с бесплатным средством выглядит как авантюра.
                                                                        +4
                                                                        Спасибо за высказанное мнение, я его прокомментирую с удовольствием.

                                                                        Во-первых, рекомендую дождаться нашей новой версии (1-2 недели) и заценить своими глазами. Вы убедитесь, что cppcheck – и рядом не валялся, как минимум, по удобству использования и возможностям, которые обеспечивает инструмент для работы с результатами анализа.

                                                                        Во-вторых, про сравнение с другими. У нас, конечно же, есть статьи-сравнения, но сравниться с кем-то – это дело очень непростое. Не всегда доступны другие инструменты (скорее никогда не доступны), не ясно на каких наборах ошибок сравниваться (на наших наборах мы выиграем, на их – они), да и главное выдать, к примеру, суммарное рейтинговое число 73 и сказать, что мы лучше – толку мало будет. Так что повторюсь, скоро выйдет версия – можете сами сравнить на тех задачах, которые Вам нужны.

                                                                        В-третьих, про 6000 евро. К сожалению, мы маленькая компания и не умеем продавать по 100 евро. Мы бы может даже и хотели, но не получается. Никакой иронии в этой фразе нет.

                                                                        Так вот, чем мы лучше других? У нас поддержка – зашибись! То есть не как у всех «высококлассные сертифицированные специалисты с удовольствием ответят на всех ваши вопросы». А у нас реально «зашибись» поддержка. Хотите пообщаться с главным разработчиком модуля анализа? Вот он:
                                                                        andrey2008
                                                                        Хотите наорать («где у вас тут самый главный!?») за что-то на начальника – пожалуйста, вот он я: evgeniyryzhkov. Хотите, чтобы мы прикрутили мега-крутую диагностику? Легко. Версию «в полосочку, а не в цветочек»? Легко. Хотите по телефону? На русском языке? Легко. Ну кто еще такое может предоставить? Никто.

                                                                        Ну и продукт у нас крутой конечно, зная cppcheck, Вы оцените нас, я уверен.
                                                                          +1
                                                                          cppcheck вообще детская игрушка, опять же не нашел ни одной ошибки Оо. Я больше всего надеюсь на дальнейшее развитие clang'а и scanbuild'а, а также собственно llvm для динамического анализа.
                                                                      0
                                                                      Свершилось: PVS-Studio для Linux.
                                                                      +2
                                                                      Не хоте ли бы вы тестировать программу ядре linux (было бы полезно для opensource)?
                                                                        +4
                                                                        Хотели бы. Ищем спонсора. Было бы полезно для бизнеса.

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