LINUX.ORG.RU

PVS-Studio для Linux

 , , ,


0

5

Появилась версия анализатора PVS-Studio, работающая в GNU/Linux. До этого программа работала только в Windows.

PVS-Studio — это инструмент для выявления ошибок в исходном коде программ, написанных на С и C++. В случае интеграции с Visual Studio также возможна проверка проектов на C#.

PVS-Studio выполняет широкий спектр проверок кода, но наиболее удачно справляется с поиском опечаток и последствий неудачного Copy-Paste. Показательные примеры таких ошибок: V501, V517, V522, V523, V3001.

Хочу поблагодарить всех, кто принял участие в Beta-тестировании и отправлял нам свои отзывы. Эти отзывы действительно были крайне полезны. Спасибо!

Пакеты PVS-Studio в форматах deb, rpm и tgz доступны для скачивания на официальном сайте.

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

Обязательно сразу же прочитайте краткую инструкцию «как запустить PVS-Studio в Linux».

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

Доклад на конференции C++ CoreHard Autumn 2016 «Что пришлось тестировать и о чем узнать при подготовке Linux-версии PVS-Studio».

Про что доклад: большинство программистов плохо представляют, что означает создание PVS-Studio для Linux. Многие думают, что вся сложность заключается в портировании кода, однако это очень далеко от истины: портировать код очень просто, но это только 5% работы. Остальная работа скрыта от стороннего наблюдателя и состоит в решении многих инфраструктурных вопросов. Предлагаем заглянуть на кухню разработчиков анализатора PVS-Studio и узнать разные интересные нюансы их работы.

>>> Подробности

Ответ на: комментарий от i-rinat

А причём тут printf? Тут дело в том, что результат операций с 32-х битными операндами без приведения типа присваивается 64-х битному результату.

alman ★★★ ()
Ответ на: комментарий от vvviperrr

Всё верно говорите, только не эту ошибку обсуждаем.

ASM ★★ ()
Ответ на: комментарий от alman

А причём тут printf?

Я там увидел %i, который для int, а передавался туда int16_t.

Тут дело в том, что результат операций с 32-х битными операндами без приведения типа присваивается 64-х битному результату.

А там разве не ожидаемый результат?

Подправил код, чтобы -Wall ругалось на несоответствие типов, так видно, какой тип имеет выражение:

#include <stdio.h>
#include <inttypes.h>

void a(void) {
  uint32_t a = 10, b = 11;
  printf("%f", a - b);
}
void b(void) {
  uint8_t a = 10, b = 11;
  printf("%f", a - b);
}
int main(void) { a(); b(); return 0; }

q.c: In function ‘a’:
q.c:6:12: warning: format ‘%f’ expects argument of type ‘double’, but argument 2 has type ‘uint32_t {aka unsigned int}’ [-Wformat=]
   printf("%f", a - b);
            ^
q.c: In function ‘b’:
q.c:10:12: warning: format ‘%f’ expects argument of type ‘double’, but argument 2 has type ‘int’ [-Wformat=]
   printf("%f", a - b);
            ^

Суть — в type promotion. uint32_t уже имеет такой же размер в битах, что и int, поэтому остаётся как есть. uint8_t повышается до int. Это в описании языка есть, разве нет?

i-rinat ★★★★★ ()
Последнее исправление: i-rinat (всего исправлений: 2)
Ответ на: комментарий от a1batross

Можно попробовать пропатчить внутренний глибц, а именно функцию time().

Это не мой путь.

andreyu ★★★★★ ()
Ответ на: комментарий от i-rinat

А там разве не ожидаемый результат?

Я бы ожидал получить -1, но судя по приведенному результату, получено UINT_MAX, что не есть правильно.

alman ★★★ ()
Ответ на: комментарий от i-rinat

Яж постил исправленный код:

#include <stdio.h>
#include <inttypes.h>

