![Page 1: Принципы работы статического анализатора кода PVS-Studio](https://reader034.vdocuments.net/reader034/viewer/2022042610/58a49e691a28ab741b8b6ccf/html5/thumbnails/1.jpg)
Принципы работы статического анализатора
кода PVS-StudioАвторы:к.т.н. Евгений Рыжков, [email protected]к.ф.-м.н. Андрей Карпов, [email protected]
![Page 2: Принципы работы статического анализатора кода PVS-Studio](https://reader034.vdocuments.net/reader034/viewer/2022042610/58a49e691a28ab741b8b6ccf/html5/thumbnails/2.jpg)
ООО "СиПроВер" (www.viva64.com)• Занимаемся разработкой, продвижением и продажей
собственного программного продукта.• Офис: г. Тула, 200 км от Москвы.• Штат: 24 человека
![Page 3: Принципы работы статического анализатора кода PVS-Studio](https://reader034.vdocuments.net/reader034/viewer/2022042610/58a49e691a28ab741b8b6ccf/html5/thumbnails/3.jpg)
PVS-Studio• Более 320 диагностик для C, C++• Более 120 диагностик для C#• Windows• Linux• Плагин для Visual Studio• Быстрый старт (мониторинг компиляции)• SonarQube
![Page 4: Принципы работы статического анализатора кода PVS-Studio](https://reader034.vdocuments.net/reader034/viewer/2022042610/58a49e691a28ab741b8b6ccf/html5/thumbnails/4.jpg)
Наши достижения• Для рекламы мы проверяем открытые проекты. На данный момент мы
проверили около 270 проектов.
• Побочный эффект: нашли более 10000 ошибок в открытых проектах, не задаваясь такой целью.
• В среднем 40 ошибок на проект – вроде немного.
• Важно ещё раз подчеркнуть, что это побочный эффект. У нас нет цели найти как можно больше ошибок. Часто мы останавливаемся, когда нашли достаточное количество дефектов в проекте, чтобы написать статью.
• Вывод: легко проверять даже незнакомые проекты и находить в них ошибки.
![Page 5: Принципы работы статического анализатора кода PVS-Studio](https://reader034.vdocuments.net/reader034/viewer/2022042610/58a49e691a28ab741b8b6ccf/html5/thumbnails/5.jpg)
В начале, что мы НЕ ИСПОЛЬЗУЕМ
![Page 6: Принципы работы статического анализатора кода PVS-Studio](https://reader034.vdocuments.net/reader034/viewer/2022042610/58a49e691a28ab741b8b6ccf/html5/thumbnails/6.jpg)
Мы не используем математический аппарат грамматик• Анализатор работает на более высоком уровне• Анализируется дерево разбора• Для построения дерева мы опираемся на уже существующие
компоненты:• Внешний препроцессор• Библиотека OpenC++, которую мы дорабатываем с развитием C++ по
мере необходимости (собственно от OpenC++ уже ничего не осталось)• При работе с C# кодом мы опираемся на Roslyn
![Page 7: Принципы работы статического анализатора кода PVS-Studio](https://reader034.vdocuments.net/reader034/viewer/2022042610/58a49e691a28ab741b8b6ccf/html5/thumbnails/7.jpg)
Мы не используем методики доказательства правильности программ (program proof).• PVS-Studio не имеет ничего общего с Prototype Verification System
(PVS) http://pvs.csl.sri.com/• PVS-Studio сокращение от OOO "Program Verification Systems"
(ООО "Системы программной верификации")
![Page 8: Принципы работы статического анализатора кода PVS-Studio](https://reader034.vdocuments.net/reader034/viewer/2022042610/58a49e691a28ab741b8b6ccf/html5/thumbnails/8.jpg)
Мы не используем поиск подстрок (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](https://reader034.vdocuments.net/reader034/viewer/2022042610/58a49e691a28ab741b8b6ccf/html5/thumbnails/9.jpg)
Что МЫ используем
Детали анализа C++ и C# кода разнятся, но мы не будем делать в докладе уточнения.
![Page 10: Принципы работы статического анализатора кода PVS-Studio](https://reader034.vdocuments.net/reader034/viewer/2022042610/58a49e691a28ab741b8b6ccf/html5/thumbnails/10.jpg)
Pattern-based analysis• Сопоставление с шаблоном на основе дерева разбора• Применяется для поиска мест в исходном коде, которые похожи
на известные шаблоны кода с ошибкой• Сложность диагностик крайне разнится• В некоторых случаях работают эмпирические алгоритмы
![Page 11: Принципы работы статического анализатора кода PVS-Studio](https://reader034.vdocuments.net/reader034/viewer/2022042610/58a49e691a28ab741b8b6ccf/html5/thumbnails/11.jpg)
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](https://reader034.vdocuments.net/reader034/viewer/2022042610/58a49e691a28ab741b8b6ccf/html5/thumbnails/12.jpg)
Средний случай: проверка не той переменной
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](https://reader034.vdocuments.net/reader034/viewer/2022042610/58a49e691a28ab741b8b6ccf/html5/thumbnails/13.jpg)
Сложный случай: неудачный макрос
#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](https://reader034.vdocuments.net/reader034/viewer/2022042610/58a49e691a28ab741b8b6ccf/html5/thumbnails/14.jpg)
Type inference• Вывод типов на основе семантической модели программы
позволяет анализатору иметь полную информацию о всех переменных и выражениях, встречающихся в коде• Важно для выявления ошибок• Важно для исключений• Особенно важна информация о классах
![Page 15: Принципы работы статического анализатора кода PVS-Studio](https://reader034.vdocuments.net/reader034/viewer/2022042610/58a49e691a28ab741b8b6ccf/html5/thumbnails/15.jpg)
Типы важны для выявления ошибокПроект 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](https://reader034.vdocuments.net/reader034/viewer/2022042610/58a49e691a28ab741b8b6ccf/html5/thumbnails/16.jpg)
Типы важны для исключений
// volatile переменная присваивается сама себеvolatile int *ptr;....*ptr = *ptr; // Нет срабатывания V570
![Page 17: Принципы работы статического анализатора кода PVS-Studio](https://reader034.vdocuments.net/reader034/viewer/2022042610/58a49e691a28ab741b8b6ccf/html5/thumbnails/17.jpg)
Особенно важна информация о классах: например, иерархия наследования
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](https://reader034.vdocuments.net/reader034/viewer/2022042610/58a49e691a28ab741b8b6ccf/html5/thumbnails/18.jpg)
Symbolic execution• Символьное выполнение позволяет вычислять значения
переменных, которые могут приводить к ошибкам, производить проверку диапазонов (range checking) значений• Один из самых важных механизмов:
• Переполнения• Утечки памяти• Выход за границы массива• Нулевые указатели / ссылки• Бессмысленные условия• Деление на 0• И так далее
![Page 19: Принципы работы статического анализатора кода PVS-Studio](https://reader034.vdocuments.net/reader034/viewer/2022042610/58a49e691a28ab741b8b6ccf/html5/thumbnails/19.jpg)
Значения переменных: размер массива, индексы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](https://reader034.vdocuments.net/reader034/viewer/2022042610/58a49e691a28ab741b8b6ccf/html5/thumbnails/20.jpg)
Значения переменных: использование условий для определения диапазона
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](https://reader034.vdocuments.net/reader034/viewer/2022042610/58a49e691a28ab741b8b6ccf/html5/thumbnails/21.jpg)
Значения функций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](https://reader034.vdocuments.net/reader034/viewer/2022042610/58a49e691a28ab741b8b6ccf/html5/thumbnails/22.jpg)
Значения переменных: указатели / ссылки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](https://reader034.vdocuments.net/reader034/viewer/2022042610/58a49e691a28ab741b8b6ccf/html5/thumbnails/23.jpg)
Method annotations• Аннотирование методов предоставляет больше информации об
используемых методах, чем может быть получено путём анализа только их сигнатуры.• C/C++. На данный момент проаннотировано 6570 функций
(стандартные библиотеки C и C++, POSIX, MFC, Qt, ZLib и так далее).• C#. На данный момент проаннотировано 920 функций.
![Page 24: Принципы работы статического анализатора кода PVS-Studio](https://reader034.vdocuments.net/reader034/viewer/2022042610/58a49e691a28ab741b8b6ccf/html5/thumbnails/24.jpg)
Пример аннотирования функции 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](https://reader034.vdocuments.net/reader034/viewer/2022042610/58a49e691a28ab741b8b6ccf/html5/thumbnails/25.jpg)
Аннотация 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](https://reader034.vdocuments.net/reader034/viewer/2022042610/58a49e691a28ab741b8b6ccf/html5/thumbnails/26.jpg)
Аннотация 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](https://reader034.vdocuments.net/reader034/viewer/2022042610/58a49e691a28ab741b8b6ccf/html5/thumbnails/27.jpg)
Аннотация 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](https://reader034.vdocuments.net/reader034/viewer/2022042610/58a49e691a28ab741b8b6ccf/html5/thumbnails/28.jpg)
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](https://reader034.vdocuments.net/reader034/viewer/2022042610/58a49e691a28ab741b8b6ccf/html5/thumbnails/29.jpg)
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](https://reader034.vdocuments.net/reader034/viewer/2022042610/58a49e691a28ab741b8b6ccf/html5/thumbnails/30.jpg)
Аннотация 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](https://reader034.vdocuments.net/reader034/viewer/2022042610/58a49e691a28ab741b8b6ccf/html5/thumbnails/31.jpg)
Аннотирование пользовательских функций• Практически отсутствует (кроме отдельных элементов, как
собственной функции printf)• Развивать механизм нет смысла• В больших проектах никто не станет тратить месяцы на разметку• Анализатор должен работать сразу
![Page 32: Принципы работы статического анализатора кода PVS-Studio](https://reader034.vdocuments.net/reader034/viewer/2022042610/58a49e691a28ab741b8b6ccf/html5/thumbnails/32.jpg)
Тестирование анализатора• Тестирование анализатора важнейшая часть процесса его
разработки• Самое сложное в статическом анализе: не ругаться• Большая тестовая база:• C++ Windows (Visual C++): 120 проектов• C++ Linux (GCC): ещё 34 проекта• C# Windows: 54 проекта
![Page 33: Принципы работы статического анализатора кода PVS-Studio](https://reader034.vdocuments.net/reader034/viewer/2022042610/58a49e691a28ab741b8b6ccf/html5/thumbnails/33.jpg)
Вышлем по почте более подробный вариант презентации• Написать письмо: [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/