PVS-Studio vs Chromium

    PVS-Studio VS Chromium
    В этот раз победу одержало добро. А вернее, исходные коды проекта Chromium. Chromium — один из лучших проектов, который мы проверяли с помощью PVS-Studio.

    Chromium — веб-браузер с открытым исходным кодом, разработанный компанией Google и предназначенный для предоставления пользователям быстрого и безопасного доступа в Интернет. На основе Chromium создаётся браузер Google Chrome. При этом Chromium является предварительной версией Google Chrome, а также ряда других альтернативных веб-обозревателей.

    С точки зрения программиста Chromium — это решение (solution), состоящее из 473 проектов. Общий объем исходного кода на языке C/C++ составляет около 460 мегабайт. Количество строк посчитать затрудняюсь.

    В эти 460 мегабайт входит большое количество различных библиотек. Если их отделить, то останется около 155 мегабайт. Существенно меньше, но всё равно много. Тем более всё относительно. Многие из этих библиотек сделаны разработчиками Chromium в рамках задачи создания Chromium. Хотя такие библиотеки живут сами по себе, их можно вполне отнести к самому браузеру.

    Chromium стал самым большим и самым качественным проектом, с которым я познакомился в ходе испытаний PVS-Studio. При работе с проектом Chromium было на самом деле не очень понятно, кто кого проверяет. Мы нашли и исправили в PVS-Studio несколько ошибок, связанных с анализом Си++ файлов и с поддержкой специфичной структуры проекта.

    О качестве исходного кода Chromium говорит множество моментов и используемых приемов. Например, большинство программистов для определения количества элементов в массиве используют следующую конструкцию:
    int XX[] = { 1, 2, 3, 4 };
    size_t N = sizeof(XX) / sizeof(XX[0]);

    Обычно это оформляют в макрос следующего вида:
    #define count_of(arg) (sizeof(arg) / sizeof(arg[0]))

    Это вполне работоспособный и полезный макрос. Я и сам, если честно, всегда именно таким макросом и пользовался. Однако он может послужить причиной ошибки, так как ему случайно можно подсунуть простой указатель, и он не будет возражать по этому поводу. Поясню на примере:
    void Test(int C[3])
    {
      int A[3];
      int *B = Foo();
      size_t x = count_of( A ); // Ok
      x = count_of( B ); // Error
      x = count_of( C ); // Error
    }

    Конструкция count_of(A) работает корректно и возвращает количество элементов в массиве A, равное трём.

    Но если случайно применить count_of() к указателю, то результатом будет малоосмысленное значение. Беда в том, что макрос никак не предупредит программиста о странной конструкции вида count_of(B). Происходит деление размера указателя на размер элемента массива. Подобная ситуация кажется надуманной и искусственной, но я встречал её в реальных приложениях. В качестве примера приведу код из проекта Miranda IM:
    #define SIZEOF(X) (sizeof(X)/sizeof(X[0]))
    int Cache_GetLineText(..., LPTSTR text, int text_size, ...)
    {
      ...
      tmi.printDateTime(pdnce->hTimeZone, _T("t"), text, SIZEOF(text), 0);
      ...
    }

    Так что подобные ошибки вполне имеют место быть и хорошо бы иметь возможность защититься от них. Ещё проще ошибиться, если попробовать вычислить размер массива, переданного в качестве аргумента:
    void Test(int C[3])
    {
      x = count_of( C ); // Error
    }

    Согласно стандарту языка Си++, переменная 'C' представляет собой обыкновенный указатель, а вовсе не массив. В результате в программах нередко можно встретить обработку только части переданного массива.
    Раз уж зашла речь о таких ошибках, подскажу приём, как же можно узнать размер переданного массива. Для этого необходимо передать его по ссылке:
    void Test(int (&C)[3])
    {
      x = count_of( C ); // Ok
    }

    Теперь результатом выражения count_of( C ) будет значение 3.

    Вернемся к Chromium. В нем используется такой макрос, который позволяет избежать описанных выше ошибок. Вот его реализация:
    template <typename T, size_t N>
    char (&ArraySizeHelper(T (&array)[N]))[N];
    #define arraysize(array) (sizeof(ArraySizeHelper(array)))

    Идея этого магического заклинания в следующем. Шаблонная функция ArraySizeHelper принимает на вход массив произвольного типа длиной N. При этом функция возвращает массив из элементов 'char' длиной N. Реализация функции отсутствует, так как она не нужна. Для оператора sizeof() достаточно только объявления функции ArraySizeHelper. В макросе 'arraysize' вычисляется размер возвращаемого функцией ArraySizeHelper массива байт. Этот размер и есть количество элементов в массиве, длину которого мы хотим вычислить.

    Если у вас опухла голова, то можете поверить мне на слово, что это работает. Причем работает гораздо лучше, чем рассмотренный ранее макрос 'count_of()'. Так как функция ArraySizeHelper принимает массив по ссылке, то в неё невозможно передать простой указатель. Напишем тестовый код:
    template <typename T, size_t N>
    char (&ArraySizeHelper(T (&array)[N]))[N];
    #define arraysize(array) (sizeof(ArraySizeHelper(array)))
    
    void Test(int C[3])
    {
      int A[3];
      int *B = Foo();
      size_t x = arraysize( A ); // Ok
      x = arraysize( B ); // Ошибка компиляции
      x = arraysize( C ); // Ошибка компиляции
    }

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

    Приведу еще один пример, совершенно другого плана, но также говорящий о качестве кода.
    if (!file_util::Delete(db_name, false) &&
        !file_util::Delete(db_name, false)) {
      // Try to delete twice. If we can't, fail.
      LOG(ERROR) << "unable to delete old TopSites file";
      return false;
    }

    Этот код может показаться многим программистам странным. Какой смысл два раза пробовать удалить файл? А смысл есть. Тот, кто его писал, достиг просветления и суть бытия программ. Файл однозначно удаляется или не удаляется только в учебниках и абстрактном мире. В реальной системе бывает так, что файл только что нельзя было удалить и мгновением позже — можно. Причиной тому могут быть антивирусы, вирусы, системы контроля версий, и бог весть что ещё. Программисты часто не задумываются о подобных ситуациях. Они мыслят так, раз не удалость удалить файл, то значит и не получится. Но, если хочется сделать хорошо и не мусорить в каталогах, нужно учитывать эти посторонние воздействия. Я сталкивался с ровно такой же ситуацией, когда файл не удаляется один раз на 1000 запусков. И решение было ровно таким же. Ну, разве что я ещё на всякий случай Sleep(0) вставил посередине.

    А что же проверка с помощью PVS-Studio? Код Chromium, пожалуй, самый качественный код, который я видел. Это подтверждается очень низкой плотностью ошибок, которые мы смогли найти. Если брать количественно, то ошибок конечно много. А вот если поделить это количество ошибок на объем кода, то, получается, что их практически нет. Какие это ошибки? Самые обыкновенные. Несколько примеров:
    V512 A call of the 'memset' function will lead to underflow of the buffer '(exploded)'. platform time_win.cc 116

    void NaCl::Time::Explode(bool is_local, Exploded* exploded) const {
      ...
      ZeroMemory(exploded, sizeof(exploded));
      ...
    }

    Опечатки делают все. Здесь просто забыли звёздочку. Должно было быть: sizeof(*exploded).
    V502  Perhaps the '?:' operator works in a different way than it was expected. The '?:' operator has a lower priority than the '-' operator.  views  custom_frame_view.cc  400

    static const int kClientEdgeThickness;
    int height() const;
    bool ShouldShowClientEdge() const;
    
    void CustomFrameView::PaintMaximizedFrameBorder(gfx::Canvas* canvas) {
      ...
      int edge_height = titlebar_bottom->height() -
                        ShouldShowClientEdge() ? kClientEdgeThickness : 0;
      ...
    }

    Коварный оператор "?:" имеет более низкий приоритет, чем вычитание. Здесь нужны дополнительные скобочки:
    int edge_height = titlebar_bottom->height() -
                      (ShouldShowClientEdge() ? kClientEdgeThickness : 0);

    Проверка, которая не имеет смысла.
    V547  Expression 'count < 0' is always false. Unsigned type value is never < 0.  ncdecode_tablegen  ncdecode_tablegen.c  197

    static void CharAdvance(char** buffer, size_t* buffer_size, size_t count) {
      if (count < 0) {
        NaClFatal("Unable to advance buffer by count!");
      } else {
      ...
    }

    Условие «count < 0» всегда ложно. Защита не сработает и потенциально какой-то буфер может быть переполнен. Это, кстати, пример, как статические анализаторы могут быть использованы для поиска уязвимостей. Злоумышленник может быстро выделить для себя те участки кода, которые содержат ошибки для их дальнейшего, более внимательного анализа. А вот еще один фрагмент кода, который может быть интересен с точки зрения безопасности:
    V511  The sizeof() operator returns size of the pointer, and not of the array, in 'sizeof (salt)' expression.  common  visitedlink_common.cc  84

    void MD5Update(MD5Context* context, const void* buf, size_t len);
    
    VisitedLinkCommon::Fingerprint VisitedLinkCommon::ComputeURLFingerprint(
      ...
     const uint8 salt[LINK_SALT_LENGTH])
    {
      ...
      MD5Update(&ctx, salt, sizeof(salt));
      ...
    }

    Функция MD5Update() обработает столько байт, сколько занимает указатель. Не потенциальная ли дыра в плане шифрования данных? Я не знаю есть ли во всём этом какая-то опасность или нет. Но с точки зрения злоумышленников — это однозначно интересное место для более подробного изучения.

    Корректный код должен выглядеть так:
    MD5Update(&ctx, salt, sizeof(salt[0]) * LINK_SALT_LENGTH);

    Или вот так:
    VisitedLinkCommon::Fingerprint VisitedLinkCommon::ComputeURLFingerprint(
      ...
     const uint8 (&salt)[LINK_SALT_LENGTH])
    {
      ...
      MD5Update(&ctx, salt, sizeof(salt));
      ...
    }

    Еще пример про опечатку:
    V501  There are identical sub-expressions 'host != buzz::XmlConstants::str_empty ()' to the left and to the right of the '&&' operator.  chromoting_jingle_glue  iq_request.cc  248

    void JingleInfoRequest::OnResponse(const buzz::XmlElement* stanza) {
      ...
      std::string host = server->Attr(buzz::QN_JINGLE_INFO_HOST);
      std::string port_str = server->Attr(buzz::QN_JINGLE_INFO_UDP);
      if (host != buzz::STR_EMPTY && host != buzz::STR_EMPTY) {
      ...
    }

    На самом деле нужно проверить и переменную port_str:
    if (host != buzz::STR_EMPTY && port_str != buzz::STR_EMPTY) {

    Немного из классики:
    V530  The return value of function 'empty' is required to be utilized.  chrome_frame_npapi  np_proxy_service.cc  293

    bool NpProxyService::GetProxyValueJSONString(std::string* output) {
      DCHECK(output);
      output->empty();
      ...
    }

    Должно быть: output->clear();

    А вот даже есть и работа с нулевым указателем:
    V522  Dereferencing of the null pointer 'plugin_instance' might take place. Check the logical condition.  chrome_frame_npapi  chrome_frame_npapi.cc  517

    bool ChromeFrameNPAPI::Invoke(...)
    {
      ChromeFrameNPAPI* plugin_instance =
        ChromeFrameInstanceFromNPObject(header);
      if (!plugin_instance && (plugin_instance->automation_client_.get()))
        return false;
      ...  
    }

    Ещё один пример проверки, которая никогда не сработает:
    V547  Expression 'current_idle_time < 0' is always false. Unsigned type value is never < 0.  browser  idle_win.cc  23

    IdleState CalculateIdleState(unsigned int idle_threshold) {
      ...
      DWORD current_idle_time = 0;
      ...
      // Will go -ve if we have been idle for a long time (2gb seconds).
      if (current_idle_time < 0)
        current_idle_time = INT_MAX;
      ...
    }

    Пожалуй, следует остановиться. Я могу продолжать дальше, но это становится скучно. И это ведь только то, что относится к самому Chromium. А ведь есть ещё тесты с ошибками наподобие этой:

    V554  Incorrect use of auto_ptr. The memory allocated with 'new []' will be cleaned using 'delete'.  interactive_ui_tests  accessibility_win_browsertest.cc  306


    void AccessibleChecker::CheckAccessibleChildren(IAccessible* parent) {
      ...
      auto_ptr<VARIANT> child_array(new VARIANT[child_count]);
      ...
    }

    И огромное количество библиотек, на которых и строится Chromium. Причем размер библиотек значительно больше, чем размер самого Chromium. А там тоже множество интересных мест в коде. Понятно, что возможно код с ошибками нигде не используется, но ошибка от этого не перестает быть ошибкой. Один первый попавшийся пример (библиотка ICU):
    V547 Expression '* string != 0 || * string != '_'' is always true. Probably the '&&' operator should be used here.  icui18n ucol_sit.cpp 242

    U_CDECL_BEGIN static const char* U_CALLCONV
    _processVariableTop(...)
    {
      ...
      if(i == locElementCapacity && (*string != 0 || *string != '_')) {
        *status = U_BUFFER_OVERFLOW_ERROR;
      }
      ...
    }

    Выражение "(*string != 0 || *string != '_')" всегда истинно. Видимо должно быть: (*string == 0 || *string == '_').

    Вывод


    PVS-Studio потерпел поражение. Код Chromium — один из лучших кодов, которые мы анализировали. Мы практически ничего не нашли в Chromium. Вернее, мы нашли очень даже много ошибок, и в этой статье мы показали только небольшую их часть. Но если учесть, что все эти ошибки размазаны по исходному коду объемом 460 мегабайт, то, получается, что их практически нет.

    P.S.

    Отвечаю на вопрос: сообщим ли мы разработчикам Chromium о найденных ошибках? Нет, не сообщим. Это очень большой объем работы, который мы не можем позволить себе выполнять бесплатно. Проверка Chromium это совсем не проверка Miranda IM или проверка Ultimate Toolbox. Это большая работа, необходимо внимательно изучить все сообщения и разобраться действительно ли это ошибка или нет. Для этого необходимо ориентироваться в проекте. Мы перешлём перевод этой статьи разработчикам Chromium, и если им будет интересно, они смогут сами выполнить анализ проекта и проанализировать все диагностические сообщения. Да, для этого им будет необходимо приобрести PVS-Studio. Но любой отдел Google легко может себе это позволить.

    P.P.S.

    Нет, мы не жадные. Мы готовы помогать открытым проектам, наподобие FlylinkDC++. Но это разные вещи.
    PVS-Studio
    Static Code Analysis for C, C++, C# and Java

    Comments 64

      +16
      А ведь Google выдаёт деньги за баги найденные в Chrome, решили сорвать банк? ;)
      Хотя позиция ваша касательно этого вопроса мне нравится, желаю вам большого заказа от Google
        +8
        Ошибка в коде не всегда есть баг (ИМХО). Этот код может либо не вызываться никогда, либо выдавать правильные результаты на тех наборах данных, которые в него подаются. Для меня баг, это тройка из: шагов для воспроизведения, ожидаемого результата и фактического результата, где ожидаемый и фактический результат расходятся. Зная ошибку в годе совершенно не факт, что так уж просто заставить ее выстрелить.
          +3
          >> Ошибка в коде не всегда есть баг

          Это называется уязвимость. Когда вы читаете в новостях «обнаружена уязвимость» — это вот значит, что кто-то нашел ПОТЕНЦИАЛЬНУЮ ошибку.
            +4
            Нет, это значит, что ожидаемый и фактический результат расходятся и для этого есть шаги для воспроизведения.
              +1
              Не совсем. Когда я читаю: «обнаружена уязвимость», то это «кто-то нашел ПОТЕНЦИАЛЬНУЮ ошибку.» Когда я читаю: «выпущен exploit», то это кто-то нашел шаги для воспроизведения и даже их автоматизировал.
              0
              Да, согласен с вами, то что накопали авторы статьи это уязвимости. Причем опять же, не факт, что все их можно эксплуатировать.
            0
            Согласен — хороший статический анализатор кода стоит покупки.

            Раз мы говорим о PVS — будет ли выпущена command-line версия для linux? Будет ли PVS выпущена в качестве библиотеки и таким образом появится возможность написать плагины для других IDE (e.g. Eclipse)?
              0
              судя по ихнему сайту — любая глупость за ваши деньги
              сами они даже ветку под линь развивать не собираются
                +2
                Вы лично готовы купить Линукс-версию?
                  +1
                  Если Linux версия будет находить баги в нашем c/c++ коде то да. Я поговорю с манагером и скорее всего купят продукт, копий десять. С покупкой полезного софта (по разумной цене) никогда проблем в нашей компании не было.
                    +2
                    10 копий — это цена почти Site License. Напишите мне на e-mail и мы обсудим варианты.
                      0
                      Если Linux версия будет находить баги в нашем c/c++ коде
                      А вы заметите свои баги за багами gcc?
                        0
                        Прошу поговорить с манагером. :)
                        PVS-Studio для Linux.
                      0
                      Свершилось: PVS-Studio для Linux.
                    +41
                    Да, для этого им будет необходимо приобрести PVS-Studio.

                    Вот так они и купят разработку или вашу организацию целиком. :)

                      +70
                      — Нам нужена PVS-Studio!
                      — Сделано!
                      — Какая версия?
                      — Версия?!11
                      0
                      Не совсем понял про двойное удаление файла: получается некая двусмысленность, если в итоге файл удалится на второй попытке, а при этом в лог пойдет запись о том, что удалить нельзя.
                        +4
                        Не вижу двусмысленности. Если 2 раза не удалось удалить, то запишем сообщение в лог.
                          0
                          Ну так если один раз удалилось, то тоже пишется в лог, нет?
                            0
                            То есть как, одно удаление завалилось, другое — нет => условие по-любому будет истинным => будет запись в лог.
                              +2
                              false && true => false
                                +6
                                Во я даю, решил чет, что условие по false выполняется, приплыли
                              +2
                              if (!file_util::Delete(db_name, false) &&
                              !file_util::Delete(db_name, false)) {

                              Читаю код вслух. :)

                              !file_util::Delete(db_name, false) — Если нам не удалось удалить файл

                              && — И при этом

                              !file_util::Delete(db_name, false) — нам опять не удалось удалить файл

                              То поместим сообщение в лог.
                                0
                                Охтыж блин, ну я и затупил, мозг чет сплавился в далекие страны.
                          +10
                          if (!file_util::Delete(db_name, false) &&
                          !file_util::Delete(db_name, false))

                          Очень странное представление о красивом коде. Если файл не удалился, но есть подозрение что он может удалится позже — нужно создать очередь для отложенного удаления.
                            +2
                            зато так быстрее.
                              +8
                              Это, к стати, вполне может быть не красивым кодом, а грязным хаком, написанным из-за осознания глючности метода file_util::Delete или из-за знания того, что этот файл может в данный момент читаться другим потоком самого Хромиума и нежеланием с этим потоком общаться на предмет ожидания освобождения ресурса.
                              +1
                              А всего в багтрекере Хромиума на данный момент 27000 багов. Солидное число. Хотя и проект, конечно, огромный.
                                +6
                                Это нормально для крупного проекта. Многие баг-репорты содержат либо недостаточно информации, необходимой для отладки, либо сомнительный фич-реквест. Такие отчеты не удаляют, а висят в баг-трекерах годами.
                                  +1
                                  … а ещё дубликаты
                                  0
                                    0
                                    Сорри, перепутал кнопки :)
                                  0
                                  Планируется ли версия под Linux?
                                  Тот же Гугл имеет несравнимо бОльшую кодовую базу под Линуксом.
                                    +2
                                    Да, если хватит здоровья и повезёт. А пока нет, по ряду причин:

                                    1) Это большая сложная задача. Подробнее в FAQ: "А
                                    что, у вас только под Windows версия? Сделайте под Linux, это же просто! Какая разница, в какой операционной системе текстовые файлы (с кодом) анализировать?
                                    "

                                    2) В Windows проще зарабатывать деньги. Не забывайте, что мы стартап, а не финансируемый отдел корпорации. Что заработали, то и потратили на развитие.
                                      –4
                                      2й аргумент совершенно неубедителен. Ваша программа же не для конечных пользователей (которые в большинстве сидят на Windows) рассчитана, а на разработчиков. А кроме прикладных программ для Windows есть огромный рынок Linux серверов, embedded и другого, где еще не всегда возможно использовать дебаггер и профайлер, как в Windows.
                                        0
                                        Вы пишите, что пользователей под Windows больше. Разработчиков для таких пользователей тоже больше, разумеется.

                                        Кстати вот Вы готовы купить линукс-версию pvs-studio?
                                          –5
                                          Ну вот возьмите большинство веб-сервисов. Большинство их используют из Windows, но это не означает, что разработчики используют Windows. Поддержка GCC, кстати, даст почти бесплатно еще и поддержку Mac OS X, с более платёжеспособной аудиторией (США).

                                          Сам купить не готов, я студент и крупными проектами на C++ не занимаюсь и таких денег не имею. Несколько раз после таких статей хотел пощупать демо (проанализировав какие-нибудь open source проекты), и каждый раз вспоминал, что оно win-only.
                                            +15
                                            Вот видите, Вы купить не готовы, но легко даете советы в какую сторону нам развивать наш бизнес…
                                              +2
                                              Я не давал советы и прекрасно понимаю, что распылять силы на несколько платформ небольшой компании может быть не выгодно. Просто я думаю, что Ваш в 2й аргумент написан не потому, что Вы исследовали рынок и пришли к такому выводу, а для того, чтобы оправдать недостаток продукта.
                                        +2
                                        Надо заметить, авторы Valgrind пошли наоборот: начали с Linux, а потом написали FAQ почему их не будет на Windows (слишком сложно, проще переписать с нуля)

                                        По опыту работы в кросс-платформенной системе тестирования (ThreadSanitizer) могу сказать что под Linux писать всё-таки проще: почти всё что нужно документировано, да ещё и с исходниками. А в потрохах Windows нередко чувствуешь себя слепым
                                        0
                                        Да, такая версия появилась: PVS-Studio для Linux.
                                        –2
                                        «подобные ошибки вполне имеют место быть»
                                        Нет такого выражения как «имеет место быть». «Имеет место».
                                          +1
                                          а что сразу или одно из двух?
                                            –1
                                            Что?
                                          +1
                                          При этом функция возвращает массив из элементов 'char' длиной N.

                                          Функция возвращает ссылку на массив.
                                            0
                                            Согласен. Неаккуратно написал.
                                            0
                                            А вы даете всем OSS проектам копии лицензий, или это выборочно? Просто я бы не отказался поанализировать вот этот проект. :)
                                              0
                                              Пост про это здесь.
                                                0
                                                Интересно как PVS-Studio отнесется к C# проекту.
                                                  0
                                                  PVS-Studio не работает с C# и откажется проверять решение, если в нём нет *.c, *.cpp файлов:
                                                  Files with C or C++ source code for analysis not found. If they are present, enable projects which were excluded from build in Configuration Manager.
                                              0
                                              На моём крупном проекте триальная версия PVS-Studio настолько сильно искажает результат (не показывает), что невозможно понять, есть ли какая-нибудь польза от неё вообще…
                                                +1
                                                Искажает результат — это какой-то очень сильный филологический оборот. Пишите нам в саппорт — разберемся и найдем все проблемы в вашем коде.
                                                +8
                                                А вы исходник PVS прогоняли через PVS?
                                                  +4
                                                  У нас ежедневно ночные билды проверяются. И иногда находим ошибки, разумеется.
                                                    +1
                                                    Например, совсем недавно сами в себе нашли это.
                                                  0
                                                  Насчет двойного удаление, зачем придумывать очередной хитрый механизм «Все гениальное — просто», и тут просто и без выдумки аля через «третью переменную».
                                                    +3
                                                    Надо сказать, частично причиной «качественности проекта Chromium» является то, что ощутимая часть его кода регулярно тестируется динамическими анализаторами: Valgrind, ThreadSanitizer, HeapChecker
                                                    build.chromium.org/p/chromium.memory/console
                                                    Но увы, они действительно не могут найти все ошибки.
                                                    И, к сожалению, Valgrind не работает на Windows (см. найденную Вами ошибку в time_win.cc)

                                                    «При работе с проектом Chromium было на самом деле не очень понятно, кто кого проверяет. Мы нашли и исправили в PVS-Studio несколько ошибок»
                                                    Точно, в вышеупомянутые динамические анализаторы тоже было зафайлено немало багов :)
                                                    А вот многие коммерческие анализаторы, вроде Intel Parallel Studio и Purify, весьма плохо работают с Chromium. Они не прошли стадию «непонятно кто кого проверяет»…
                                                      +2
                                                      я вот только не понял
                                                      как там моги оказаться проверки unsigned на меньше нуля
                                                      gcc это ворнингами же выдаёт
                                                        –1
                                                        > Количество строк посчитать затрудняюсь

                                                        find . -name \*.cc | xargs cat | wc -l

                                                        В любом нормальном шелле эта задача решается за несколько секунд. Конечно, решение не точное (например, хидеры не ищет), зато позволяет очень быстро и просто получить качественную оценку объёма кодовой базы.
                                                          0
                                                          Прошу сделать это и написать результат. Мне интересно иметь представление о количестве строк кода.
                                                            +1
                                                            Сделал так:

                                                            $ for EXT in cc c cpp h ; do files=`find . -name \*.${EXT}|wc -l`; rows=`find . -name \*.${EXT}|xargs cat|wc -l`; echo $EXT: $files files, $rows rows; done

                                                            cc: 8161 files, 3187779 rows
                                                            c: 5912 files, 3143894 rows
                                                            cpp: 8170 files, 2426530 rows
                                                            h: 22999 files, 3925234 rows


                                                            Итого: 45242 файла, 12683437 строк (12.5 М! Внушает!)
                                                              0
                                                              по-моему, вы посчитали пустые строки и строки-комментарии. Это не сильно ли искажает картину?
                                                                0
                                                                Принципиально — вряд ли.

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