void a(void) {
  uint32_t a=10,b=11;
  int64_t c;
  c=(a-b);
  printf("C: %li\n",(long int)c);
}
void b(void) {
  uint8_t a=10,b=11;
  int16_t c;
  c=(a-b);
  printf("C: %i\n",c);
}

int main(void) { a(); b(); return 0; }
ASM ★★ ()
Ответ на: комментарий от ASM

Яж постил исправленный код

Посмотри на формат в printf. Я его специально испортил, чтобы GCC написал тип параметра в предупреждениях.

i-rinat ★★★★★ ()
Ответ на: комментарий от alman

Я бы ожидал получить -1

с какого перепуга? результат двух uint32 есть uint32. проблема в том, что в printf неверные спецификаторы, захардкоженные под встроенные типы.

vvviperrr ★★★★★ ()
Ответ на: комментарий от alman

Я бы ожидал получить -1,

Вычитаются беззнаковые числа, для которых явно описано поведение при переполнении — они «проворачиваются». Потом 32-битное беззнаковое расширяется до знакового 64-битного, которое может вместить это число.

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

i-rinat ★★★★★ ()
Ответ на: комментарий от i-rinat

Посмотри на формат в printf. Я его специально испортил, чтобы GCC написал тип параметра в предупреждениях.

У нас какбы типизированный язык, и так известно какие типы передаём в printf и какие ожидаем получить, если пишем %li или PRId64, как правильно заметил vvviperrr .

ASM ★★ ()
Ответ на: комментарий от i-rinat

Так разве анализатор не для того нужен, чтобы ошибки программиста отлавливать?

anonymous ()
Ответ на: комментарий от ASM

Тут и clang ругнется:

$ gcc tmp/t.cpp
tmp/t.cpp:10:24: warning: format specifies type 'long' but the argument has type 'int64_t' (aka 'long long') [-Wformat]
    printf("C: %li\n", c);
               ~~~     ^
               %lli
1 warning generated.

Или вы про разницу a и b, где b > a?

andreyu ★★★★★ ()
Ответ на: комментарий от Sunderland93

Тут уже написали, что Coverity предоставляет опенсорс-проектам бесплатный сервис проверки? Наверное, написали. Ну ничего, я тоже напишу: Coverity предоставляет опенсорс-проектам бесплатный сервис проверки.

Ceiling_QB ★★★★ ()
Ответ на: комментарий от anonymous

чтобы ошибки программиста отлавливать

V0041: Ваша программа что-то делает. Это источник ошибок. Советуем изменить программу так, чтобы она ничего не делала.

А если серьёзно, то что тут отлавливать? Расширение типов? Расширение со сменой знака?

i-rinat ★★★★★ ()
Ответ на: комментарий от i-rinat

Вас не смущает что один и тот же код выполняется по разному, если собрать под x86 и x64? Или то, что результат иной при увеличении типов в 4 раза?

ASM ★★ ()
Ответ на: комментарий от ASM

и так известно какие типы

Судя по тому, что ты вопрос задал, не известно. Твой пример о том, что вычитая два uint32_t, получаем unsigned int, а вычитая два uint8_t, получаем int. А совсем не про printf. Мой пример это наглядно показывает, тогда как в твоём это скрыто.

i-rinat ★★★★★ ()
Ответ на: комментарий от i-rinat

Как минимум, отлавливать, что операция двух известных на этапе беззнаковых компиляции чисел дает отрицательный результат.

anonymous ()
Ответ на: комментарий от Ceiling_QB

Ну ничего, я тоже напишу: Coverity предоставляет опенсорс-проектам бесплатный сервис проверки

Ну не все же в опенсорс пишут.

fornlr ★★★★★ ()
Ответ на: комментарий от ASM

Вас не смущает что один и тот же код выполняется по разному, если собрать под x86 и x64?

Это потому что ты не используешь PRId64 и PRId16 в формате printf. Если их использовать, будет одинаковый результат и там и тут. Ты же в курсе, что ты в «стек» пихаешь 64-битное число, а забираешь 32-битное?

