Единорог заинтересовался KDE


    KDE (сокращение от K Desktop Environment) — среда рабочего стола, преимущественно для Linux и других UNIX-подобных систем. Если простым языком, то это та штука, которая отвечает за всё графическое оформление. Среда построена на основе кроссплатформенного инструментария разработки пользовательского интерфейса Qt. Разработкой занимаются несколько сотен программистов со всего мира, преданных идее свободного программного обеспечения. KDE предлагает полный набор приложений пользовательского окружения, который позволяет взаимодействовать с операционной системой в современном графическом интерфейсе. Давайте же посмотрим, что у KDE под капотом.

    Следующие пакеты проекта KDE версии 4.14 проверялись с помощью PVS-Studio 5.19 в OpenSUSE Factory:
    • KDE PIM Libraries
    • KDE Base Libraries
    • KDE Base Apps
    • KDE Development

    KDE PIM Libraries


    V547 Expression is always true. Probably the '&&' operator should be used here. incidenceformatter.cpp 2684
    enum PartStat {
      ....
      Accepted,
      Tentative,
      ....
    };
    
    static QString formatICalInvitationHelper(....)
    {
      ....
      a = findDelegatedFromMyAttendee( inc );
      if ( a ) {
        if ( a->status() != Attendee::Accepted ||      //<==
             a->status() != Attendee::Tentative ) {    //<==
          html += responseButtons( inc, rsvpReq, rsvpRec, helper );
          break;
        }
      }
      ....
    }

    Выражение всегда истинно. Причиной может быть опечатка или неправильная логика программиста. Возможно, здесь необходимо использовать оператор '&&'.

    Аналогичное подозрительное место:
    • V547 Expression is always true. Probably the '&&' operator should be used here. incidenceformatter.cpp 3293

    V593 Consider reviewing the expression of the 'A = B == C' kind. The expression is calculated as following: 'A = (B == C)'. kio_ldap.cpp 535
    void LDAPProtocol::del( const KUrl &_url, bool )
    {
      ....
      if ( (id = mOp.del( usrc.dn() ) == -1) ) {
        LDAPErr();
        return;
      }
      ret = mOp.waitForResult( id, -1 );
      ....
    }

    Приоритет оператора сравнения (==) выше приоритета оператора присваивания (=). Благодаря везению, условие выполняется как задумно, но дальше используется некорректное значение идентификатора 'id', равное 0.

    V595 The 'incBase' pointer was utilized before it was verified against nullptr. Check lines: 2487, 2491. incidenceformatter.cpp 2487
    static QString formatICalInvitationHelper(....)
    {
      ....
      incBase->shiftTimes( mCalendar->timeSpec(), ....);
    
      Incidence *existingIncidence = 0;
      if ( incBase && helper->calendar() ) {
        ....
      }
      ....
    }

    Разыменование указателя 'incBase' выполняется перед его проверкой.

    V622 Consider inspecting the 'switch' statement. It's possible that the first 'case' operator is missing. listjob.cpp 131
    void ListJob::doStart()
    {
      Q_D( ListJob );
    
      switch ( d->option ) {
        break;                          //<==
      case IncludeUnsubscribed:
        d->command = "LIST";
        break;
      case IncludeFolderRoleFlags:
        d->command = "XLIST";
        break;
      case NoOption:
      default:
        d->command = "LSUB";
      }
      ....
    }

    В блоке оператора 'switch' первым оператором не является 'case'. Это приводит к тому, что фрагмент кода никогда не получит управление. В лучшем случае оператор 'break' остался после неполного удаления старого условия, но в худшем случае тут пропущен ещё один 'case'.

    V701 realloc() possible leak: when realloc() fails in allocating memory, original pointer 'lexBuf.strs' is lost. Consider assigning realloc() to a temporary pointer. vcc.y 638
    static void lexAppendc(int c)
    {
      lexBuf.strs = (char *) realloc(lexBuf.strs, (size_t) .... + 1);  
      lexBuf.strs[lexBuf.strsLen] = c;
      ....
    }

    Данное выражение является потенциально опасным: рекомендуется результат функции realloc сохранять в другой переменной. Функция realloc() производит изменение размера некоторого блока памяти. В случае ошибки указатель на старую область памяти будет утерян.

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

    Аналогичные места:
    • V701 realloc() possible leak: when realloc() fails in allocating memory, original pointer 'mods' is lost. Consider assigning realloc() to a temporary pointer. ldapoperation.cpp 534
    • V701 realloc() possible leak: when realloc() fails in allocating memory, original pointer 'mods[i]->mod_vals.modv_bvals' is lost. Consider assigning realloc() to a temporary pointer. ldapoperation.cpp 579
    • V701 realloc() possible leak: when realloc() fails in allocating memory, original pointer 'ctrls' is lost. Consider assigning realloc() to a temporary pointer. ldapoperation.cpp 624
    • V701 realloc() possible leak: when realloc() fails in allocating memory, original pointer 'fp->s' is lost. Consider assigning realloc() to a temporary pointer. vobject.c 1055
    • V701 realloc() possible leak: when realloc() fails in allocating memory, original pointer 'lexBuf.strs' is lost. Consider assigning realloc() to a temporary pointer. vcc.y 635
    • V701 realloc() possible leak: when realloc() fails in allocating memory, original pointer 'lexBuf.strs' is lost. Consider assigning realloc() to a temporary pointer. vcc.y 643
    • V701 realloc() possible leak: when realloc() fails in allocating memory, original pointer 'bytes' is lost. Consider assigning realloc() to a temporary pointer. vcc.y 928
    • V701 realloc() possible leak: when realloc() fails in allocating memory, original pointer 'fp->s' is lost. Consider assigning realloc() to a temporary pointer. vobject.c 1050

    KDE Base Libraries


    V523 The 'then' statement is equivalent to the 'else' statement. kconfig_compiler.cpp 1051
    QString newItem( const QString &type, ....)
    {
      QString t = "new "+cfg.inherits+"::Item" + ....;
      if ( type == "Enum" ) t += ", values" + name;
      if ( !defaultValue.isEmpty() ) {
        t += ", ";
        if ( type == "String" ) t += defaultValue;        //<==
        else t+= defaultValue;                            //<==
      }
      t += " );";
    
      return t;
    }

    Одинаковые истинная и ложная ветвь оператора 'if' выглядят крайне подозрительно. Если код всё-таки не содержит опечатку, то его можно упростить, например, так:
    if ( !defaultValue.isEmpty() )
        t += ", " + defaultValue;

    Похожее место:
    • V523 The 'then' statement is equivalent to the 'else' statement. installation.cpp 589

    V595 The 'priv->slider' pointer was utilized before it was verified against nullptr. Check lines: 786, 792. knuminput.cpp 786
    void KDoubleNumInput::spinBoxChanged(double val)
    {
      ....
      const double slidemin = priv->slider->minimum();      //<==
      const double slidemax = priv->slider->maximum();      //<==
      ....
      if (priv->slider) {                                   //<==
        priv->slider->blockSignals(true);
        priv->slider->setValue(qRound(slidemin + rel * (....)));
        priv->slider->blockSignals(false);
      }
    }

    Разыменование указателя 'priv' выполняется перед его проверкой.

    Похожие опасные места:
    • V595 The 'm_instance' pointer was utilized before it was verified against nullptr. Check lines: 364, 376. ksystemtimezone.cpp 364
    • V595 The 'job' pointer was utilized before it was verified against nullptr. Check lines: 778, 783. knewfilemenu.cpp 778

    V646 Consider inspecting the application's logic. It's possible that 'else' keyword is missing. karchive.cpp 187
    *bool KArchive::close()
    {
      ....
      // if d->saveFile is not null then it is equal to d->dev.
      if ( d->saveFile ) {
        closeSucceeded = d->saveFile->finalize();
        delete d->saveFile;
        d->saveFile = 0;
      } if ( d->deviceOwned ) {                                 //<==
        delete d->dev; // we created it ourselves in open()
      }
      ....
    }

    Данный фрагмент кода может свидетельствовать о пропуске ключевого слова 'else', либо это просто крайне ненаглядное и сбивающие с толку оформление кода.

    V655 The strings was concatenated but are not utilized. Consider inspecting the expression. entrydetailsdialog.cpp 225
    void EntryDetails::updateButtons()
    {
      ....
      foreach (....) {
        QString text = info.name;
        if (!info.distributionType.trimmed().isEmpty()) {
            text + " (" + info.distributionType.trimmed() + ")";//<==
        }
        QAction* installAction =
          installMenu->addAction(KIcon("dialog-ok"), text);
        installAction->setData(info.id);
      }
      ....
    }

    Анализатор обнаружил неиспользуемое объединение строковых переменных. Возможно, код должен быть таким:
    text += " (" + info.distributionType.trimmed() + ")";

    Аналогичные места:
    • V655 The strings was concatenated but are not utilized. Consider inspecting the expression. itemsgridviewdelegate.cpp 365
    • V655 The strings was concatenated but are not utilized. Consider inspecting the expression. itemsviewdelegate.cpp 159

    V705 It is possible that 'else' block was forgotten or commented out, thus altering the program's operation logics. entrydetailsdialog.cpp 149
    void EntryDetails::entryChanged(const KNS3::EntryInternal& entry)
    {
      ....
      if(m_entry.previewUrl(EntryInternal::PreviewSmall1).isEmpty()){
        ui->previewBig->setVisible(false);
      } else                                //<==
    
      if (!m_entry.previewUrl((....)type).isEmpty()) {
        ....
      }
      ....
    }

    Оформление этого фрагмента кода тоже выглядит неоднозначно. Планировалась ли тут конструкция «else if» или же просто забыли удалить 'else'?

    V612 An unconditional 'return' within a loop. bufferfragment_p.h 94
    BufferFragment split(char c, unsigned int* start) 
    {
      while (*start < len) {
        int end = indexOf(c, *start);
        if (end == -1) end = len;
        BufferFragment line(d + (*start), end - (*start));
        *start = end + 1;
        return line;
      }
      return BufferFragment();
    }

    Стоило ли писать цикл из-за одной итерации? Или же не хватает условного оператора?

    V701 realloc() possible leak: when realloc() fails in allocating memory, original pointer 'd' is lost. Consider assigning realloc() to a temporary pointer. netwm.cpp 596
    template <class Z>
    void NETRArray<Z>::reset() {
        sz = 0;
        capacity = 2;
        d = (Z*) realloc(d, sizeof(Z)*capacity);
        memset( (void*) d, 0, sizeof(Z)*capacity );
    }

    Как и в «KDE PIM Libraries», здесь не рекомендутся использовать один указатель с функцией realloc(), так как указатель на старую область памяти может быть утерян, если память не удастся увеличить.

    Аналогичные места:
    • V701 realloc() possible leak: when realloc() fails in allocating memory, original pointer 'handlers' is lost. Consider assigning realloc() to a temporary pointer. kxerrorhandler.cpp 94
    • V701 realloc() possible leak: when realloc() fails in allocating memory, original pointer 'buffer' is lost. Consider assigning realloc() to a temporary pointer. netwm.cpp 528
    • V701 realloc() possible leak: when realloc() fails in allocating memory, original pointer 'd' is lost. Consider assigning realloc() to a temporary pointer. netwm.cpp 608
    • V701 realloc() possible leak: when realloc() fails in allocating memory, original pointer 'ptr' is lost. Consider assigning realloc() to a temporary pointer. kdesu_stub.c 119
    • V701 realloc() possible leak: when realloc() fails in allocating memory, original pointer 'addr.generic' is lost. Consider assigning realloc() to a temporary pointer. k3socketaddress.cpp 372

    KDE Base Apps


    V501 There are identical sub-expressions 'mimeData->hasFormat(QLatin1String(«application/x-kde-ark-dndextract-service»))' to the left and to the right of the '&&' operator. iconview.cpp 2357
    void IconView::dropEvent(QGraphicsSceneDragDropEvent *event)
    {
      ....
      if (mimeData->hasFormat(QLatin1String(
           "application/x-kde-ark-dndextract-service")) &&      //<==
          mimeData->hasFormat(QLatin1String(
           "application/x-kde-ark-dndextract-service")))        //<==
      {
        const QString remoteDBusClient = mimeData->data(
          QLatin1String("application/x-kde-ark-dndextract-service"));
        const QString remoteDBusPath = mimeData->data(
          QLatin1String("application/x-kde-ark-dndextract-path"));
        ....
      }
      ....
    }

    Анализатор обнаружил одинаковые условные выражения. По телу условного оператора логично предположить, что условие должно быть таким:
    if (mimeData->hasFormat(QLatin1String(
           "application/x-kde-ark-dndextract-service")) &&     //<==
          mimeData->hasFormat(QLatin1String(
           "application/x-kde-ark-dndextract-path ")))         //<==
    {
      ....
    }

    V595 The 'm_view' pointer was utilized before it was verified against nullptr. Check lines: 797, 801. kitemlistcontroller.cpp 797
    bool KItemListController::mouseDoubleClickEvent(....)
    {
      const QPointF pos = transform.map(event->pos());
      const int index = m_view->itemAt(pos);
    
      // Expand item if desired - See Bug 295573
      if (m_mouseDoubleClickAction != ActivateItemOnly) {
        if (m_view && m_model && ....) {
          const bool expanded = m_model->isExpanded(index);
          m_model->setExpanded(index, !expanded);
        }
      }
      ....
    }

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

    V637 Two opposite conditions were encountered. The second condition is always false. Check lines: 410, 412. kebsearchline.cpp 410
    void
    KViewSearchLine::slotColumnsRemoved(const QModelIndex &,
                                        int first, int last)
    {
      if(d->treeView)
        updateSearch();
      else
      {
        if(d->listView->modelColumn() >= first &&
           d->listView->modelColumn() <= last)
        {
          if(d->listView->modelColumn()>last)   //<==
            kFatal()<<"...."<<endl;
          updateSearch();
        }
      }
    }

    Вложенное условие будет всегда ложным. Можно предположить, что такое условие было актуальным до некоторых правок.

    V654 The condition 'state != 1' of loop is always true. passwd.cpp 255
    int PasswdProcess::ConversePasswd(....)
    {
      ....
      state = 0;
      while (state != 1)
      {
        line = readLine();
        if (line.isNull())
        {
          // No more input... OK
          return 0;
        }
        if (isPrompt(line, "password"))
        {
          // Uh oh, another prompt. Not good!
          kill(m_Pid, SIGKILL);
          waitForChild();
          return PasswordNotGood;
        }
        m_Error += line + '\n'; // Collect error message
      }
      ....
    }

    Значение переменной 'state' не изменяется в цикле, следовательно, условием остановки является только вызов 'return'.

    KDE Development


    V501 There are identical sub-expressions 'file == rhs.file' to the left and to the right of the '&&' operator. pp-macro.cpp 44
    bool pp_macro::operator==(const pp_macro& rhs) const {
      if(completeHash() != rhs.completeHash())
        return false;
      
      return name == rhs.name && file == rhs.file &&      //<==
             file == rhs.file &&                          //<==
             sourceLine == rhs.sourceLine &&
             defined == rhs.defined &&
             hidden == rhs.hidden &&
             function_like == rhs.function_like &&
             variadics == rhs.variadics &&
             fixed == rhs.fixed &&
             defineOnOverride == rhs.defineOnOverride &&
             listsEqual(rhs);
    }

    Анализатор обнаружил несколько мест с повторяющимися условными выраженями. Что-то из этого вполне может быть серьёзной опечаткой.

    Ещё такие места:
    • V501 There are identical sub-expressions 'tokenKind == Token_not_eq' to the left and to the right of the '||' operator. builtinoperators.cpp 174
    • V501 There are identical sub-expressions '!context->owner()' to the left and to the right of the '||' operator. typeutils.cpp 194

    V595 The 'parentJob()->cpp()' pointer was utilized before it was verified against nullptr. Check lines: 437, 438. cppparsejob.cpp 437
    void CPPInternalParseJob::run()
    {
        ....
        QReadLocker lock(parentJob()->parentPreprocessor() ?
          0: parentJob()->cpp()->language()->parseLock());      //<==
        if(.... || !parentJob()->cpp())                         //<==
          return;
        ....
    }

    И в этом проекте нашлось место с разыменованием указателя до его проверки.

    Ещё место:
    • V595 The 'parentContext()' pointer was utilized before it was verified against nullptr. Check lines: 692, 695. context.cpp 692

    V564 The '&' operator is applied to bool type value. You've probably forgotten to include parentheses or intended to use the '&&' operator. usedecoratorvisitor.cpp 40
    DataAccess::DataAccessFlags typeToDataAccessFlags(....)
    {
      DataAccess::DataAccessFlags ret = DataAccess::Read;
      TypePtr< ReferenceType > reftype=type.cast<ReferenceType>();
      if(reftype && reftype->baseType() &&
         !reftype->baseType()->modifiers() &    //<==
         AbstractType::ConstModifier)
        ret |= DataAccess::Write;
      
      return ret;
    }

    Авторам лучше знать, ошибка здесь или нет, но оператор '&' выглядит подозрительно. Обратите внимание, что выражение "!reftype->baseType()->modifiers()" имеет тип 'bool'.

    V555 The expression 'm_pos — backOffset > 0' will work as 'm_pos != backOffset'. pp-stream.cpp 225
    unsigned int rpp::Stream::peekLastOutput(uint backOffset) const {
      if(m_pos - backOffset > 0)
        return m_string->at(m_pos - backOffset - 1);
      return 0;
    }

    Сравнивать разность беззнаковых чисел с нулём не совсем корректно, потому что отрицательный результат может интерпретироваться как очень большое положительное число. Чтобы в теле условия не получить гигантский индекс, лучше написать условие таким образом:
    if(m_pos > backOffset)
        return m_string->at(m_pos - backOffset - 1);

    Похожее место:
    • V555 The expression 'nextOffset — currentOffset > 0' will work as 'nextOffset != currentOffset'. pp-location.cpp 211

    Заключение


    Огромная аудитория пользователей и разработчиков продуктов KDE играет большую роль в плане тестирования, но также стоит уделять внимание и различным анализаторам кода. Впрочем, если судить по публикациям в Интернете, для проверки исходных кодов KDE уже используется как минимум Coverity. Именно из-за этого PVS-Studio находит очень мало подозрительных мест.

    Используя статический анализ регулярно, можно сэкономить массу времени на решение более полезных задач. Также контроль за качеством кода можно переложить на других, например, воспользовавшись новой услугой: регулярный аудит Си/Си++ кода.

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


    Если хотите поделиться этой статьей с англоязычной аудиторией, то прошу использовать ссылку на перевод: Svyatoslav Razmyslov. The Unicorn Getting Interested in KDE.

    Прочитали статью и есть вопрос?
    Часто к нашим статьям задают одни и те же вопросы. Ответы на них мы собрали здесь: Ответы на вопросы читателей статей про PVS-Studio и CppCat, версия 2014. Пожалуйста, ознакомьтесь со списком.
    PVS-Studio
    558,00
    Static Code Analysis for C, C++, C# and Java
    Поделиться публикацией

    Похожие публикации

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

      +1
      Вопрос немного не по теме статьи, но все же.

      Какой парсер («парсер» в смысле Computer Science парсеров) используется в PVS-Studio? Все тот же LL(k) с бэктрекингом, что в оригинальном OpenC++?
        +1
        Гм… Какой… Какой был в OpenC++, такой и используем. :) Кажется, рукописный. По коду видно, что кое-что было сгенерировано, но потом сильно переделывалось вручную. Почему OpenC++? На тот момент нам показалось это лучшее что было бесплатное, нормально собираемое и работающее под Windows. Про Clang тогда никто ничего не знал.
          +2
          Ага, значит, родной рукописный LL(k), спасибо :)

          Я не спрашиваю, кстати, почему не Clang, Clang вообще отношению к этому не имеет. Это большой компилятор для плюсов с традиционным для плюсов хаками и костылями внутри. И не знаю, честно говоря, почему народ так массово этим интересуется. Buzzwords такие buzzwords…
        –2
        Для Rust планируете делать анализатор?
          +22
          Ребята даже для linux/gcc не хотят в анализатор добавлять поддержку, т.к. не видят там потенциальных покупателей и рынка, а вы за «какой-то там rust» интересуетесь, который до первого релиза еще не добрался, не говоря уж о каком-то комьюнити сравнимом с линуксовым c/c++. :)
            –4
            Давайте, всё-таки, не придумывать ответы за представителей PVS-Studio.
              +16
              А никто и не придумывает. На хабре их давно спрашивают «когда добавите поддержку linux/gcc», а ответ от них стандартный: «тогда когда появятся реальные заказчики с деньгами, т.к. слишком большой пласт работы». Вот и всё. Так что считайте вам пересказали официальную позицию.
                +8
                Ну и соответственно, с чего вдруг им поддерживать какой-то свежерождённый язык с пока не ясными перспективами, если им даже не интересен весьма солидный рынок linux/gcc?
                  +9
                  Всё правильно.
                0
                Всему своё время: PVS-Studio для Linux.
              +3
              На сколько адекватно анализатор справляется с кодом в котором есть qt (там всякие сигналы/слоты) оссобености?
                +2
                Если подсунуть окончательный препроцессированный файл, то нормально справится. А так — никак. Если есть коммерческий проект и такая задача, можно пообщаться в почте.
              • НЛО прилетело и опубликовало эту надпись здесь
                • НЛО прилетело и опубликовало эту надпись здесь
                    +4
                    Откройте, пожалуйста, последний спойлер в статье и кликните по ссылочке.
                    А минусуют потому что к каждой статье про анализ open source проектов задают одни и те же вопросы.
                    • НЛО прилетело и опубликовало эту надпись здесь
                      • НЛО прилетело и опубликовало эту надпись здесь
                          –2
                          Тем не менее было бы интересно каким образом, куда сообщили и какой ответ получили.
                        +5
                        Видимо за то, что вы не читаете статью.
                        • НЛО прилетело и опубликовало эту надпись здесь
                          0
                          Пока не отправили (автор статьи пока занят и отошёл из офиса). Но отправит. Всегда стараемся уведомить о найденных дефектах.
                          0
                          Спасибо за очередную проверку отличного проекта!
                          Отправлял несколько патчей в KDE, надеюсь анализатором заинтересуются. К слову, у них есть свой простенький анализатор, по возможностям ближе даже к style checker: krazy (онлайн-отчёты здесь). CppCheck находит больше ошибок, но ему, конечно, не сравниться с вашим продуктом. Прогнал сейчас на KDE Pim Libraries, нашлись только ошибки с приоритетом операций и неправильной работа с realloc() (обычно проверка на NULL и сравнение unsigned с отрицательным числом тоже находится, но здесь ему чего-то не хватило, чтобы их увидеть).
                            0
                            KDE (сокращение от K Desktop Environment)

                            Пользователь reddit /u/iamtheLINAX намекает, что после ребрэндинга это представление несколько устарело:

                            After the repositioning, the name KDE no longer stands for K Desktop Environment, as it now acts as an umbrella brand for software produced by the community. What would have been previously known as KDE 4 will now be referred as «KDE Software Compilation 4» (abbreviated «KDE SC 4»). Regardless, many users still refer to it as KDE 4. With the releases of Frameworks 5 and Plasma 5, the term «Software Compilation» is again retired, in favor of the names of each specific product the KDE community produces.

                            en.wikipedia.org/wiki/KDE#Brand_repositioning

                            Вольный перевод:
                            После ребрэндинга, название KDE более не означает «K Desktop Environment», поскольку отныне является брэндом, объединяющим программное обеспечение, разрабатываемое сообществом. То, что ранее называлось KDE 4, с тех пор называют «KDE Software Compilation 4» (аббревиатура «KDE SC 4»). Многие пользователи всё ещё называют этот продукт именем KDE 4. С выходом Frameworks 5 и Plasma 5 устареет и термин «Software Compilation», в угоду именам отдельных продуктов, производимых сообществом KDE.


                              –2
                              Использую тайловый awesome. Как то собрался с духом и решил попробовать KDE тем более что там вроде как есть тайловый режим.
                              Первое впечатление — красота. Минут через 15 полное разочарование. У виджетов какие-то мелкие кнопочки кругом — мишура одна. Поменял тему, из стандартной поставки, все разлезлось. Потом плазма упала (да да именно так).
                              И тут я понял. Все что есть хорошего в KDE это заслуга Qt. Все эти красявости, прозрачности, быстрая работа и спец эффекты — это все Qt. KDE же написан отвратно. Плохая идеалогия интерфейса засвляет делять кучи ненужных кликов. Сбоящие тулзы и плагины и т.д. и т.п. Вот так вот взяв замечательный тулкит, не означает что у программиста руки УЖЕ растут правильно.
                                –4
                                предлагаю Вам почти универсальный совет по выбору проектов для проверки

                                1 взять список всех файлов из distfiles.gentoo.org/distfiles/ (не открывать!)
                                2 оставить только последние версии пакетов
                                3 отсортировать по размеру вниз
                                4 принять jj равно 1
                                5 взять jj-й елемент из списка
                                6 посмотреть соотвествует ли он следующим условиям
                                6.1 написан на С/С++
                                6.2 нужно ли вашей компании его протестировать (еще раз)?
                                7 увеличить значение jj на 1
                                8 перейти к номеру 5
                                  0
                                  Я тут переваривал Вашу статью, смотрел OpenC++ и другие парсеры, способные пережевать С++; разбирал работы и тезисы по статическим анализаторам. Конкретно парсеры — что-то вроде моего давнего хобби, что может быть понятно из вопроса выше. Как бы то ни было, Вас действительно часто упоминают специалисты в контексте сравнения с Coverity.

                                  Понимаю, что это старый и скучный вопрос. Однако, хочу вам представить одно давнее мое наблюдение: в России и близлежащих странах разработчики гораздо чаще пользуются Windows в работе в силу исторических причин. Здесь и первые программы писали в Студии еще шестой, и в университетах стояли еще пиратские версии софта, и многое другое… *никсы появились позже, и выглядели как эдакое маргинальное и нишевое веяние. И, конечно, Ваша цель — корпоративные заказчики, в мире которых десктопная винда может доминировать. Это то, как, насколько понимаю, Вы это видите.

                                  Однако, обратите внимание, что в наши дни правят не десктопы, а серверы. А в серверных правят Red Hat'ы и Debian'ы, которыми заправляют, очевидно совершенно другого рода люди. И ваша потенциальная целевая аудитория — профессиональные айтишные продуктовые компании. В таких местах интересные и полезные продукты выбирают айтишники, в эпоху Интернета и серверов привыкшие в работе с *никсами.

                                  Скажем, можно ли настроить PVS-Studio автоматической проверки кода на build-сервере? Который с очень высокой вероятностью работает на Debian/Red Hat? Я не знаю. Просто потому, что не имел возможности проверить: моя работа в различных продуктовых Интернет-компаниях (коих сейчас едва ли не больше, чем десктопных) подразумевает работу с Юниксом, пренебрежение которым означает только одно — соответствующий продукт я, старший разработчик, рекомендовать для покупки не могу. Мы просто не сможем его в наших онлайн-играх, онлайн-сервисах и на серверах использовать!

                                  Мне симпатичны и интересны Ваши усилия, Вы много правильного делаете для продвижения. Более того, Ваш продукт по сути своей не завязан на конкретную платформу. Я не знаю Вашего кода, но парсер, построение абстрактного дерева и последующий анализ более-менее стандартизированного языка — они не завязаны на платформу совершенно точно. А вот, эм, сердца разработчиков совершенно точно вам либо достанутся либо нет в зависимости от поддержки платформ.
                                    0
                                    Я не согласен с таким видением ситуации. Но обсуждать эту тему не интересно и не хочется. Замечу только, по поводу ощущения, что у нас Windows используется чаще. Может и чаще, но покупают в основном американцы и европейцы, а вовсе не из стран бывшего СССР. Так что всё нормально у них там с Windows.

                                    Скажем, можно ли настроить PVS-Studio автоматической проверки кода на build-сервере?
                                    Всё можно. Мы готовы доработать наш продукт для конкретных задач заказчика (его компилятора, ОС, редактора, системы сборки). Но только очереди из потенциальных желающих мы не видим. Зато тихо, спокойно и хорошо приобретают и продлевают PVS-Studio под Windows.
                                      0
                                      Может быть, вам виднее, я ни в коем случае не настаиваю и понимаю, что вопрос, скажем так, далеко не первичный.

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

                                      Но, повторюсь, вам виднее.
                                        0
                                        Зато тихо, спокойно и хорошо приобретают и продлевают PVS-Studio под Windows.
                                        Это все понятно. Но вот вы еще в 2012 г. пишете, что (цитата) возможно в будущем в дистрибутиве будет идти версия, которая может работать сразу же под Wine из коробки.

                                        Поскорей бы. :-) Попробовал вот запустить 5.21 под вайном 1.6.2, не работает (про ошибки написал в саппорт).

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

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