Принципы работы статического анализатора кода pvs-studio

33
Принципы работы статического анализатора кода PVS- Studio Авторы: к.т.н. Евгений Рыжков, [email protected] к.ф.-м.н. Андрей Карпов, [email protected]

Upload: andrey-karpov

Post on 16-Feb-2017

43 views

Category:

Software


0 download

TRANSCRIPT

Page 1: Принципы работы статического анализатора кода PVS-Studio

Принципы работы статического анализатора

кода PVS-StudioАвторы:к.т.н. Евгений Рыжков, [email protected]к.ф.-м.н. Андрей Карпов, [email protected]

Page 2: Принципы работы статического анализатора кода PVS-Studio

ООО "СиПроВер" (www.viva64.com)• Занимаемся разработкой, продвижением и продажей

собственного программного продукта.• Офис: г. Тула, 200 км от Москвы.• Штат: 24 человека

Page 3: Принципы работы статического анализатора кода PVS-Studio

PVS-Studio• Более 320 диагностик для C, C++• Более 120 диагностик для C#• Windows• Linux• Плагин для Visual Studio• Быстрый старт (мониторинг компиляции)• SonarQube

Page 4: Принципы работы статического анализатора кода PVS-Studio

Наши достижения• Для рекламы мы проверяем открытые проекты. На данный момент мы

проверили около 270 проектов.

• Побочный эффект: нашли более 10000 ошибок в открытых проектах, не задаваясь такой целью.

• В среднем 40 ошибок на проект – вроде немного.

• Важно ещё раз подчеркнуть, что это побочный эффект. У нас нет цели найти как можно больше ошибок. Часто мы останавливаемся, когда нашли достаточное количество дефектов в проекте, чтобы написать статью.

• Вывод: легко проверять даже незнакомые проекты и находить в них ошибки.

Page 5: Принципы работы статического анализатора кода PVS-Studio

В начале, что мы НЕ ИСПОЛЬЗУЕМ

Page 6: Принципы работы статического анализатора кода PVS-Studio

Мы не используем математический аппарат грамматик• Анализатор работает на более высоком уровне• Анализируется дерево разбора• Для построения дерева мы опираемся на уже существующие

компоненты:• Внешний препроцессор• Библиотека OpenC++, которую мы дорабатываем с развитием C++ по

мере необходимости (собственно от OpenC++ уже ничего не осталось)• При работе с C# кодом мы опираемся на Roslyn

Page 7: Принципы работы статического анализатора кода PVS-Studio

Мы не используем методики доказательства правильности программ (program proof).• PVS-Studio не имеет ничего общего с Prototype Verification System

(PVS) http://pvs.csl.sri.com/• PVS-Studio сокращение от OOO "Program Verification Systems"

(ООО "Системы программной верификации")

Page 8: Принципы работы статического анализатора кода PVS-Studio

Мы не используем поиск подстрок (string matching) и регулярные выражения (regular expressions)

• Тупиковый путь• Подводит даже в простейших ситуациях• Пример: if (A+B == A+B)• A+B == B+A• A+(B) == (A)+B• ((A+B)) == A+B

• Более фатально: типы, размеры объектов, наследование, значения переменных и так далее

Page 9: Принципы работы статического анализатора кода PVS-Studio

Что МЫ используем

Детали анализа C++ и C# кода разнятся, но мы не будем делать в докладе уточнения.

Page 10: Принципы работы статического анализатора кода PVS-Studio

Pattern-based analysis• Сопоставление с шаблоном на основе дерева разбора• Применяется для поиска мест в исходном коде, которые похожи

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

Page 11: Принципы работы статического анализатора кода PVS-Studio

if ((*path)[0]->e->dest->loop_father != path->last()->e->....){ delete_jump_thread_path (path); e->aux = NULL; ei_next (&ei;);}else{ delete_jump_thread_path (path); e->aux = NULL; ei_next (&ei;);}

Простой случай: copy-paste

Проект GCC

V523 The 'then' statement is equivalent to the 'else' statement. tree-ssa-threadupdate.c 2596

Page 12: Принципы работы статического анализатора кода PVS-Studio

Средний случай: проверка не той переменной