Или то, что результат иной при увеличении типов в 4 раза?

Меня это не смущает, это правила языка Си. Я учил его не по книжке, а по кусочкам то там, то тут. Поэтому у меня нет ощущения «да знаю я всё», которое бывает у студентов после чтения методички. Это ощущение опасное, оно приводит вот к таким недоразумениям.

i-rinat ★★★★★ ()
Ответ на: комментарий от i-rinat

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

ASM ★★ ()
Ответ на: комментарий от fornlr

Просто, его вопрос намекал на то, что Coverity не «помог выявить несколько тысяч ошибок в опенсорс-ПО», а это неправда.

Ceiling_QB ★★★★ ()
Ответ на: комментарий от i-rinat

Пожалуй с Вами соглашусь:

sh-4.2$ cat main.c 
#include <stdio.h>
#include <inttypes.h>

void a(void) {
  uint32_t a=10,b=11;
  int64_t c;
  c=(a-b);
  printf("C: %"PRIi64"\n",c);
}
void b(void) {
  uint8_t a=10,b=11;
  int16_t c;
  c=(a-b);
  printf("C: %"PRIi16"\n",c);
}

int main(void) { a(); b(); return 0; }

sh-4.2$ gcc-6.2.0 -m32 -Wall -Wextra -Wpedantic main.c && ./a.out
C: 4294967295
C: -1

Но потенциальной проблемы это не отменяет.

На заметку: использование PRIi64 конечно правильно, но код получается уж крайне ублюдочный. ИМХО.

ASM ★★ ()
Последнее исправление: ASM (всего исправлений: 1)
Ответ на: комментарий от ASM

Или то, что результат иной при увеличении типов в 4 раза

если для тебя такое поведение новость - почитай про type promotion

vvviperrr ★★★★★ ()
Ответ на: комментарий от vvviperrr

если для тебя такое поведение новость - почитай про type promotion

Вы так говорите, будто анализаторы ненужны.

ASM ★★ ()
Ответ на: комментарий от ASM

отнюдь. но пользование анализатором не гарантирует 100% защиты от ошибок. отсюда мне и неясен твой пример.

Мой пример показывает, что никакие опции компилятора, никакие анализаторы не могут указать на потенциальную проблему

а кто утверждал обратное?

vvviperrr ★★★★★ ()
Ответ на: комментарий от MuZHiK-2

Его нельзя купить, а можно только арендовать.

А с Coverity (не для опенсoрса) как? Они разве продают «бессрочные версии»? Да и цена, насколько я знаю, «немного» побольше.

DarkEld3r ★★★★★ ()
Последнее исправление: DarkEld3r (всего исправлений: 1)
Ответ на: комментарий от vvviperrr

Разработчики анализатора представили свой продукт. Я кинул им пример кода, который содержит потенциальную ошибку, убедился что их анализатор эту ошибку не поймает. А вы в свою очередь набросились на меня за мою криворукость, из-за двух ошибок, которые я допустил в примере. Обе ошибки я признал и код поправил.

Вы до сих пор продолжаете со мной разговаривать, Вы хотите донести до меня что-то ещё?

ASM ★★ ()
Ответ на: комментарий от env

Ничего интересного в нем нет. Работы там на 5 минут. Смотри в удаленных.

anonymous ()
Ответ на: комментарий от andreyu

Путь — впустую работать для кого-то не получив из этого ровным счётом ничего? Ок.

a1batross ★★★★★ ()
Ответ на: комментарий от ASM

убедился что их анализатор эту ошибку не поймает

Анализатор на строке «printf(„C: %li\n“, c);» выдаёт: V576 Incorrect format. Consider checking the second actual argument of the 'printf' function. The actual argument equals '4294967295'.

vvviperrr ★★★★★ ()

А где чувак по имени mandala. Ну тот, который за «13 сребренников» защищал ПиВаС-Студио.