public override Predicate JoinWith(Predicate other){ var right = other as PredicateNullness; if (other != null) { if (this.value == right.value) {

Проект CodeContracts

V3019 Possibly an incorrect variable is compared to null after type conversion using 'as' keyword. Check variables 'other', 'right'. CallerInvariant.cs 189

Page 13: Принципы работы статического анализатора кода PVS-Studio

Сложный случай: неудачный макрос

#define ICB2400_VPINFO_PORT_OFF(chan) \ (ICB2400_VPINFO_OFF + \ sizeof (isp_icb_2400_vpinfo_t) + \ (chan * ICB2400_VPOPT_WRITE_SIZE))

off += ICB2400_VPINFO_PORT_OFF(chan - 1);

V733 It is possible that macro expansion resulted in incorrect evaluation order. Check expression: chan - 1 * 20. isp.c 2301

Проект FreeBSD

Page 14: Принципы работы статического анализатора кода PVS-Studio

Type inference• Вывод типов на основе семантической модели программы

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

Page 15: Принципы работы статического анализатора кода PVS-Studio

Типы важны для выявления ошибокПроект Cocos2d-x

WCHAR *gai_strerrorW(int ecode);

#define gai_strerror gai_strerrorW

fprintf(stderr, "net_listen error for %s: %s", serv, gai_strerror(n)); V576 Incorrect format. Consider checking the fourth actual argument of the 'fprintf' function. The pointer to string of char type symbols is expected. ccconsole.cpp 341

Page 16: Принципы работы статического анализатора кода PVS-Studio

Типы важны для исключений

// volatile переменная присваивается сама себеvolatile int *ptr;....*ptr = *ptr; // Нет срабатывания V570

Page 17: Принципы работы статического анализатора кода PVS-Studio

Особенно важна информация о классах: например, иерархия наследования

class sg_throwable : public std::exception { .... };class sg_exception : public sg_throwable { .... };

if (!aInstall) { sg_exception("missing argument to scheduleToUpdate");}V596 The object was created but it is not being used. The 'throw' keyword could be missing: throw sg_exception(FOO); root.cxx 239

Проект FlightGear

Page 18: Принципы работы статического анализатора кода PVS-Studio

Symbolic execution• Символьное выполнение позволяет вычислять значения

переменных, которые могут приводить к ошибкам, производить проверку диапазонов (range checking) значений• Один из самых важных механизмов:

• Переполнения• Утечки памяти• Выход за границы массива• Нулевые указатели / ссылки• Бессмысленные условия• Деление на 0• И так далее

Page 19: Принципы работы статического анализатора кода PVS-Studio

Значения переменных: размер массива, индексыHandle<YieldTermStructure> md0Yts() { double q6mh[] = { 0.0001,0.0001,0.0001,0.0003,0.00055,0.0009,0.0014,0.0019, 0.0025,0.0031,0.00325,0.00313,0.0031,0.00307,0.00309, ........................................................ 0.02336,0.02407,0.0245 }; 60 элементов .... for(int i=0;i<10+18+37;i++) { i < 65 q6m.push_back( boost::shared_ptr<Quote>(new SimpleQuote(q6mh[i])));

Проект QuantLib

V557 Array overrun is possible. The value of 'i' index could reach 64. markovfunctional.cpp 176

Page 20: Принципы работы статического анализатора кода PVS-Studio

Значения переменных: использование условий для определения диапазона

std::string rangeTypeLabel(int idx){ const char* rangeTypeLabels[] = {"Self", "Touch", "Target"}; if (idx >= 0 && idx <= 3) return rangeTypeLabels[idx]; else return "Invalid";}

V557 Array overrun is possible. The value of 'idx' index could reach 3. esmtool labels.cpp 502

Проект OpenMW

Page 21: Принципы работы статического анализатора кода PVS-Studio

Значения функцийstatic inline size_t UnboxedTypeSize(JSValueType type){ switch (type) { ....... default: return 0; }}

Minstruction *loadUnboxedProperty(size_t offset, ....){ size_t index = offset / UnboxedTypeSize(unboxedType);

Проект Thunderbird

V609 Divide by zero. Denominator range [0..8]. ionbuilder.cpp 10922

Page 22: Принципы работы статического анализатора кода PVS-Studio

Значения переменных: указатели / ссылкиif (providerName == null){ ProviderNotFoundException e = new ProviderNotFoundException( providerName.ToString(), SessionStateCategory.CmdletProvider, "ProviderNotFound", SessionStateStrings.ProviderNotFound); throw e;V3080 Possible null dereference. Consider inspecting 'providerName'. System.Management.Automation SessionStateProviderAPIs.cs 1004

Проект PowerShell

Page 23: Принципы работы статического анализатора кода PVS-Studio

Method annotations• Аннотирование методов предоставляет больше информации об

используемых методах, чем может быть получено путём анализа только их сигнатуры.• C/C++. На данный момент проаннотировано 6570 функций

(стандартные библиотеки C и C++, POSIX, MFC, Qt, ZLib и так далее).• C#. На данный момент проаннотировано 920 функций.

Page 24: Принципы работы статического анализатора кода PVS-Studio

Пример аннотирования функции memcmp

C_"int memcmp(const void *buf1, const void *buf2, size_t count);"ADD(REENTERABLE | RET_USE | F_MEMCMP | STRCMP | HARD_TEST | INT_STATUS, nullptr, nullptr, "memcmp", POINTER_1, POINTER_2, BYTE_COUNT);• C_ - вспомогательный механизм контроля аннотаций (юнит-тесты)• REENTERABLE – повторный вызов с теми же аргументами даст тот-же результат• RET_USE – результат должен быть использован• F_MEMCMP – запуск определённых проверок выхода за границы буфера• STR_CMP – При равенстве функция возвращает 0.• HARD_TEST – особая функция. Некоторые программисты определяют собственные такие

функции в своих namespace. Не учитывать namespace.• INT_STATUS – результат явно сравнивать с 1 или -1.• POINTER_1, POINTER_2 – указатели должны быть не нулевыми и разными.• BYTE_COUNT – параметр задает количество байт и должен быть больше 0.

Page 25: Принципы работы статического анализатора кода PVS-Studio

Аннотация memcmp: проверка результата

bool operator()(const GUID& _Key1, const GUID& _Key2) const{ return memcmp(&_Key1, &_Key2, sizeof(GUID)) == -1;}

Проект CoreCLR

V698 Expression 'memcmp(....) == -1' is incorrect. This function can return not only the value '-1', but any negative value. Consider using 'memcmp(....) < 0' instead. sos util.cpp 142

Page 26: Принципы работы статического анализатора кода PVS-Studio

Аннотация memcmp: хранение результата

Проект Firebird

V642 Saving the 'memcmp' function result inside the 'short' type variable is inappropriate. The significant bits could be lost breaking the program's logic. texttype.cpp 3

SSHORT TextType::compare(ULONG len1, const UCHAR* str1, ULONG len2, const UCHAR* str2){ .... SSHORT cmp = memcmp(str1, str2, MIN(len1, len2)); if (cmp == 0) cmp = (len1 < len2 ? -1 : (len1 > len2 ? 1 : 0)); return cmp;}

Page 27: Принципы работы статического анализатора кода PVS-Studio

Аннотация memcmp: неверный аргументПроект GLG3D

V575 The 'memcmp' function processes '0' elements. Inspect the 'third' argument. graphics3D matrix4.cpp 269

bool Matrix4::operator==(const Matrix4& other) const { if (memcmp(this, &other, sizeof(Matrix4) == 0)) { return true; } ...}

Page 28: Принципы работы статического анализатора кода PVS-Studio

static intpsymbol_compare (const void *addr1, const void *addr2, int length){ struct partial_symbol *sym1 = (struct partial_symbol *) addr1; struct partial_symbol *sym2 = (struct partial_symbol *) addr2;

return (memcmp (&sym1->ginfo.value, &sym1->ginfo.value, sizeof (sym1->ginfo.value)) == 0 && .......

Аннотация memcmp: разные аргументы

Проект GDB

V549 The first argument of 'memcmp' function is equal to the second argument. psymtab.c 1580

Page 29: Принципы работы статического анализатора кода PVS-Studio

dst_s_read_private_key_file(....){ .... if (memcmp(in_buff, "Private-key-format: v", 20) != 0) goto fail; ....} 21 символ

Аннотация memcmp: buffer underrun

Проект Haiku

V512 A call of the 'memcmp' function will lead to underflow of the buffer '"Private-key-format: v"'. dst_api.c 858

Page 30: Принципы работы статического анализатора кода PVS-Studio

Аннотация memcmp: нет состоянияПроект PHP

V501 There are identical sub-expressions '!memcmp("auto", charset_hint, 4)' to the left and to the right of the '||' operator. html.c 396

if ((len == 4) /* sizeof (none|auto|pass) */ && (!memcmp("pass", charset_hint, 4) || !memcmp("auto", charset_hint, 4) || !memcmp("auto", charset_hint, 4)))

Page 31: Принципы работы статического анализатора кода PVS-Studio

Аннотирование пользовательских функций• Практически отсутствует (кроме отдельных элементов, как

собственной функции printf)• Развивать механизм нет смысла• В больших проектах никто не станет тратить месяцы на разметку• Анализатор должен работать сразу

Page 32: Принципы работы статического анализатора кода PVS-Studio

Тестирование анализатора• Тестирование анализатора важнейшая часть процесса его

разработки• Самое сложное в статическом анализе: не ругаться• Большая тестовая база:• C++ Windows (Visual C++): 120 проектов• C++ Linux (GCC): ещё 34 проекта• C# Windows: 54 проекта

Page 33: Принципы работы статического анализатора кода PVS-Studio

Вышлем по почте более подробный вариант презентации• Написать письмо: [email protected]• Подписаться на твиттер: @Code_Analysis

• Скачать PVS-Studio для Windows:http://www.viva64.com/ru/pvs-studio/

• Скачать PVS-Studio для Linux:http://www.viva64.com/ru/pvs-studio-download-linux/