anonymous ()
Ответ на: комментарий от vvviperrr

Ответ протух, надо тестировать на этом:

#include <stdio.h>
#include <inttypes.h>

void a(void) {
  uint32_t a=10,b=11;
  int64_t c;
  c=(a-b);
  printf("C: %"PRIi64"\n",c);
}
void b(void) {
  uint8_t a=10,b=11;
  int16_t c;
  c=(a-b);
  printf("C: %"PRIi16"\n",c);
}

int main(void) { a(); b(); return 0; }

Ошибку вида:

 if (a=3)
ловят все

Ошибку вида:

 int32_t a;
 b=a<<33;
тоже ловят все.

Чем моя хуже?

ASM ★★ ()
Последнее исправление: ASM (всего исправлений: 1)
Ответ на: комментарий от ASM

в упор не понимаю, где ты тут увидел ошибку? тебе не нравится, что результаты разные? тебе уже 2 человека ответили, есть такая вещь - type promotion. в чем ошибка то? в стандарте?

vvviperrr ★★★★★ ()
Последнее исправление: vvviperrr (всего исправлений: 1)
Ответ на: комментарий от Aprel

Шикарная новость!

А ваша компания сколько экземпляров закупила, если не секрет? С какими аналогами сравнивали?

anonymous ()
Ответ на: комментарий от vvviperrr

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

В том числе он это может успешно получить на типах другой размерности.

ASM ★★ ()
Последнее исправление: ASM (всего исправлений: 1)
Ответ на: комментарий от a1batross

Путь — впустую работать для кого-то не получив из этого ровным счётом ничего? Ок.

Вы про бета-тестинг? Да, обидно. Но страдать из-за этого не стоит.

andreyu ★★★★★ ()
Ответ на: комментарий от ASM

в языке си операции не всегда проходят очевидным для «человека» способом. таких примеров куча. в данном примере нет ошибки, т.к стандарт четко регламентирует работу над типами меньше int.

vvviperrr ★★★★★ ()
Ответ на: комментарий от a1batross

А зачем страдать?

А я и не предлагал страдать.

Разве это не весело?

Понятия не имею.

andreyu ★★★★★ ()
Ответ на: комментарий от ASM

Если честно, я не уловил суть примера.

А жаль. Подобный код у миллионов людей приводит к ошибкам:

<режим зануды>Понятно, что для того, кто задаёт вопрос - всё понятно. А вот тот кто слышит - может слышать другое или у него может быть несколько вариантов интерпретации. Задать вопрос - это тоже искусство.</режим зануды>

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

Andrey_Karpov_2009 ()
Ответ на: комментарий от andreyu

Ты предполагал страдание. А я вот удивляюсь, откуда и, главное, зачем?

a1batross ★★★★★ ()
Ответ на: комментарий от vvviperrr

Стандарт все регламентирует. Анализаторы не нужны?

anonymous ()
Ответ на: комментарий от vvviperrr

В if(a=3) тоже нет ошибки. Там где есть ошибка компилятор выдаст предупреждение.

Мы тут анализатор обсуждаем, который должен искать ошибки в коде, код который пишут люди (часто с недостаточным багажём знаний)? Или тема уже сменилась, а я не заметил?

ASM ★★ ()
Ответ на: комментарий от Andrey_Karpov_2009

Я ни в коем разе не делаю выводов о качестве Вашего продукта. И не хочу Вас как-то унизить. Считайте, что это моя конструктивная критика. Делать выводы о Вашей конторе я буду по факту того, выявляется ли подобная ошибока в следующих версиях.

ASM ★★ ()
Ответ на: комментарий от ASM

а какого вида предупреждения ты хочешь для своего примера? в каждой операции с типами меньше int кидать варнинг - внимание, продвижение типов?

на мой взгляд - для статического анализатора тут нечего анализировать.

vvviperrr ★★★★★ ()
Последнее исправление: vvviperrr (всего исправлений: 1)
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.