Документация по анализатору кода PVS-Studio (одной страницей)
- Введение
- Проверка проектов
- Регулярное использование в процессе разработки
- Интеграция результатов анализа PVS-Studio в инструменты контроля качества кода
- Развёртывание анализатора в облачных CI
- Работа с результатами анализа
- Дополнительная настройка и решение проблем
- Описание диагностируемых ошибок
- Дополнительная информация
Вы можете открыть всю документацию по PVS-Studio одной страницей.
Введение
- Как ввести лицензию PVS-Studio, и что делать дальше
- Ознакомительный режим PVS-Studio
- Системные требования
- Технологии, используемые в PVS-Studio
- История версий
- История версий для старых релизов PVS-Studio (до версии 7.00)
Проверка проектов
На Windows
- Знакомство со статическим анализатором кода PVS-Studio на Windows
- Проверка проектов независимо от сборочной системы (C и C++)
- Прямая интеграция анализатора в системы автоматизации сборки (C и C++)
На Linux и macOS
- Установка PVS-Studio C# на Linux и macOS
- Как запустить PVS-Studio C# на Linux и macOS
- Установка и обновление PVS-Studio C++ на Linux
- Установка и обновление PVS-Studio C++ на macOS
- Как запустить PVS-Studio C++ на Linux и macOS
Кроссплатформенное использование
- Работа с ядром Java анализатора из командной строки
- Кроссплатформенная проверка C и C++ проектов в PVS-Studio
- PVS-Studio для Embedded-разработки
- Анализ C и C++ проектов на основе JSON Compilation Database
Среды разработки
- Работа PVS-Studio в Visual Studio
- Работа PVS-Studio в JetBrains Rider и CLion
- Использование расширения PVS-Studio для Qt Creator
- Интеграция с Qt Creator без использования плагина PVS-Studio
- Использование расширения PVS-Studio для Visual Studio Code
- Работа PVS-Studio в IntelliJ IDEA и Android Studio
Сборочные системы
- Проверка проектов Visual Studio / MSBuild / .NET из командной строки с помощью PVS-Studio
- Интеграция PVS-Studio с помощью CMake-модуля
- Интеграция PVS-Studio Java в сборочную систему Gradle
- Интеграция PVS-Studio Java в сборочную систему Maven
Игровые движки
Регулярное использование в процессе разработки
- Запуск PVS-Studio в Docker
- Запуск PVS-Studio в Jenkins
- Запуск PVS-Studio в TeamCity
- Загрузка результатов анализа в Jira
- PVS-Studio и Continuous Integration
- Режим инкрементального анализа PVS-Studio
- Проверка коммитов и Pull Request'ов
- Автоматическое развертывание PVS-Studio
- Ускорение анализа C и C++ кода с помощью систем распределённой сборки (Incredibuild)
Интеграция результатов анализа PVS-Studio в инструменты контроля качества кода
- Интеграция результатов анализа PVS-Studio в DefectDojo
- Интеграция результатов анализа PVS-Studio в SonarQube
- Интеграция результатов анализа PVS-Studio в CodeChecker
Развёртывание анализатора в облачных CI
- Использование в Travis CI
- Использование в CircleCI
- Использование в GitLab CI/CD
- Использование в GitHub Actions
- Использование в Azure DevOps
- Использование в AppVeyor
- Использование в Buddy
Работа с результатами анализа
- Отображение наиболее интересных предупреждений анализатора
- Использование диагностических правил группы OWASP в PVS-Studio
- Подавление сообщений анализатора (отключение выдачи предупреждений на существующий код)
- Работа со списком диагностических сообщений в Visual Studio
- Подавление ложноположительных предупреждений
- Просмотр и конвертация результатов анализа
- Использование относительных путей в файлах отчётов PVS-Studio
- Просмотр результатов анализа в приложении C and C++ Compiler Monitoring UI
- Оповещение команд разработчиков (утилита blame-notifier)
- Фильтрация и обработка вывода анализатора при помощи файлов конфигурации диагностик (.pvsconfig)
- Исключение из анализа файлов и каталогов
Дополнительная настройка и решение проблем
- Советы по повышению скорости работы PVS-Studio
- Устранение неисправностей при работе PVS-Studio
- Дополнительная настройка диагностик
- Механизм пользовательских аннотаций в формате JSON
- Предопределенный макрос PVS_STUDIO
- Файл конфигурации анализа Settings.xml
- Настройки анализатора (Visual Studio / C and C++ Compiler Monitoring UI)
Описание диагностируемых ошибок
- Сообщения PVS-Studio
- Диагностики общего назначения (General Analysis, C++)
- Диагностики общего назначения (General Analysis, C#)
- Диагностики общего назначения (General Analysis, Java)
- Микрооптимизации (C++)
- Микрооптимизации (C#)
- Диагностика 64-битных ошибок (Viva64, C++)
- Реализовано по запросам пользователей (C++)
- Cтандарт MISRA
- Стандарт AUTOSAR
- Стандарт OWASP (C++)
- Стандарт OWASP (C#)
- Стандарт OWASP (Java)
- Проблемы при работе анализатора кода
Дополнительная информация
- График количества диагностик в PVS-Studio
- Какие ошибки ловит PVS-Studio?
- Список всех диагностик анализатора в XML
- Диагностики общего назначения (General Analysis, C++)
- Диагностики общего назначения (General Analysis, C#)
- Диагностики общего назначения (General Analysis, Java)
- Микрооптимизации (C++)
- Микрооптимизации (C#)
- Диагностика 64-битных ошибок (Viva64, C++)
- Реализовано по запросам пользователей (C++)
- Cтандарт MISRA
- Стандарт AUTOSAR
- Стандарт OWASP (C++)
- Стандарт OWASP (C#)
- Стандарт OWASP (Java)
- Проблемы при работе анализатора кода
Сообщения PVS-Studio
График количества диагностик в PVS-Studio
Анализатор PVS-Studio активно развивается. Например, наша команда постоянно совершенствует его интеграцию с различными CI/CD системами и средами разработки, добавляет поддержку новых платформ и компиляторов. Однако лучше всего развитие возможностей анализатора показывает график количества диагностик.
![warnings_ru/image1.png](https://import.viva64.com/docx/manual/../warnings/warnings_ru/image1.png)
Рисунок 1. Увеличение количества диагностик в PVS-Studio
Как видите, мы активно совершенствуем возможности анализатора по выявлению новых паттернов ошибок. Более подробная информация по нововведениям в различных версиях анализатора представлена ниже. Вы также можете почитать об изменениях в PVS-Studio за последний год в нашем блоге.
Какие ошибки ловит PVS-Studio?
Мы постарались сгруппировать большинство диагностик в несколько групп, чтобы вы могли получить общее представление о возможностях анализатора кода PVS-Studio.
Так как деление диагностик весьма условно, то некоторые диагностики входят в несколько групп. Например, неправильное условие "if (abc == abc)", можно одновременно интерпретировать и как простую опечатку, и как проблему безопасности, так как ошибка приводит к уязвимости кода при некорректных входных данных.
Некоторым ошибкам наоборот места в таблице не нашлось - уж слишком они специфичны. Тем не менее, таблица в целом дает представление о функциональности статического анализатора кода.
Список всех диагностик анализатора в XML
Список диагностик анализатора в формате XML, предназначенный для автоматического разбора, доступен по постоянной ссылке здесь.
Основные диагностические возможности PVS-Studio |
Диагностики |
---|---|
64-битные ошибки |
C, C++: V101-V128, V201-V207, V220, V221, V301-V303 |
Адрес локальной переменной возвращается из функции по ссылке |
C, C++: V506, V507, V558, V723, V758, V1017, V1047 |
Арифметическое переполнение, потеря значимости |
C, C++: V569, V636, V658, V784, V786, V1012, V1026, V1028, V1029, V1033, V1070, V1081, V1083, V1085, V1112
C#: V3041, V3200, V3204
Java: V6011, V6088, V6117 |
Выход за границу массива |
C, C++: V557, V582, V643, V781, V1038, V1111
C#: V3106
Java: V6025, V6079 |
Двойное освобождение ресурсов |
C, C++: V586, V749, V1002, V1006 |
Мёртвый код |
C, C++: V606, V607
Java: V6021 |
Микрооптимизации |
C, C++: V801, V802, V803, V804, V805, V806, V807, V808, V809, V810, V811, V812, V813, V814, V815, V816, V817, V818, V819, V820, V821, V822, V823, V824, V825, V826, V827, V828, V829, V830, V831, V832, V833, V834, V835, V836, V837, V838, V839
C#: V4001, V4002, V4003, V4004, V4005, V4006, V4007 |
Недостижимый код |
C, C++: V517, V551, V695, V734, V776, V779, V785
C#: V3136, V3142, V3202
Java: V6018, V6019 |
Неинициализированные переменные |
C, C++: V573, V614, V679, V730, V737, V788, V1007, V1050, V1077, V1086
C#: V3070, V3128
Java: V6036, V6050, V6052, V6090 |
Неиспользуемые переменные |
C, C++: V603, V751, V763, V1001, V1079
C#: V3061, V3065, V3077, V3117, V3137, V3143, V3196, V3203
Java: V6021, V6022, V6023 |
Некорректные операции сдвига |
C, C++: V610, V629, V673, V684, V770, V1093
C#: V3134
Java: V6034, V6069 |
Неопределенное/неуточняемое поведение |
C, C++: V567, V610, V611, V681, V694, V704, V708, V726, V736, V772, V1007, V1016, V1026, V1032, V1061, V1066, V1069, V1082, V1091, V1094, V1097, V1099 |
Неправильная работа с типами (HRESULT, BSTR, BOOL, VARIANT_BOOL, float, double) |
C, C++: V543, V544, V545, V556, V615, V636, V676, V716, V721, V724, V745, V750, V767, V768, V771, V772, V775, V1014, V1027, V1034, V1046, V1060, V1066, V1084
C#: V3041, V3059, V3076, V3111, V3121, V3148
Java: V6038, V6108 |
Неправильное представление о работе функции/класса |
C, C++: V515, V518, V530, V540, V541, V554, V575, V597, V598, V618, V630, V632, V663, V668, V698, V701, V702, V717, V718, V720, V723, V725, V727, V738, V742, V743, V748, V762, V764, V780, V789, V797, V1014, V1024, V1031, V1035, V1045, V1052, V1053, V1054, V1057, V1060, V1066, V1098, V1100, V1107, V1115
C#: V3010, V3057, V3068, V3072, V3073, V3074, V3078, V3082, V3084, V3094, V3096, V3097, V3102, V3103, V3104, V3108, V3114, V3115, V3118, V3123, V3126, V3145, V3178, V3186, V3192, V3194, V3195, V3197
Java: V6009, V6010, V6016, V6026, V6029, V6049, V6055, V6058, V6064, V6068, V6081, V6110, V6116, V6122, V6125 |
Опечатки |
C, C++: V501, V503, V504, V508, V511, V516, V519, V520, V521, V525, V527, V528, V529, V532, V533, V534, V535, V536, V537, V539, V546, V549, V552, V556, V559, V560, V561, V564, V568, V570, V571, V575, V577, V578, V584, V587, V588, V589, V590, V592, V602, V604, V606, V607, V616, V617, V620, V621, V622, V625, V626, V627, V633, V637, V638, V639, V644, V646, V650, V651, V653, V654, V655, V657, V660, V661, V662, V666, V669, V671, V672, V678, V682, V683, V693, V715, V722, V735, V741, V747, V753, V754, V756, V765, V767, V768, V770, V771, V787, V791, V792, V796, V1013, V1015, V1021, V1040, V1051, V1055, V1074, V1094, V1113
C#: V3001, V3003, V3005, V3007, V3008, V3009, V3011, V3012, V3014, V3015, V3016, V3020, V3028, V3029, V3034, V3035, V3036, V3037, V3038, V3050, V3055, V3056, V3057, V3060, V3062, V3063, V3066, V3081, V3086, V3091, V3092, V3093, V3102, V3107, V3109, V3110, V3112, V3113, V3116, V3118, V3122, V3124, V3132, V3140, V3170, V3174, V3185, V3187
Java: V6001, V6005, V6009, V6012, V6014, V6015, V6016, V6017, V6021, V6026, V6028, V6029, V6030, V6031, V6037, V6041, V6042, V6043, V6045, V6057, V6059, V6061, V6062, V6063, V6077, V6080, V6085, V6091, V6105, V6112 |
Отсутствие виртуального деструктора |
C, C++: V599, V689 |
Оформление кода не совпадает с логикой его работы |
C, C++: V563, V612, V628, V640, V646, V705, V709, V715, V1044, V1073
C#: V3007, V3018, V3033, V3043, V3067, V3069, V3138, V3150, V3172, V3183
Java: V6040, V6047, V6063, V6086, V6089 |
Ошибки из-за Copy-Paste |
C, C++: V501, V517, V519, V523, V524, V571, V581, V649, V656, V666, V691, V760, V766, V778, V1037
C#: V3001, V3003, V3004, V3008, V3012, V3013, V3021, V3030, V3058, V3127, V3139, V3140
Java: V6003, V6004, V6012, V6021, V6027, V6032, V6033, V6039, V6067, V6072 |
Ошибки при работе с исключениями |
C, C++: V509, V565, V596, V667, V668, V740, V741, V746, V759, V1022, V1045, V1067, V1090
C#: V3006, V3052, V3100, V3141, V3163, V3164, V5606, V5607
Java: V6006, V6051, V6103 |
Переполнение буфера |
C, C++: V512, V514, V594, V635, V641, V645, V752, V755 |
Проблемы безопасности |
C, C++: V505, V510, V511, V512, V518, V531, V541, V547, V559, V560, V569, V570, V575, V576, V579, V583, V597, V598, V618, V623, V631, V642, V645, V675, V676, V724, V727, V729, V733, V743, V745, V750, V771, V774, V782, V1003, V1005, V1010, V1017, V1055, V1072, V1076, V1113
C#: V3022, V3023, V3025, V3027, V3039, V3053, V3063, V5601, V5608, V5609, V5610, V5611, V5612, V5613, V5614, V5615, V5616, V5617, V5618, V5619, V5620, V5621, V5622, V5623, V5624, V5625, V5626, V5627, V5628
Java: V5305, V5309, V6007, V6046, V6054, V6109 |
Путаница с приоритетом операций |
C, C++: V502, V562, V593, V634, V648, V727, V733, V1003, V1104
C#: V3130, V3133, V3177, V3207
Java: V6044 |
Разыменование нулевого указателя/нулевой ссылки |
C, C++: V522, V595, V664, V713, V757, V769
C#: V3019, V3042, V3080, V3095, V3105, V3125, V3141, V3145, V3146, V3148, V3149, V3153, V3156, V3168
Java: V6008, V6060, V6093 |
Разыменование параметров без предварительной проверки |
C, C++: V595, V664, V783, V1004
C#: V3095
Java: V6060 |
Ошибки синхронизации |
C, C++: V712, V720, V744, V1011, V1018, V1025, V1036, V1088, V1089, V1114
C#: V3032, V3054, V3079, V3082, V3083, V3089, V3090, V3147, V3167, V3168, V3190
Java: V6064, V6070, V6074, V6082, V6095, V6102, V6125 |
Утечки ресурсов |
C, C++: V599, V701, V773, V1020, V1023, V1100, V1106, V1110
Java: V6114, V6115 |
Целочисленное деление на 0 |
C, C++: V609
C#: V3064, V3151, V3152
Java: V6020 |
Ошибки сериализации / десериализации |
C, C++: V513, V663, V739, V1024, V1095
C#: V3094, V3096, V3097, V3099, V3103, V3104, V3193, V5611
Java: V6065, V6075, V6076, V6083, V6087 |
Диагностики, созданные по специальным просьбам пользователей |
C, C++: V2001, V2002, V2003, V2004, V2005, V2006, V2007, V2008, V2009, V2010, V2011, V2012, V2013, V2014, V2022 |
Таблица 1 – Возможности PVS-Studio.
Как видите, анализатор максимально проявляет себя в таких областях, как поиск ошибок, возникших из-за опечаток и Copy-Paste. Хорошо диагностирует проблемы, которые связаны с безопасностью кода.
Как всё это работает на практике можно узнать, заглянув в базу ошибок. Мы собираем в эту базу все ошибки, которые нашли, проверяя различные открытые проекты с помощью PVS-Studio.
Диагностики общего назначения (General Analysis, C++)
- V501. Identical sub-expressions to the left and to the right of 'foo' operator.
- V502. The '?:' operator may not work as expected. The '?:' operator has a lower priority than the 'foo' operator.
- V503. Nonsensical comparison: pointer < 0.
- V504. Semicolon ';' is probably missing after the 'return' keyword.
- V505. The 'alloca' function is used inside the loop. This can quickly overflow stack.
- V506. Pointer to local variable 'X' is stored outside the scope of this variable. Such a pointer will become invalid.
- V507. Pointer to local array 'X' is stored outside the scope of this array. Such a pointer will become invalid.
- V508. The 'new type(n)' pattern was detected. Probably meant: 'new type[n]'.
- V509. Exceptions raised inside noexcept functions must be wrapped in a try..catch block.
- V510. The 'Foo' function receives class-type variable as Nth actual argument. This is unexpected behavior.
- V511. The sizeof() operator returns pointer size instead of array size.
- V512. Call of the 'Foo' function will lead to buffer overflow.
- V513. Use _beginthreadex/_endthreadex functions instead of CreateThread/ExitThread functions.
- V514. Potential logical error. Size of a pointer is divided by another value.
- V515. The 'delete' operator is applied to non-pointer.
- V516. Non-null function pointer is compared to null. Consider inspecting the expression.
- V517. Potential logical error. The 'if (A) {...} else if (A) {...}' pattern was detected.
- V518. The 'malloc' function allocates suspicious amount of memory calculated by 'strlen(expr)'. Perhaps the correct expression is strlen(expr) + 1.
- V519. The 'x' variable is assigned values twice successively. Perhaps this is a mistake.
- V520. Comma operator ',' in array index expression.
- V521. Expressions that use comma operator ',' are dangerous. Make sure the expression is correct.
- V522. Possible null pointer dereference.
- V523. The 'then' statement is equivalent to the 'else' statement.
- V524. It is suspicious that the body of 'Foo_1' function is fully equivalent to the body of 'Foo_2' function.
- V525. Code contains collection of similar blocks. Check items X, Y, Z, ... in lines N1, N2, N3, ...
- V526. The 'strcmp' function returns 0 if corresponding strings are equal. Consider inspecting the condition for mistakes.
- V527. The 'zero' value is assigned to pointer. Probably meant: *ptr = zero.
- V528. Pointer is compared with 'zero' value. Probably meant: *ptr != zero.
- V529. Suspicious semicolon ';' after 'if/for/while' operator.
- V530. Return value of 'Foo' function is required to be used.
- V531. The sizeof() operator is multiplied by sizeof(). Consider inspecting the expression.
- V532. Consider inspecting the statement of '*pointer++' pattern. Probably meant: '(*pointer)++'.
- V533. It is possible that a wrong variable is incremented inside the 'for' operator. Consider inspecting 'X'.
- V534. It is possible that a wrong variable is compared inside the 'for' operator. Consider inspecting 'X'.
- V535. The 'X' variable is used for this loop and outer loops.
- V536. Constant value is represented by an octal form.
- V537. Potential incorrect use of item 'X'. Consider inspecting the expression.
- V538. The line contains control character 0x0B (vertical tabulation).
- V539. Iterators are passed as arguments to 'Foo' function. Consider inspecting the expression.
- V540. Member 'x' should point to string terminated by two 0 characters.
- V541. String is printed into itself. Consider inspecting the expression.
- V542. Suspicious type cast: 'Type1' to ' Type2'. Consider inspecting the expression.
- V543. It is suspicious that value 'X' is assigned to the variable 'Y' of HRESULT type.
- V544. It is suspicious that the value 'X' of HRESULT type is compared with 'Y'.
- V545. Conditional expression of 'if' statement is incorrect for the HRESULT type value 'Foo'. The SUCCEEDED or FAILED macro should be used instead.
- V546. The 'Foo(Foo)' class member is initialized with itself.
- V547. Expression is always true/false.
- V548. TYPE X[][] is not equivalent to TYPE **X. Consider inspecting type casting.
- V549. The 'first' argument of 'Foo' function is equal to the 'second' argument.
- V550. Suspicious precise comparison. Consider using a comparison with defined precision: fabs(A - B) < Epsilon or fabs(A - B) > Epsilon.
- V551. Unreachable code under a 'case' label.
- V552. A bool type variable is incremented. Perhaps another variable should be incremented instead.
- V553. Length of function body or class declaration is more than 2000 lines. Consider refactoring the code.
- V554. Incorrect use of smart pointer.
- V555. Expression of the 'A - B > 0' kind will work as 'A != B'.
- V556. Values of different enum types are compared.
- V557. Possible array overrun.
- V558. Function returns pointer/reference to temporary local object.
- V559. Suspicious assignment inside the conditional expression of 'if/while/for' statement.
- V560. Part of conditional expression is always true/false.
- V561. Consider assigning value to 'foo' variable instead of declaring it anew.
- V562. Bool type value is compared with value of N. Consider inspecting the expression.
- V563. An 'else' branch may apply to the previous 'if' statement.
- V564. The '&' or '|' operator is applied to bool type value. Check for missing parentheses or use the '&&' or '||' operator.
- V565. Empty exception handler. Silent suppression of exceptions can hide errors in source code during testing.
- V566. Integer constant is converted to pointer. Check for an error or bad coding style.
- V567. Modification of variable is unsequenced relative to another operation on the same variable. This may lead to undefined behavior.
- V568. It is suspicious that the argument of sizeof() operator is the expression.
- V569. Truncation of constant value.
- V570. Variable is assigned to itself.
- V571. Recurring check. This condition was already verified in previous line.
- V572. Object created using 'new' operator is immediately cast to another type. Consider inspecting the expression.
- V573. Use of uninitialized variable 'Foo'. The variable was used to initialize itself.
- V574. Pointer is used both as an array and as a pointer to single object.
- V575. Function receives suspicious argument.
- V576. Incorrect format. Consider checking the Nth actual argument of the 'Foo' function.
- V577. Label is present inside switch(). Check for typos and consider using the 'default:' operator instead.
- V578. Suspicious bitwise operation was detected. Consider inspecting it.
- V579. The 'Foo' function receives the pointer and its size as arguments. This may be a potential error. Inspect the Nth argument.
- V580. Suspicious explicit type casting. Consider inspecting the expression.
- V581. Conditional expressions of 'if' statements located next to each other are identical.
- V582. Consider reviewing the source code that uses the container.
- V583. The '?:' operator, regardless of its conditional expression, always returns the same value.
- V584. Same value is present on both sides of the operator. The expression is incorrect or can be simplified.
- V585. Attempt to release memory that stores the 'Foo' local variable.
- V586. The 'Foo' function is called twice to deallocate the same resource.
- V587. Suspicious sequence of assignments: A = B; B = A;.
- V588. Expression of the 'A =+ B' kind is used. Possibly meant: 'A += B'. Consider inspecting the expression.
- V589. Expression of the 'A =- B' kind is used. Possibly meant: 'A -= B'. Consider inspecting the expression.
- V590. Possible excessive expression or typo. Consider inspecting the expression.
- V591. Non-void function must return value.
- V592. Expression is enclosed by parentheses twice: ((expression)). One pair of parentheses is unnecessary or typo is present.
- V593. Expression 'A = B == C' is calculated as 'A = (B == C)'. Consider inspecting the expression.
- V594. Pointer to array is out of array bounds.
- V595. Pointer was used before its check for nullptr. Check lines: N1, N2.
- V596. Object was created but is not used. Check for missing 'throw' keyword.
- V597. Compiler may delete 'memset' function call that is used to clear 'Foo' buffer. Use the RtlSecureZeroMemory() function to erase private data.
- V598. Memory manipulation function is used to work with a class object containing a virtual table pointer. The result of such an operation may be unexpected.
- V599. The virtual destructor is not present, although the 'Foo' class contains virtual functions.
- V600. The 'Foo' pointer is always not equal to NULL. Consider inspecting the condition.
- V601. Suspicious implicit type casting.
- V602. The '<' operator should probably be replaced with '<<'. Consider inspecting this expression.
- V603. Object was created but not used. If you wish to call constructor, use 'this->Foo::Foo(....)'.
- V604. Number of iterations in loop equals size of a pointer. Consider inspecting the expression.
- V605. Unsigned value is compared to the NN number. Consider inspecting the expression.
- V606. Ownerless token 'Foo'.
- V607. Ownerless expression 'Foo'.
- V608. Recurring sequence of explicit type casts.
- V609. Possible division or mod by zero.
- V610. Undefined behavior. Check the shift operator.
- V611. Memory allocation and deallocation methods are incompatible.
- V612. Unconditional 'break/continue/return/goto' within a loop.
- V613. Suspicious pointer arithmetic with 'malloc/new'.
- V614. Use of 'Foo' uninitialized variable.
- V615. Suspicious explicit conversion from 'float *' type to 'double *' type.
- V616. Use of 'Foo' named constant with 0 value in bitwise operation.
- V617. Argument of the '|' bitwise operation always contains non-zero value. Consider inspecting the condition.
- V618. Dangerous call of 'Foo' function. The passed line may contain format specification. Example of safe code: printf("%s", str);
- V619. Array is used as pointer to single object.
- V620. Expression of sizeof(T)*N kind is summed up with pointer to T type. Consider inspecting the expression.
- V621. Loop may execute incorrectly or may not execute at all. Consider inspecting the 'for' operator.
- V622. First 'case' operator may be missing. Consider inspecting the 'switch' statement.
- V623. Temporary object is created and then destroyed. Consider inspecting the '?:' operator.
- V624. Use of constant NN. The resulting value may be inaccurate. Consider using the M_NN constant from <math.h>.
- V625. Initial and final values of the iterator are the same. Consider inspecting the 'for' operator.
- V626. It's possible that ',' should be replaced by ';'. Consider checking for typos.
- V627. Argument of sizeof() is a macro, which expands to a number. Consider inspecting the expression.
- V628. It is possible that a line was commented out improperly, thus altering the program's operation logic.
- V629. Bit shifting of the 32-bit value with a subsequent expansion to the 64-bit type. Consider inspecting the expression.
- V630. The 'malloc' function is used to allocate memory for an array of objects that are classes containing constructors/destructors.
- V631. Defining absolute path to file or directory is considered a poor coding style. Consider inspecting the 'Foo' function call.
- V632. Argument is of the 'T' type. Consider inspecting the NN argument of the 'Foo' function.
- V633. The '!=' operator should probably be used here. Consider inspecting the expression.
- V634. Priority of '+' operation is higher than priority of '<<' operation. Consider using parentheses in the expression.
- V635. Length should be probably multiplied by sizeof(wchar_t). Consider inspecting the expression.
- V636. Expression was implicitly cast from integer type to real type. Consider using an explicit type cast to avoid overflow or loss of a fractional part.
- V637. Use of two opposite conditions. The second condition is always false.
- V638. Terminal null is present inside a string. Use of '\0xNN' characters. Probably meant: '\xNN'.
- V639. One of closing ')' parentheses is probably positioned incorrectly. Consider inspecting the expression for function call.
- V640. Code's operational logic does not correspond with its formatting.
- V641. Buffer size is not a multiple of element size.
- V642. Function result is saved inside the 'byte' type variable. Significant bits may be lost. This may break the program's logic.
- V643. Suspicious pointer arithmetic. Value of 'char' type is added to a string pointer.
- V644. Suspicious function declaration. Consider creating a 'T' type object.
- V645. Function call may lead to buffer overflow. Bounds should not contain size of a buffer, but a number of characters it can hold.
- V646. The 'else' keyword may be missing. Consider inspecting the program's logic.
- V647. Value of 'A' type is assigned to a pointer of 'B' type.
- V648. Priority of '&&' operation is higher than priority of '||' operation.
- V649. Two 'if' statements with identical conditional expressions. The first 'if' statement contains function return. This means that the second 'if' statement is senseless.
- V650. Type casting is used 2 times in a row. The '+' operation is executed. Probably meant: (T1)((T2)a + b).
- V651. Suspicious operation of 'sizeof(X)/sizeof(T)' kind, where 'X' is of the 'class' type.
- V652. Operation is executed 3 or more times in a row.
- V653. Suspicious string consisting of two parts is used for initialization. Comma may be missing.
- V654. Condition of a loop is always true/false.
- V655. Strings were concatenated but not used. Consider inspecting the expression.
- V656. Variables are initialized through the call to the same function. It's probably an error or un-optimized code.
- V657. Function always returns the same value of NN. Consider inspecting the function.
- V658. Value is subtracted from unsigned variable. It can result in an overflow. In such a case, the comparison operation may behave unexpectedly.
- V659. Functions' declarations with 'Foo' name differ in 'const' keyword only, while these functions' bodies have different composition. It is suspicious and can possibly be an error.
- V660. Program contains an unused label and function call: 'CC:AA()'. Probably meant: 'CC::AA()'.
- V661. Suspicious expression 'A[B < C]'. Probably meant 'A[B] < C'.
- V662. Different containers are used to set up initial and final values of iterator. Consider inspecting the loop expression.
- V663. Infinite loop is possible. The 'cin.eof()' condition is insufficient to break from the loop. Consider adding the 'cin.fail()' function call to the conditional expression.
- V664. Pointer is dereferenced on the initialization list before its check for null inside the body of a constructor function.
- V665. Possible incorrect use of '#pragma warning(default: X)'. The '#pragma warning(push/pop)' should be used instead.
- V666. Value may not correspond with the length of a string passed with YY argument. Consider inspecting the NNth argument of the 'Foo' function.
- V667. The 'throw' operator does not have any arguments and is not located within the 'catch' block.
- V668. Possible meaningless check for null, as memory was allocated using 'new' operator. Memory allocation will lead to an exception.
- V669. Argument is a non-constant reference. The analyzer is unable to determine the position where this argument is modified. Consider checking the function for an error.
- V670. Uninitialized class member is used to initialize another member. Remember that members are initialized in the order of their declarations inside a class.
- V671. The 'swap' function may interchange a variable with itself.
- V672. It is possible that creating a new variable is unnecessary. One of the function's arguments has the same name and this argument is a reference.
- V673. More than N bits are required to store the value, but the expression evaluates to the T type which can only hold K bits.
- V674. Expression contains a suspicious mix of integer and real types.
- V675. Writing into read-only memory.
- V676. Incorrect comparison of BOOL type variable with TRUE.
- V677. Custom declaration of standard type. Consider using the declaration from system header files instead.
- V678. Object is used as an argument to its own method. Consider checking the first actual argument of the 'Foo' function.
- V679. The 'X' variable was not initialized. This variable is passed by reference to the 'Foo' function in which its value will be used.
- V680. The 'delete A, B' expression only destroys the 'A' object. Then the ',' operator returns a resulting value from the right side of the expression.
- V681. The language standard does not define order in which 'Foo' functions are called during evaluation of arguments.
- V682. Suspicious literal: '/r'. It is possible that a backslash should be used instead: '\r'.
- V683. The 'i' variable should probably be incremented instead of the 'n' variable. Consider inspecting the loop expression.
- V684. Value of variable is not modified. It is possible that '1' should be present instead of '0'. Consider inspecting the expression.
- V685. The expression contains a comma. Consider inspecting the return statement.
- V686. Pattern A || (A && ...) was detected. The expression is excessive or contains a logical error.
- V687. Size of array calculated by sizeof() operator was added to a pointer. It is possible that the number of elements should be calculated by sizeof(A)/sizeof(A[0]).
- V688. The 'foo' local variable has the same name as one of class members. This can result in confusion.
- V689. Destructor of 'Foo' class is not declared as virtual. A smart pointer may not destroy an object correctly.
- V690. The class implements a copy constructor/operator=, but lacks the operator=/copy constructor.
- V691. Empirical analysis. Possible typo inside the string literal. The 'foo' word is suspicious.
- V692. Inappropriate attempt to append a null character to a string. To determine the length of a string by 'strlen' function correctly, use a string ending with a null terminator in the first place.
- V693. It is possible that 'i < X.size()' should be used instead of 'X.size()'. Consider inspecting conditional expression of the loop.
- V694. The condition (ptr - const_value) is only false if the value of a pointer equals a magic constant.
- V695. Range intersections are possible within conditional expressions.
- V696. The 'continue' operator will terminate 'do { ... } while (FALSE)' loop because the condition is always false.
- V697. Number of elements in the allocated array equals the size of a pointer in bytes.
- V698. Functions of strcmp() kind can return any values, not only -1, 0, or 1.
- V699. It is possible that 'foo = bar == baz ? .... : ....' should be used here instead of 'foo = bar = baz ? .... : ....'. Consider inspecting the expression.
- V700. It is suspicious that variable is initialized through itself. Consider inspecting the 'T foo = foo = x;' expression.
- V701. Possible realloc() leak: when realloc() fails to allocate memory, original pointer is lost. Consider assigning realloc() to a temporary pointer.
- V702. Classes should always be derived from std::exception (and alike) as 'public'.
- V703. It is suspicious that the 'foo' field in derived class overwrites field in base class.
- V704. The expression is always false on newer compilers. Avoid using 'this == 0' comparison.
- V705. It is possible that 'else' block was forgotten or commented out, thus altering the program's operation logics.
- V706. Suspicious division: sizeof(X) / Value. Size of every element in X array is not equal to divisor.
- V707. Giving short names to global variables is considered to be bad practice.
- V708. Dangerous construction is used: 'm[x] = m.size()', where 'm' is of 'T' class. This may lead to undefined behavior.
- V709. Suspicious comparison found: 'a == b == c'. Remember that 'a == b == c' is not equal to 'a == b && b == c'.
- V710. Suspicious declaration. There is no point to declare constant reference to a number.
- V711. It is dangerous to create a local variable within a loop with a same name as a variable controlling this loop.
- V712. Compiler may optimize out this loop or make it infinite. Use volatile variable(s) or synchronization primitives to avoid this.
- V713. Pointer was used in the logical expression before its check for nullptr in the same logical expression.
- V714. Variable is not passed into foreach loop by reference, but its value is changed inside of the loop.
- V715. The 'while' operator has empty body. This pattern is suspicious.
- V716. Suspicious type conversion: HRESULT -> BOOL (BOOL -> HRESULT).
- V717. It is suspicious to cast object of base class V to derived class U.
- V718. The 'Foo' function should not be called from 'DllMain' function.
- V719. The switch statement does not cover all values of the enum.
- V720. The 'SuspendThread' function is usually used when developing a debugger. See documentation for details.
- V721. The VARIANT_BOOL type is used incorrectly. The true value (VARIANT_TRUE) is defined as -1.
- V722. Abnormality within similar comparisons. It is possible that a typo is present inside the expression.
- V723. Function returns a pointer to the internal string buffer of a local object, which will be destroyed.
- V724. Converting integers or pointers to BOOL can lead to a loss of high-order bits. Non-zero value can become 'FALSE'.
- V725. Dangerous cast of 'this' to 'void*' type in the 'Base' class, as it is followed by a subsequent cast to 'Class' type.
- V726. Attempt to free memory containing the 'int A[10]' array by using the 'free(A)' function.
- V727. Return value of 'wcslen' function is not multiplied by 'sizeof(wchar_t)'.
- V728. Excessive check can be simplified. The '||' operator is surrounded by opposite expressions 'x' and '!x'.
- V729. Function body contains the 'X' label that is not used by any 'goto' statements.
- V730. Not all members of a class are initialized inside the constructor.
- V731. The variable of char type is compared with pointer to string.
- V732. Unary minus operator does not modify a bool type value.
- V733. It is possible that macro expansion resulted in incorrect evaluation order.
- V734. Excessive expression. Examine the substrings "abc" and "abcd".
- V735. Possibly an incorrect HTML. The "</XX>" closing tag was encountered, while the "</YY>" tag was expected.
- V736. The behavior is undefined for arithmetic or comparisons with pointers that do not point to members of the same array.
- V737. It is possible that ',' comma is missing at the end of the string.
- V738. Temporary anonymous object is used.
- V739. EOF should not be compared with a value of the 'char' type. Consider using the 'int' type.
- V740. Exception is of the 'int' type because NULL is defined as 0. Keyword 'nullptr' can be used for 'pointer' type exception.
- V741. Use of the throw (a, b); pattern. It is possible that type name was omitted: throw MyException(a, b);.
- V742. Function receives an address of a 'char' type variable instead of pointer to a buffer.
- V743. The memory areas must not overlap. Use 'memmove' function.
- V744. Temporary object is immediately destroyed after being created. Consider naming the object.
- V745. A 'wchar_t *' type string is incorrectly converted to 'BSTR' type string.
- V746. Object slicing. An exception should be caught by reference rather than by value.
- V747. Suspicious expression inside parentheses. A function name may be missing.
- V748. Memory for 'getline' function should be allocated only by 'malloc' or 'realloc' functions. Consider inspecting the first parameter of 'getline' function.
- V749. Destructor of the object will be invoked a second time after leaving the object's scope.
- V750. BSTR string becomes invalid. Notice that BSTR strings store their length before start of the text.
- V751. Parameter is not used inside function's body.
- V752. Creating an object with placement new requires a buffer of large size.
- V753. The '&=' operation always sets a value of 'Foo' variable to zero.
- V754. The expression of 'foo(foo(x))' pattern is excessive or contains an error.
- V755. Copying from potentially tainted data source. Buffer overflow is possible.
- V756. The 'X' counter is not used inside a nested loop. Consider inspecting usage of 'Y' counter.
- V757. It is possible that an incorrect variable is compared with null after type conversion using 'dynamic_cast'.
- V758. Reference was invalidated because of destruction of the temporary object returned by the function.
- V759. Violated order of exception handlers. Exception caught by handler for base class.
- V760. Two identical text blocks were detected. The second block starts with NN string.
- V761. NN identical blocks were found.
- V762. Consider inspecting virtual function arguments. See NN argument of function 'Foo' in derived class and base class.
- V763. Parameter is always rewritten in function body before being used.
- V764. Possible incorrect order of arguments passed to function.
- V765. Compound assignment expression 'X += X + N' is suspicious. Consider inspecting it for a possible error.
- V766. An item with the same key has already been added.
- V767. Suspicious access to element by a constant index inside a loop.
- V768. Variable is of enum type. It is suspicious that it is used as a variable of a Boolean-type.
- V769. The pointer in the expression equals nullptr. The resulting value is meaningless and should not be used.
- V770. Possible use of left shift operator instead of comparison operator.
- V771. The '?:' operator uses constants from different enums.
- V772. Calling the 'delete' operator for a void pointer will cause undefined behavior.
- V773. Function exited without releasing the pointer/handle. A memory/resource leak is possible.
- V774. Pointer was used after the memory was released.
- V775. It is suspicious that the BSTR data type is compared using a relational operator.
- V776. Potentially infinite loop. The variable in the loop exit condition does not change its value between iterations.
- V777. Dangerous widening type conversion from an array of derived-class objects to a base-class pointer.
- V778. Two similar code fragments. Perhaps, it is a typo and 'X' variable should be used instead of 'Y'.
- V779. Unreachable code was detected. It is possible that an error is present.
- V780. The object of non-passive (non-PDS) type cannot be used with the function.
- V781. Value of a variable is checked after it is used. Possible error in program's logic. Check lines: N1, N2.
- V782. It is pointless to compute the distance between the elements of different arrays.
- V783. Possible dereference of invalid iterator 'X'.
- V784. The size of the bit mask is less than the size of the first operand. This will cause the loss of the higher bits.
- V785. Constant expression in switch statement.
- V786. Assigning the value C to the X variable looks suspicious. The value range of the variable: [A, B].
- V787. Wrong variable is probably used in the for operator as an index.
- V788. Review captured variable in lambda expression.
- V789. Iterators for the container, used in the range-based for loop, become invalid upon a function call.
- V790. It is suspicious that the assignment operator takes an object by a non-constant reference and returns this object.
- V791. The initial value of the index in the nested loop equals 'i'. Consider using 'i + 1' instead.
- V792. The function located to the right of the '|' and '&' operators will be called regardless of the value of the left operand. Consider using '||' and '&&' instead.
- V793. It is suspicious that the result of the statement is a part of the condition. Perhaps, this statement should have been compared with something else.
- V794. The assignment operator should be protected from the case of 'this == &src'.
- V795. Size of the 'time_t' type is not 64 bits. After the year 2038, the program will work incorrectly.
- V796. A 'break' statement is probably missing in a 'switch' statement.
- V797. The function is used as if it returned a bool type. The return value of the function should probably be compared with std::string::npos.
- V798. The size of the dynamic array can be less than the number of elements in the initializer.
- V799. Variable is not used after memory is allocated for it. Consider checking the use of this variable.
- V1001. Variable is assigned but not used by the end of the function.
- V1002. Class that contains pointers, constructor and destructor is copied by the automatically generated operator= or copy constructor.
- V1003. Macro expression is dangerous or suspicious.
- V1004. Pointer was used unsafely after its check for nullptr.
- V1005. The resource was acquired using 'X' function but was released using incompatible 'Y' function.
- V1006. Several shared_ptr objects are initialized by the same pointer. A double memory deallocation will occur.
- V1007. Value from the uninitialized optional is used. It may be an error.
- V1008. No more than one iteration of the loop will be performed. Consider inspecting the 'for' operator.
- V1009. Check the array initialization. Only the first element is initialized explicitly.
- V1010. Unchecked tainted data is used in expression.
- V1011. Function execution could be deferred. Consider specifying execution policy explicitly.
- V1012. The expression is always false. Overflow check is incorrect.
- V1013. Suspicious subexpression in a sequence of similar comparisons.
- V1014. Structures with members of real type are compared byte-wise.
- V1015. Suspicious simultaneous use of bitwise and logical operators.
- V1016. The value is out of range of enum values. This causes unspecified or undefined behavior.
- V1017. Variable of the 'string_view' type references a temporary object, which will be removed after evaluation of an expression.
- V1018. Usage of a suspicious mutex wrapper. It is probably unused, uninitialized, or already locked.
- V1019. Compound assignment expression is used inside condition.
- V1020. Function exited without performing epilogue actions. It is possible that there is an error.
- V1021. The variable is assigned the same value on several loop iterations.
- V1022. Exception was thrown by pointer. Consider throwing it by value instead.
- V1023. A pointer without owner is added to the container by the 'emplace_back' method. A memory leak will occur in case of an exception.
- V1024. Potential use of invalid data. The stream is checked for EOF before reading from it but is not checked after reading.
- V1025. New variable with default value is created instead of 'std::unique_lock' that locks on the mutex.
- V1026. The variable is incremented in the loop. Undefined behavior will occur in case of signed integer overflow.
- V1027. Pointer to an object of the class is cast to unrelated class.
- V1028. Possible overflow. Consider casting operands, not the result.
- V1029. Numeric Truncation Error. Return value of function is written to N-bit variable.
- V1030. Variable is used after it is moved.
- V1031. Function is not declared. The passing of data to or from this function may be affected.
- V1032. Pointer is cast to a more strictly aligned pointer type.
- V1033. Variable is declared as auto in C. Its default type is int.
- V1034. Do not use real-type variables as loop counters.
- V1035. Only values returned from fgetpos() can be used as arguments to fsetpos().
- V1036. Potentially unsafe double-checked locking.
- V1037. Two or more case-branches perform the same actions.
- V1038. It is suspicious that a char or string literal is added to a pointer.
- V1039. Character escape is used in multicharacter literal. This causes implementation-defined behavior.
- V1040. Possible typo in the spelling of a pre-defined macro name.
- V1041. Class member is initialized with dangling reference.
- V1042. This file is marked with copyleft license, which requires you to open the derived source code.
- V1043. A global object variable is declared in the header. Multiple copies of it will be created in all translation units that include this header file.
- V1044. Loop break conditions do not depend on the number of iterations.
- V1045. The DllMain function throws an exception. Consider wrapping the throw operator in a try..catch block.
- V1046. Unsafe usage of the 'bool' and integer types together in the operation '&='.
- V1047. Lifetime of the lambda is greater than lifetime of the local variable captured by reference.
- V1048. Variable 'foo' was assigned the same value.
- V1049. The 'foo' include guard is already defined in the 'bar1.h' header. The 'bar2.h' header will be excluded from compilation.
- V1050. Uninitialized class member is used when initializing the base class.
- V1051. It is possible that an assigned variable should be checked in the next condition. Consider checking for typos.
- V1052. Declaring virtual methods in a class marked as 'final' is pointless.
- V1053. Calling the 'foo' virtual function in the constructor/destructor may lead to unexpected result at runtime.
- V1054. Object slicing. Derived class object was copied to the base class object.
- V1055. The 'sizeof' expression returns the size of the container type, not the number of elements. Consider using the 'size()' function.
- V1056. The predefined identifier '__func__' always contains the string 'operator()' inside function body of the overloaded 'operator()'.
- V1057. Pseudo random sequence is the same at every program run. Consider assigning the seed to a value not known at compile-time.
- V1058. Nonsensical comparison of two different functions' addresses.
- V1059. Macro name overrides a keyword/reserved name. This may lead to undefined behavior.
- V1060. Passing 'BSTR ' to the 'SysAllocString' function may lead to incorrect object creation.
- V1061. Extending 'std' or 'posix' namespace may result in undefined behavior.
- V1062. Class defines a custom new or delete operator. The opposite operator must also be defined.
- V1063. The modulo by 1 operation is meaningless. The result will always be zero.
- V1064. The left operand of integer division is less than the right one. The result will always be zero.
- V1065. Expression can be simplified: check similar operands.
- V1066. The 'SysFreeString' function should be called only for objects of the 'BSTR' type.
- V1067. Throwing from exception constructor may lead to unexpected behavior.
- V1068. Do not define an unnamed namespace in a header file.
- V1069. Do not concatenate string literals with different prefixes.
- V1070. Signed value is converted to an unsigned one with subsequent expansion to a larger type in ternary operator.
- V1071. Return value is not always used. Consider inspecting the 'foo' function.
- V1072. Buffer needs to be securely cleared on all execution paths.
- V1073. Check the following code block after the 'if' statement. Consider checking for typos.
- V1074. Boundary between numeric escape sequence and string is unclear. The escape sequence ends with a letter and the next character is also a letter. Check for typos.
- V1075. The function expects the file to be opened in one mode, but it was opened in different mode.
- V1076. Code contains invisible characters that may alter its logic. Consider enabling the display of invisible characters in the code editor.
- V1077. Constructor contains potentially uninitialized members.
- V1078. An empty container is iterated. The loop will not be executed.
- V1079. Parameter of 'std::stop_token' type is not used inside function's body.
- V1080. Call of 'std::is_constant_evaluated' function always returns the same value.
- V1081. Argument of abs() function is minimal negative value. Such absolute value can't be represented in two's complement. This leads to undefined behavior.
- V1082. Function marked as 'noreturn' may return control. This will result in undefined behavior.
- V1083. Signed integer overflow in arithmetic expression. This leads to undefined behavior.
- V1084. The expression is always true/false. The value is out of range of enum values.
- V1085. Negative value is implicitly converted to unsigned integer type in arithmetic expression.
- V1086. Call of the 'Foo' function will lead to buffer underflow.
- V1087. Upper bound of case range is less than its lower bound. This case may be unreachable.
- V1088. No objects are passed to the 'std::scoped_lock' constructor. No locking will be performed. This can cause concurrency issues.
- V1089. Waiting on condition variable without predicate. A thread can wait indefinitely or experience a spurious wake-up.
- V1090. The 'std::uncaught_exception' function is deprecated since C++17 and is removed in C++20. Consider replacing this function with 'std::uncaught_exceptions'.
- V1091. The pointer is cast to an integer type of a larger size. Casting pointer to a type of a larger size is an implementation-defined behavior.
- V1092. Recursive function call during the static/thread_local variable initialization might occur. This may lead to undefined behavior.
- V1093. The result of the right shift operation will always be 0. The right operand is greater than or equal to the number of bits in the left operand.
- V1094. Conditional escape sequence in literal. Its representation is implementation-defined.
- V1095. Usage of potentially invalid handle. The value should be non-negative.
- V1096. Variable with static storage duration is declared inside the inline function with external linkage. This may lead to ODR violation.
- V1097. Line splice results in a character sequence that matches the syntax of a universal-character-name. Using this sequence lead to undefined behavior.
- V1098. The 'emplace' / 'insert' function call contains potentially dangerous move operation. Moved object can be destroyed even if there is no insertion.
- V1099. Using the function of uninitialized derived class while initializing the base class will lead to undefined behavior.
- V1100. Unreal Engine. Declaring a pointer to a type derived from 'UObject' in a class that is not derived from 'UObject' is dangerous. The pointer may start pointing to an invalid object after garbage collection.
- V1101. Changing the default argument of a virtual function parameter in a derived class may result in unexpected behavior.
- V1102. Unreal Engine. Violation of naming conventions may cause Unreal Header Tool to work incorrectly.
- V1103. The values of padding bytes are unspecified. Comparing objects with padding using 'memcmp' may lead to unexpected result.
- V1104. Priority of the 'M' operator is higher than that of the 'N' operator. Possible missing parentheses.
- V1105. Suspicious string modification using the 'operator+='. The right operand is implicitly converted to a character type.
- V1106. Qt. Class inherited from 'QObject' should contain at least one constructor that takes a pointer to 'QObject'.
- V1107. Function was declared as accepting unspecified number of parameters. Consider explicitly specifying the function parameters list.
- V1108. Constraint specified in a custom function annotation on the parameter is violated.
- V1109. Function is deprecated. Consider switching to an equivalent newer function.
- V1110. Constructor of a class inherited from 'QObject' does not use a pointer to a parent object.
- V1111. The index was used without check after it was checked in previous lines.
- V1112. Comparing expressions with different signedness can lead to unexpected results.
- V1113. Potential resource leak. Calling the 'memset' function will change the pointer itself, not the allocated resource. Check the first and third arguments.
- V1114. Suspicious use of type conversion operator when working with COM interfaces. Consider using the 'QueryInterface' member function.
- V1115. Function annotated with the 'pure' attribute has side effects.
- V1116. Creating an exception object without an explanatory message may result in insufficient logging.
- V1117. The declared function type is cv-qualified. The behavior when using this type is undefined.
Диагностики общего назначения (General Analysis, C#)
- V3001. There are identical sub-expressions to the left and to the right of the 'foo' operator.
- V3002. The switch statement does not cover all values of the enum.
- V3003. The use of 'if (A) {...} else if (A) {...}' pattern was detected. There is a probability of logical error presence.
- V3004. The 'then' statement is equivalent to the 'else' statement.
- V3005. The 'x' variable is assigned to itself.
- V3006. The object was created but it is not being used. The 'throw' keyword could be missing.
- V3007. Odd semicolon ';' after 'if/for/while' operator.
- V3008. The 'x' variable is assigned values twice successively. Perhaps this is a mistake.
- V3009. It's odd that this method always returns one and the same value of NN.
- V3010. The return value of function 'Foo' is required to be utilized.
- V3011. Two opposite conditions were encountered. The second condition is always false.
- V3012. The '?:' operator, regardless of its conditional expression, always returns one and the same value.
- V3013. It is odd that the body of 'Foo_1' function is fully equivalent to the body of 'Foo_2' function.
- V3014. It is likely that a wrong variable is being incremented inside the 'for' operator. Consider reviewing 'X'.
- V3015. It is likely that a wrong variable is being compared inside the 'for' operator. Consider reviewing 'X'.
- V3016. The variable 'X' is being used for this loop and for the outer loop.
- V3017. A pattern was detected: A || (A && ...). The expression is excessive or contains a logical error.
- V3018. Consider inspecting the application's logic. It's possible that 'else' keyword is missing.
- V3019. It is possible that an incorrect variable is compared with null after type conversion using 'as' keyword.
- V3020. An unconditional 'break/continue/return/goto' within a loop.
- V3021. There are two 'if' statements with identical conditional expressions. The first 'if' statement contains method return. This means that the second 'if' statement is senseless.
- V3022. Expression is always true/false.
- V3023. Consider inspecting this expression. The expression is excessive or contains a misprint.
- V3024. An odd precise comparison. Consider using a comparison with defined precision: Math.Abs(A - B) < Epsilon or Math.Abs(A - B) > Epsilon.
- V3025. Incorrect format. Consider checking the N format items of the 'Foo' function.
- V3026. The constant NN is being utilized. The resulting value could be inaccurate. Consider using the KK constant.
- V3027. The variable was utilized in the logical expression before it was verified against null in the same logical expression.
- V3028. Consider inspecting the 'for' operator. Initial and final values of the iterator are the same.
- V3029. The conditional expressions of the 'if' statements situated alongside each other are identical.
- V3030. Recurring check. This condition was already verified in previous line.
- V3031. An excessive check can be simplified. The operator '||' operator is surrounded by opposite expressions 'x' and '!x'.
- V3032. Waiting on this expression is unreliable, as compiler may optimize some of the variables. Use volatile variable(s) or synchronization primitives to avoid this.
- V3033. It is possible that this 'else' branch must apply to the previous 'if' statement.
- V3034. Consider inspecting the expression. Probably the '!=' should be used here.
- V3035. Consider inspecting the expression. Probably the '+=' should be used here.
- V3036. Consider inspecting the expression. Probably the '-=' should be used here.
- V3037. An odd sequence of assignments of this kind: A = B; B = A;
- V3038. The argument was passed to method several times. It is possible that another argument should be passed instead.
- V3039. Consider inspecting the 'Foo' function call. Defining an absolute path to the file or directory is considered a poor style.
- V3040. The expression contains a suspicious mix of integer and real types.
- V3041. The expression was implicitly cast from integer type to real type. Consider utilizing an explicit type cast to avoid the loss of a fractional part.
- V3042. Possible NullReferenceException. The '?.' and '.' operators are used for accessing members of the same object.
- V3043. The code's operational logic does not correspond with its formatting.
- V3044. WPF: writing and reading are performed on a different Dependency Properties.
- V3045. WPF: the names of the property registered for DependencyProperty, and of the property used to access it, do not correspond with each other.
- V3046. WPF: the type registered for DependencyProperty does not correspond with the type of the property used to access it.
- V3047. WPF: A class containing registered property does not correspond with a type that is passed as the ownerType.type.
- V3048. WPF: several Dependency Properties are registered with a same name within the owner type.
- V3049. WPF: readonly field of 'DependencyProperty' type is not initialized.
- V3050. Possibly an incorrect HTML. The </XX> closing tag was encountered, while the </YY> tag was expected.
- V3051. An excessive type cast or check. The object is already of the same type.
- V3052. The original exception object was swallowed. Stack of original exception could be lost.
- V3053. An excessive expression. Examine the substrings "abc" and "abcd".
- V3054. Potentially unsafe double-checked locking. Use volatile variable(s) or synchronization primitives to avoid this.
- V3055. Suspicious assignment inside the condition expression of 'if/while/for' operator.
- V3056. Consider reviewing the correctness of 'X' item's usage.
- V3057. Function receives an odd argument.
- V3058. An item with the same key has already been added.
- V3059. Consider adding '[Flags]' attribute to the enum.
- V3060. A value of variable is not modified. Consider inspecting the expression. It is possible that other value should be present instead of '0'.
- V3061. Parameter 'A' is always rewritten in method body before being used.
- V3062. An object is used as an argument to its own method. Consider checking the first actual argument of the 'Foo' method.
- V3063. A part of conditional expression is always true/false if it is evaluated.
- V3064. Division or mod division by zero.
- V3065. Parameter is not utilized inside method's body.
- V3066. Possible incorrect order of arguments passed to method.
- V3067. It is possible that 'else' block was forgotten or commented out, thus altering the program's operation logics.
- V3068. Calling overrideable class member from constructor is dangerous.
- V3069. It's possible that the line was commented out improperly, thus altering the program's operation logics.
- V3070. Uninitialized variables are used when initializing the 'A' variable.
- V3071. The object is returned from inside 'using' block. 'Dispose' will be invoked before exiting method.
- V3072. The 'A' class containing IDisposable members does not itself implement IDisposable.
- V3073. Not all IDisposable members are properly disposed. Call 'Dispose' when disposing 'A' class.
- V3074. The 'A' class contains 'Dispose' method. Consider making it implement 'IDisposable' interface.
- V3075. The operation is executed 2 or more times in succession.
- V3076. Comparison with 'double.NaN' is meaningless. Use 'double.IsNaN()' method instead.
- V3077. Property setter / event accessor does not utilize its 'value' parameter.
- V3078. Sorting keys priority will be reversed relative to the order of 'OrderBy' method calls. Perhaps, 'ThenBy' should be used instead.
- V3079. The 'ThreadStatic' attribute is applied to a non-static 'A' field and will be ignored.
- V3080. Possible null dereference.
- V3081. The 'X' counter is not used inside a nested loop. Consider inspecting usage of 'Y' counter.
- V3082. The 'Thread' object is created but is not started. It is possible that a call to 'Start' method is missing.
- V3083. Unsafe invocation of event, NullReferenceException is possible. Consider assigning event to a local variable before invoking it.
- V3084. Anonymous function is used to unsubscribe from event. No handlers will be unsubscribed, as a separate delegate instance is created for each anonymous function declaration.
- V3085. The name of 'X' field/property in a nested type is ambiguous. The outer type contains static field/property with identical name.
- V3086. Variables are initialized through the call to the same function. It's probably an error or un-optimized code.
- V3087. Type of variable enumerated in 'foreach' is not guaranteed to be castable to the type of collection's elements.
- V3088. The expression was enclosed by parentheses twice: ((expression)). One pair of parentheses is unnecessary or misprint is present.
- V3089. Initializer of a field marked by [ThreadStatic] attribute will be called once on the first accessing thread. The field will have default value on different threads.
- V3090. Unsafe locking on an object.
- V3091. Empirical analysis. It is possible that a typo is present inside the string literal. The 'foo' word is suspicious.
- V3092. Range intersections are possible within conditional expressions.
- V3093. The operator evaluates both operands. Perhaps a short-circuit operator should be used instead.
- V3094. Possible exception when deserializing type. The Ctor(SerializationInfo, StreamingContext) constructor is missing.
- V3095. The object was used before it was verified against null. Check lines: N1, N2.
- V3096. Possible exception when serializing type. [Serializable] attribute is missing.
- V3097. Possible exception: type marked by [Serializable] contains non-serializable members not marked by [NonSerialized].
- V3098. The 'continue' operator will terminate 'do { ... } while (false)' loop because the condition is always false.
- V3099. Not all the members of type are serialized inside 'GetObjectData' method.
- V3100. NullReferenceException is possible. Unhandled exceptions in destructor lead to termination of runtime.
- V3101. Potential resurrection of 'this' object instance from destructor. Without re-registering for finalization, destructor will not be called a second time on resurrected object.
- V3102. Suspicious access to element by a constant index inside a loop.
- V3103. A private Ctor(SerializationInfo, StreamingContext) constructor in unsealed type will not be accessible when deserializing derived types.
- V3104. The 'GetObjectData' implementation in unsealed type is not virtual, incorrect serialization of derived type is possible.
- V3105. The 'a' variable was used after it was assigned through null-conditional operator. NullReferenceException is possible.
- V3106. Possibly index is out of bound.
- V3107. Identical expression to the left and to the right of compound assignment.
- V3108. It is not recommended to return null or throw exceptions from 'ToString()' method.
- V3109. The same sub-expression is present on both sides of the operator. The expression is incorrect or it can be simplified.
- V3110. Possible infinite recursion.
- V3111. Checking value for null will always return false when generic type is instantiated with a value type.
- V3112. An abnormality within similar comparisons. It is possible that a typo is present inside the expression.
- V3113. Consider inspecting the loop expression. It is possible that different variables are used inside initializer and iterator.
- V3114. IDisposable object is not disposed before method returns.
- V3115. It is not recommended to throw exceptions from 'Equals(object obj)' method.
- V3116. Consider inspecting the 'for' operator. It's possible that the loop will be executed incorrectly or won't be executed at all.
- V3117. Constructor parameter is not used.
- V3118. A component of TimeSpan is used, which does not represent full time interval. Possibly 'Total*' value was intended instead.
- V3119. Calling a virtual (overridden) event may lead to unpredictable behavior. Consider implementing event accessors explicitly or use 'sealed' keyword.
- V3120. Potentially infinite loop. The variable from the loop exit condition does not change its value between iterations.
- V3121. An enumeration was declared with 'Flags' attribute, but does not set any initializers to override default values.
- V3122. Uppercase (lowercase) string is compared with a different lowercase (uppercase) string.
- V3123. Perhaps the '??' operator works in a different way than it was expected. Its priority is lower than priority of other operators in its left part.
- V3124. Appending an element and checking for key uniqueness is performed on two different variables.
- V3125. The object was used after it was verified against null. Check lines: N1, N2.
- V3126. Type implementing IEquatable<T> interface does not override 'GetHashCode' method.
- V3127. Two similar code fragments were found. Perhaps, this is a typo and 'X' variable should be used instead of 'Y'.
- V3128. The field (property) is used before it is initialized in constructor.
- V3129. The value of the captured variable will be overwritten on the next iteration of the loop in each instance of anonymous function that captures it.
- V3130. Priority of the '&&' operator is higher than that of the '||' operator. Possible missing parentheses.
- V3131. The expression is checked for compatibility with the type 'A', but is casted to the 'B' type.
- V3132. A terminal null is present inside a string. The '\0xNN' characters were encountered. Probably meant: '\xNN'.
- V3133. Postfix increment/decrement is senseless because this variable is overwritten.
- V3134. Shift by N bits is greater than the size of type.
- V3135. The initial value of the index in the nested loop equals 'i'. Consider using 'i + 1' instead.
- V3136. Constant expression in switch statement.
- V3137. The variable is assigned but is not used by the end of the function.
- V3138. String literal contains potential interpolated expression.
- V3139. Two or more case-branches perform the same actions.
- V3140. Property accessors use different backing fields.
- V3141. Expression under 'throw' is a potential null, which can lead to NullReferenceException.
- V3142. Unreachable code detected. It is possible that an error is present.
- V3143. The 'value' parameter is rewritten inside a property setter, and is not used after that.
- V3144. This file is marked with copyleft license, which requires you to open the derived source code.
- V3145. Unsafe dereference of a WeakReference target. The object could have been garbage collected before the 'Target' property was accessed.
- V3146. Possible null dereference. A method can return default null value.
- V3147. Non-atomic modification of volatile variable.
- V3148. Casting potential 'null' value to a value type can lead to NullReferenceException.
- V3149. Dereferencing the result of 'as' operator can lead to NullReferenceException.
- V3150. Loop break conditions do not depend on the number of iterations.
- V3151. Potential division by zero. Variable was used as a divisor before it was compared to zero. Check lines: N1, N2.
- V3152. Potential division by zero. Variable was compared to zero before it was used as a divisor. Check lines: N1, N2.
- V3153. Dereferencing the result of null-conditional access operator can lead to NullReferenceException.
- V3154. The 'a % b' expression always evaluates to 0.
- V3155. The expression is incorrect or it can be simplified.
- V3156. The argument of the method is not expected to be null.
- V3157. Suspicious division. Absolute value of the left operand is less than the right operand.
- V3158. Suspicious division. Absolute values of both operands are equal.
- V3159. Modified value of the operand is not used after the increment/decrement operation.
- V3160. Argument of incorrect type is passed to the 'Enum.HasFlag' method.
- V3161. Comparing value type variables with 'ReferenceEquals' is incorrect because compared values will be boxed.
- V3162. Suspicious return of an always empty collection.
- V3163. An exception handling block does not contain any code.
- V3164. Exception classes should be publicly accessible.
- V3165. The expression of the 'char' type is passed as an argument of the 'A' type whereas similar overload with the string parameter exists.
- V3166. Calling the 'SingleOrDefault' method may lead to 'InvalidOperationException'.
- V3167. Parameter of 'CancellationToken' type is not used inside function's body.
- V3168. Awaiting on expression with potential null value can lead to throwing of 'NullReferenceException'.
- V3169. Suspicious return of a local reference variable which always equals null.
- V3170. Both operands of the '??' operator are identical.
- V3171. Potentially negative value is used as the size of an array.
- V3172. The 'if/if-else/for/while/foreach' statement and code block after it are not related. Inspect the program's logic.
- V3173. Possible incorrect initialization of variable. Consider verifying the initializer.
- V3174. Suspicious subexpression in a sequence of similar comparisons.
- V3175. Locking operations must be performed on the same thread. Using 'await' in a critical section may lead to a lock being released on a different thread.
- V3176. The '&=' or '|=' operator is redundant because the right operand is always true/false.
- V3177. Logical literal belongs to second operator with a higher priority. It is possible literal was intended to belong to '??' operator instead.
- V3178. Calling method or accessing property of potentially disposed object may result in exception.
- V3179. Calling element access method for potentially empty collection may result in exception.
- V3180. The 'HasFlag' method always returns 'true' because the value '0' is passed as its argument.
- V3181. The result of '&' operator is '0' because one of the operands is '0'.
- V3182. The result of '&' operator is always '0'.
- V3183. Code formatting implies that the statement should not be a part of the 'then' branch that belongs to the preceding 'if' statement.
- V3184. The argument's value is greater than the size of the collection. Passing the value into the 'Foo' method will result in an exception.
- V3185. An argument containing a file path could be mixed up with another argument. The other function parameter expects a file path instead.
- V3186. The arguments violate the bounds of collection. Passing these values into the method will result in an exception.
- V3187. Parts of an SQL query are not delimited by any separators or whitespaces. Executing this query may lead to an error.
- V3188. Unity Engine. The value of an expression is a potentially destroyed Unity object or null. Member invocation on this value may lead to an exception.
- V3189. The assignment to a member of the readonly field will have no effect when the field is of a value type. Consider restricting the type parameter to reference types.
- V3190. Concurrent modification of a variable may lead to errors.
- V3191. Iteration through collection makes no sense because it is always empty.
- V3192. Type member is used in the 'GetHashCode' method but is missing from the 'Equals' method.
- V3193. Data processing results are potentially used before asynchronous output reading is complete. Consider calling 'WaitForExit' overload with no arguments before using the data.
- V3194. Calling 'OfType' for collection will return an empty collection. It is not possible to cast collection elements to the type parameter.
- V3195. Collection initializer implicitly calls 'Add' method. Using it on member with default value of null will result in null dereference exception.
- V3196. Parameter is not utilized inside the method body, but an identifier with a similar name is used inside the same method.
- V3197. The compared value inside the 'Object.Equals' override is converted to a different type that does not contain the override.
- V3198. The variable is assigned the same value that it already holds.
- V3199. The index from end operator is used with the value that is less than or equal to zero. Collection index will be out of bounds.
- V3200. Possible overflow. The expression will be evaluated before casting. Consider casting one of the operands instead.
- V3201. Return value is not always used. Consider inspecting the 'foo' method.
- V3202. Unreachable code detected. The 'case' value is out of the range of the match expression.
- V3203. Method parameter is not used.
- V3204. The expression is always false due to implicit type conversion. Overflow check is incorrect.
- V3205. Unity Engine. Improper creation of 'MonoBehaviour' or 'ScriptableObject' object using the 'new' operator. Use the special object creation method instead.
- V3206. Unity Engine. A direct call to the coroutine-like method will not start it. Use the 'StartCoroutine' method instead.
- V3207. The 'not A or B' logical pattern may not work as expected. The 'not' pattern is matched only to the first expression from the 'or' pattern.
- V3208. Unity Engine. Using 'WeakReference' with 'UnityEngine.Object' is not supported. GC will not reclaim the object's memory because it is linked to a native object.
- V3209. Unity Engine. Using await on 'Awaitable' object more than once can lead to exception or deadlock, as such objects are returned to the pool after being awaited.
- V3210. Unity Engine. Unity does not allow removing the 'Transform' component using 'Destroy' or 'DestroyImmediate' methods. The method call will be ignored.
Диагностики общего назначения (General Analysis, Java)
- V6001. There are identical sub-expressions to the left and to the right of the 'foo' operator.
- V6002. The switch statement does not cover all values of the enum.
- V6003. The use of 'if (A) {...} else if (A) {...}' pattern was detected. There is a probability of logical error presence.
- V6004. The 'then' statement is equivalent to the 'else' statement.
- V6005. The 'x' variable is assigned to itself.
- V6006. The object was created but it is not being used. The 'throw' keyword could be missing.
- V6007. Expression is always true/false.
- V6008. Potential null dereference.
- V6009. Function receives an odd argument.
- V6010. The return value of function 'Foo' is required to be utilized.
- V6011. The expression contains a suspicious mix of integer and real types.
- V6012. The '?:' operator, regardless of its conditional expression, always returns one and the same value.
- V6013. Comparison of arrays, strings, collections by reference. Possibly an equality comparison was intended.
- V6014. It's odd that this method always returns one and the same value of NN.
- V6015. Consider inspecting the expression. Probably the '!='/'-='/'+=' should be used here.
- V6016. Suspicious access to element by a constant index inside a loop.
- V6017. The 'X' counter is not used inside a nested loop. Consider inspecting usage of 'Y' counter.
- V6018. Constant expression in switch statement.
- V6019. Unreachable code detected. It is possible that an error is present.
- V6020. Division or mod division by zero.
- V6021. The value is assigned to the 'x' variable but is not used.
- V6022. Parameter is not used inside method's body.
- V6023. Parameter 'A' is always rewritten in method body before being used.
- V6024. The 'continue' operator will terminate 'do { ... } while (false)' loop because the condition is always false.
- V6025. Possibly index is out of bound.
- V6026. This value is already assigned to the 'b' variable.
- V6027. Variables are initialized through the call to the same function. It's probably an error or un-optimized code.
- V6028. Identical expression to the left and to the right of compound assignment.
- V6029. Possible incorrect order of arguments passed to method.
- V6030. The function located to the right of the '|' and '&' operators will be called regardless of the value of the left operand. Consider using '||' and '&&' instead.
- V6031. The variable 'X' is being used for this loop and for the outer loop.
- V6032. It is odd that the body of 'Foo_1' function is fully equivalent to the body of 'Foo_2' function.
- V6033. An item with the same key has already been added.
- V6034. Shift by N bits is inconsistent with the size of type.
- V6035. Double negation is present in the expression: !!x.
- V6036. The value from the uninitialized optional is used.
- V6037. An unconditional 'break/continue/return/goto' within a loop.
- V6038. Comparison with 'double.NaN' is meaningless. Use 'double.isNaN()' method instead.
- V6039. There are two 'if' statements with identical conditional expressions. The first 'if' statement contains method return. This means that the second 'if' statement is senseless.
- V6040. The code's operational logic does not correspond with its formatting.
- V6041. Suspicious assignment inside the conditional expression of 'if/while/do...while' statement.
- V6042. The expression is checked for compatibility with type 'A', but is cast to type 'B'.
- V6043. Consider inspecting the 'for' operator. Initial and final values of the iterator are the same.
- V6044. Postfix increment/decrement is senseless because this variable is overwritten.
- V6045. Suspicious subexpression in a sequence of similar comparisons.
- V6046. Incorrect format. Consider checking the N format items of the 'Foo' function.
- V6047. It is possible that this 'else' branch must apply to the previous 'if' statement.
- V6048. This expression can be simplified. One of the operands in the operation equals NN. Probably it is a mistake.
- V6049. Classes that define 'equals' method must also define 'hashCode' method.
- V6050. Class initialization cycle is present.
- V6051. Use of jump statements in 'finally' block can lead to the loss of unhandled exceptions.
- V6052. Calling an overridden method in parent-class constructor may lead to use of uninitialized data.
- V6053. Collection is modified while iteration is in progress. ConcurrentModificationException may occur.
- V6054. Classes should not be compared by their name.
- V6055. Expression inside assert statement can change object's state.
- V6056. Implementation of 'compareTo' overloads the method from a base class. Possibly, an override was intended.
- V6057. Consider inspecting this expression. The expression is excessive or contains a misprint.
- V6058. Comparing objects of incompatible types.
- V6059. Odd use of special character in regular expression. Possibly, it was intended to be escaped.
- V6060. The reference was used before it was verified against null.
- V6061. The used constant value is represented by an octal form.
- V6062. Possible infinite recursion.
- V6063. Odd semicolon ';' after 'if/for/while' operator.
- V6064. Suspicious invocation of Thread.run().
- V6065. A non-serializable class should not be serialized.
- V6066. Passing objects of incompatible types to the method of collection.
- V6067. Two or more case-branches perform the same actions.
- V6068. Suspicious use of BigDecimal class.
- V6069. Unsigned right shift assignment of negative 'byte' / 'short' value.
- V6070. Unsafe synchronization on an object.
- V6071. This file is marked with copyleft license, which requires you to open the derived source code.
- V6072. Two similar code fragments were found. Perhaps, this is a typo and 'X' variable should be used instead of 'Y'.
- V6073. It is not recommended to return null or throw exceptions from 'toString' / 'clone' methods.
- V6074. Non-atomic modification of volatile variable.
- V6075. The signature of method 'X' does not conform to serialization requirements.
- V6076. Recurrent serialization will use cached object state from first serialization.
- V6077. A suspicious label is present inside a switch(). It is possible that these are misprints and 'default:' label should be used instead.
- V6078. Potential Java SE API compatibility issue.
- V6079. Value of variable is checked after use. Potential logical error is present. Check lines: N1, N2.
- V6080. Consider checking for misprints. It's possible that an assigned variable should be checked in the next condition.
- V6081. Annotation that does not have 'RUNTIME' retention policy will not be accessible through Reflection API.
- V6082. Unsafe double-checked locking.
- V6083. Serialization order of fields should be preserved during deserialization.
- V6084. Suspicious return of an always empty collection.
- V6085. An abnormality within similar comparisons. It is possible that a typo is present inside the expression.
- V6086. Suspicious code formatting. 'else' keyword is probably missing.
- V6087. InvalidClassException may occur during deserialization.
- V6088. Result of this expression will be implicitly cast to 'Type'. Check if program logic handles it correctly.
- V6089. It's possible that the line was commented out improperly, thus altering the program's operation logics.
- V6090. Field 'A' is being used before it was initialized.
- V6091. Suspicious getter/setter implementation. The 'A' field should probably be returned/assigned instead.
- V6092. A resource is returned from try-with-resources statement. It will be closed before the method exits.
- V6093. Automatic unboxing of a variable may cause NullPointerException.
- V6094. The expression was implicitly cast from integer type to real type. Consider utilizing an explicit type cast to avoid the loss of a fractional part.
- V6095. Thread.sleep() inside synchronized block/method may cause decreased performance.
- V6096. An odd precise comparison. Consider using a comparison with defined precision: Math.abs(A - B) < Epsilon or Math.abs(A - B) > Epsilon.
- V6097. Lowercase 'L' at the end of a long literal can be mistaken for '1'.
- V6098. The method does not override another method from the base class.
- V6099. The initial value of the index in the nested loop equals 'i'. Consider using 'i + 1' instead.
- V6100. An object is used as an argument to its own method. Consider checking the first actual argument of the 'Foo' method.
- V6101. compareTo()-like methods can return not only the values -1, 0 and 1, but any values.
- V6102. Inconsistent synchronization of a field. Consider synchronizing the field on all usages.
- V6103. Ignored InterruptedException could lead to delayed thread shutdown.
- V6104. A pattern was detected: A || (A && ...). The expression is excessive or contains a logical error.
- V6105. Consider inspecting the loop expression. It is possible that different variables are used inside initializer and iterator.
- V6106. Casting expression to 'X' type before implicitly casting it to other type may be excessive or incorrect.
- V6107. The constant NN is being utilized. The resulting value could be inaccurate. Consider using the KK constant.
- V6108. Do not use real-type variables in 'for' loop counters.
- V6109. Potentially predictable seed is used in pseudo-random number generator.
- V6110. Using an environment variable could be unsafe or unreliable. Consider using trusted system property instead
- V6111. Potentially negative value is used as the size of an array.
- V6112. Calling the 'getClass' method repeatedly or on the value of the '.class' literal will always return the instance of the 'Class<Class>' type.
- V6113. Suspicious division. Absolute value of the left operand is less than the value of the right operand.
- V6114. The 'A' class containing Closeable members does not release the resources that the field is holding.
- V6115. Not all Closeable members are released inside the 'close' method.
- V6116. The class does not implement the Closeable interface, but it contains the 'close' method that releases resources.
- V6117. Possible overflow. The expression will be evaluated before casting. Consider casting one of the operands instead.
- V6118. The original exception object was swallowed. Cause of original exception could be lost.
- V6119. The result of '&' operator is always '0'.
- V6120. The result of the '&' operator is '0' because one of the operands is '0'.
- V6121. Return value is not always used. Consider inspecting the 'foo' method.
- V6122. The 'Y' (week year) pattern is used for date formatting. Check whether the 'y' (year) pattern was intended instead.
- V6123. Modified value of the operand is not used after the increment/decrement operation.
- V6124. Converting an integer literal to the type with a smaller value range will result in overflow.
- V6125. Calling the 'wait', 'notify', and 'notifyAll' methods outside of synchronized context will lead to 'IllegalMonitorStateException'.
Микрооптимизации (C++)
- V801. Decreased performance. It is better to redefine the N function argument as a reference. Consider replacing 'const T' with 'const .. &T' / 'const .. *T'.
- V802. On 32-bit/64-bit platform, structure size can be reduced from N to K bytes by rearranging the fields according to their sizes in decreasing order.
- V803. Decreased performance. It is more effective to use the prefix form of ++it. Replace iterator++ with ++iterator.
- V804. Decreased performance. The 'Foo' function is called twice in the specified expression to calculate length of the same string.
- V805. Decreased performance. It is inefficient to identify an empty string by using 'strlen(str) > 0' construct. A more efficient way is to check: str[0] != '\0'.
- V806. Decreased performance. The expression of strlen(MyStr.c_str()) kind can be rewritten as MyStr.length().
- V807. Decreased performance. Consider creating a pointer/reference to avoid using the same expression repeatedly.
- V808. An array/object was declared but was not utilized.
- V809. Verifying that a pointer value is not NULL is not required. The 'if (ptr != NULL)' check can be removed.
- V810. Decreased performance. The 'A' function was called several times with identical arguments. The result should possibly be saved to a temporary variable, which then could be used while calling the 'B' function.
- V811. Decreased performance. Excessive type casting: string -> char * -> string.
- V812. Decreased performance. Ineffective use of the 'count' function. It can possibly be replaced by the call to the 'find' function.
- V813. Decreased performance. The argument should probably be rendered as a constant pointer/reference.
- V814. Decreased performance. The 'strlen' function was called multiple times inside the body of a loop.
- V815. Decreased performance. Consider replacing the expression 'AA' with 'BB'.
- V816. It is more efficient to catch exception by reference rather than by value.
- V817. It is more efficient to search for 'X' character rather than a string.
- V818. It is more efficient to use an initialization list rather than an assignment operator.
- V819. Decreased performance. Memory is allocated and released multiple times inside the loop body.
- V820. The variable is not used after copying. Copying can be replaced with move/swap for optimization.
- V821. The variable can be constructed in a lower level scope.
- V822. Decreased performance. A new object is created, while a reference to an object is expected.
- V823. Decreased performance. Object may be created in-place in a container. Consider replacing methods: 'insert' -> 'emplace', 'push_*' -> 'emplace_*'.
- V824. It is recommended to use the 'make_unique/make_shared' function to create smart pointers.
- V825. Expression is equivalent to moving one unique pointer to another. Consider using 'std::move' instead.
- V826. Consider replacing standard container with a different one.
- V827. Maximum size of a vector is known at compile time. Consider pre-allocating it by calling reserve(N).
- V828. Decreased performance. Moving an object in a return statement prevents copy elision.
- V829. Lifetime of the heap-allocated variable is limited to the current function's scope. Consider allocating it on the stack instead.
- V830. Decreased performance. Consider replacing the use of 'std::optional::value()' with either the '*' or '->' operator.
- V831. Decreased performance. Consider replacing the call to the 'at()' method with the 'operator[]'.
- V832. It's better to use '= default;' syntax instead of empty body.
- V833. Using 'std::move' function's with const object disables move semantics.
- V834. Incorrect type of a loop variable. This leads to the variable binding to a temporary object instead of a range element.
- V835. Passing cheap-to-copy argument by reference may lead to decreased performance.
- V836. Expression's value is copied at the variable declaration. The variable is never modified. Consider declaring it as a reference.
- V837. The 'emplace' / 'insert' function does not guarantee that arguments will not be copied or moved if there is no insertion. Consider using the 'try_emplace' function.
- V838. Temporary object is constructed during lookup in ordered associative container. Consider using a container with heterogeneous lookup to avoid construction of temporary objects.
- V839. Function returns a constant value. This may interfere with move semantics.
Микрооптимизации (C#)
- V4001. Unity Engine. Boxing inside a frequently called method may decrease performance.
- V4002. Unity Engine. Avoid storing consecutive concatenations inside a single string in performance-sensitive context. Consider using StringBuilder to improve performance.
- V4003. Unity Engine. Avoid capturing variable in performance-sensitive context. This can lead to decreased performance.
- V4004. Unity Engine. New array object is returned from method or property. Using such member in performance-sensitive context can lead to decreased performance.
- V4005. Unity Engine. The expensive operation is performed inside method or property. Using such member in performance-sensitive context can lead to decreased performance.
- V4006. Unity Engine. Multiple operations between complex and numeric values. Prioritizing operations between numeric values can optimize execution time.
- V4007. Unity Engine. Avoid creating and destroying UnityEngine objects in performance-sensitive context. Consider activating and deactivating them instead.
Диагностика 64-битных ошибок (Viva64, C++)
- V101. Implicit assignment type conversion to memsize type.
- V102. Usage of non memsize type for pointer arithmetic.
- V103. Implicit type conversion from memsize type to 32-bit type.
- V104. Implicit type conversion to memsize type in an arithmetic expression.
- V105. N operand of '?:' operation: implicit type conversion to memsize type.
- V106. Implicit type conversion N argument of function 'foo' to memsize type.
- V107. Implicit type conversion N argument of function 'foo' to 32-bit type.
- V108. Incorrect index type: 'foo[not a memsize-type]'. Use memsize type instead.
- V109. Implicit type conversion of return value to memsize type.
- V110. Implicit type conversion of return value from memsize type to 32-bit type.
- V111. Call of function 'foo' with variable number of arguments. N argument has memsize type.
- V112. Dangerous magic number N used.
- V113. Implicit type conversion from memsize to double type or vice versa.
- V114. Dangerous explicit type pointer conversion.
- V115. Memsize type is used for throw.
- V116. Memsize type is used for catch.
- V117. Memsize type is used in the union.
- V118. malloc() function accepts a dangerous expression in the capacity of an argument.
- V119. More than one sizeof() operator is used in one expression.
- V120. Member operator[] of object 'foo' is declared with 32-bit type argument, but is called with memsize type argument.
- V121. Implicit conversion of the type of 'new' operator's argument to size_t type.
- V122. Memsize type is used in the struct/class.
- V123. Allocation of memory by the pattern "(X*)malloc(sizeof(Y))" where the sizes of X and Y types are not equal.
- V124. Function 'Foo' writes/reads 'N' bytes. The alignment rules and type sizes have been changed. Consider reviewing this value.
- V125. It is not advised to declare type 'T' as 32-bit type.
- V126. Be advised that the size of the type 'long' varies between LLP64/LP64 data models.
- V127. An overflow of the 32-bit variable is possible inside a long cycle which utilizes a memsize-type loop counter.
- V128. A variable of the memsize type is read from a stream. Consider verifying the compatibility of 32 and 64 bit versions of the application in the context of a stored data.
- V201. Explicit conversion from 32-bit integer type to memsize type.
- V202. Explicit conversion from memsize type to 32-bit integer type.
- V203. Explicit type conversion from memsize to double type or vice versa.
- V204. Explicit conversion from 32-bit integer type to pointer type.
- V205. Explicit conversion of pointer type to 32-bit integer type.
- V206. Explicit conversion from 'void *' to 'int *'.
- V207. A 32-bit variable is utilized as a reference to a pointer. A write outside the bounds of this variable may occur.
- V220. Suspicious sequence of types castings: memsize -> 32-bit integer -> memsize.
- V221. Suspicious sequence of types castings: pointer -> memsize -> 32-bit integer.
- V301. Unexpected function overloading behavior. See N argument of function 'foo' in derived class 'derived' and base class 'base'.
- V302. Member operator[] of 'foo' class has a 32-bit type argument. Use memsize-type here.
- V303. The function is deprecated in the Win64 system. It is safer to use the 'foo' function.
Реализовано по запросам пользователей (C++)
- V2001. Consider using the extended version of the 'foo' function here.
- V2002. Consider using the 'Ptr' version of the 'foo' function here.
- V2003. Explicit conversion from 'float/double' type to signed integer type.
- V2004. Explicit conversion from 'float/double' type to unsigned integer type.
- V2005. C-style explicit type casting is utilized. Consider using: static_cast/const_cast/reinterpret_cast.
- V2006. Implicit type conversion from enum type to integer type.
- V2007. This expression can be simplified. One of the operands in the operation equals NN. Probably it is a mistake.
- V2008. Cyclomatic complexity: NN. Consider refactoring the 'Foo' function.
- V2009. Consider passing the 'Foo' argument as a pointer/reference to const.
- V2010. Handling of two different exception types is identical.
- V2011. Consider inspecting signed and unsigned function arguments. See NN argument of function 'Foo' in derived class and base class.
- V2012. Possibility of decreased performance. It is advised to pass arguments to std::unary_function/std::binary_function template as references.
- V2013. Consider inspecting the correctness of handling the N argument in the 'Foo' function.
- V2014. Don't use terminating functions in library code.
- V2015. An identifier declared in an inner scope should not hide an identifier in an outer scope.
- V2016. Consider inspecting the function call. The function was annotated as dangerous.
- V2017. String literal is identical to variable name. It is possible that the variable should be used instead of the string literal.
- V2018. Cast should not remove 'const' qualifier from the type that is pointed to by a pointer or a reference.
- V2019. Cast should not remove 'volatile' qualifier from the type that is pointed to by a pointer or a reference.
- V2020. The loop body contains the 'break;' / 'continue;' statement. This may complicate the control flow.
- V2021. Using assertions may cause the abnormal program termination in undesirable contexts.
- V2022. Implicit type conversion from integer type to enum type.
Cтандарт MISRA
- V2501. MISRA. Octal constants should not be used.
- V2502. MISRA. The 'goto' statement should not be used.
- V2503. MISRA. Implicitly specified enumeration constants should be unique – consider specifying non-unique constants explicitly.
- V2504. MISRA. Size of an array is not specified.
- V2505. MISRA. The 'goto' statement shouldn't jump to a label declared earlier.
- V2506. MISRA. A function should have a single point of exit at the end.
- V2507. MISRA. The body of a loop\conditional statement should be enclosed in braces.
- V2508. MISRA. The function with the 'atof/atoi/atol/atoll' name should not be used.
- V2509. MISRA. The function with the 'abort/exit/getenv/system' name should not be used.
- V2510. MISRA. The function with the 'qsort/bsearch' name should not be used.
- V2511. MISRA. Memory allocation and deallocation functions should not be used.
- V2512. MISRA. The macro with the 'setjmp' name and the function with the 'longjmp' name should not be used.
- V2513. MISRA. Unbounded functions performing string operations should not be used.
- V2514. MISRA. Unions should not be used.
- V2515. MISRA. Declaration should contain no more than two levels of pointer nesting.
- V2516. MISRA. The 'if' ... 'else if' construct should be terminated with an 'else' statement.
- V2517. MISRA. Literal suffixes should not contain lowercase characters.
- V2518. MISRA. The 'default' label should be either the first or the last label of a 'switch' statement.
- V2519. MISRA. Every 'switch' statement should have a 'default' label, which, in addition to the terminating 'break' statement, should contain either a statement or a comment.
- V2520. MISRA. Every switch-clause should be terminated by an unconditional 'break' or 'throw' statement.
- V2521. MISRA. Only the first member of enumerator list should be explicitly initialized, unless all members are explicitly initialized.
- V2522. MISRA. The 'switch' statement should have 'default' as the last label.
- V2523. MISRA. All integer constants of unsigned type should have 'u' or 'U' suffix.
- V2524. MISRA. A switch-label should only appear at the top level of the compound statement forming the body of a 'switch' statement.
- V2525. MISRA. Every 'switch' statement should contain non-empty switch-clauses.
- V2526. MISRA. The functions from time.h/ctime should not be used.
- V2527. MISRA. A switch-expression should not have Boolean type. Consider using of 'if-else' construct.
- V2528. MISRA. The comma operator should not be used.
- V2529. MISRA. Any label should be declared in the same block as 'goto' statement or in any block enclosing it.
- V2530. MISRA. Any loop should be terminated with no more than one 'break' or 'goto' statement.
- V2531. MISRA. Expression of essential type 'foo' should not be explicitly cast to essential type 'bar'.
- V2532. MISRA. String literal should not be assigned to object unless it has type of pointer to const-qualified char.
- V2533. MISRA. C-style and functional notation casts should not be performed.
- V2534. MISRA. The loop counter should not have floating-point type.
- V2535. MISRA. Unreachable code should not be present in the project.
- V2536. MISRA. Function should not contain labels not used by any 'goto' statements.
- V2537. MISRA. Functions should not have unused parameters.
- V2538. MISRA. The value of uninitialized variable should not be used.
- V2539. MISRA. Class destructor should not exit with an exception.
- V2540. MISRA. Arrays should not be partially initialized.
- V2541. MISRA. Function should not be declared implicitly.
- V2542. MISRA. Function with a non-void return type should return a value from all exit paths.
- V2543. MISRA. Value of the essential character type should be used appropriately in the addition/subtraction operations.
- V2544. MISRA. The values used in expressions should have appropriate essential types.
- V2545. MISRA. Conversion between pointers of different object types should not be performed.
- V2546. MISRA. Expression resulting from the macro expansion should be surrounded by parentheses.
- V2547. MISRA. The return value of non-void function should be used.
- V2548. MISRA. The address of an object with local scope should not be passed out of its scope.
- V2549. MISRA. Pointer to FILE should not be dereferenced.
- V2550. MISRA. Floating-point values should not be tested for equality or inequality.
- V2551. MISRA. Variable should be declared in a scope that minimizes its visibility.
- V2552. MISRA. Expressions with enum underlying type should have values corresponding to the enumerators of the enumeration.
- V2553. MISRA. Unary minus operator should not be applied to an expression of the unsigned type.
- V2554. MISRA. Expression containing increment (++) or decrement (--) should not have other side effects.
- V2555. MISRA. Incorrect shifting expression.
- V2556. MISRA. Use of a pointer to FILE when the associated stream has already been closed.
- V2557. MISRA. Operand of sizeof() operator should not have other side effects.
- V2558. MISRA. A pointer/reference parameter in a function should be declared as pointer/reference to const if the corresponding object was not modified.
- V2559. MISRA. Subtraction, >, >=, <, <= should be applied only to pointers that address elements of the same array.
- V2560. MISRA. There should be no user-defined variadic functions.
- V2561. MISRA. The result of an assignment expression should not be used.
- V2562. MISRA. Expressions with pointer type should not be used in the '+', '-', '+=' and '-=' operations.
- V2563. MISRA. Array indexing should be the only form of pointer arithmetic and it should be applied only to objects defined as an array type.
- V2564. MISRA. There should be no implicit integral-floating conversion.
- V2565. MISRA. A function should not call itself either directly or indirectly.
- V2566. MISRA. Constant expression evaluation should not result in an unsigned integer wrap-around.
- V2567. MISRA. Cast should not remove 'const' / 'volatile' qualification from the type that is pointed to by a pointer or a reference.
- V2568. MISRA. Both operands of an operator should be of the same type category.
- V2569. MISRA. The 'operator &&', 'operator ||', 'operator ,' and the unary 'operator &' should not be overloaded.
- V2570. MISRA. Operands of the logical '&&' or the '||' operators, the '!' operator should have 'bool' type.
- V2571. MISRA. Conversions between pointers to objects and integer types should not be performed.
- V2572. MISRA. Value of the expression should not be converted to the different essential type or the narrower essential type.
- V2573. MISRA. Identifiers that start with '__' or '_[A-Z]' are reserved.
- V2574. MISRA. Functions should not be declared at block scope.
- V2575. MISRA. The global namespace should only contain 'main', namespace declarations and 'extern "C"' declarations.
- V2576. MISRA. The identifier 'main' should not be used for a function other than the global function 'main'.
- V2577. MISRA. The function argument corresponding to a parameter declared to have an array type should have an appropriate number of elements.
- V2578. MISRA. An identifier with array type passed as a function argument should not decay to a pointer.
- V2579. MISRA. Macro should not be defined with the same name as a keyword.
- V2580. MISRA. The 'restrict' specifier should not be used.
- V2581. MISRA. Single-line comments should not end with a continuation token.
- V2582. MISRA. Block of memory should only be freed if it was allocated by a Standard Library function.
- V2583. MISRA. Line whose first token is '#' should be a valid preprocessing directive.
- V2584. MISRA. Expression used in condition should have essential Boolean type.
- V2585. MISRA. Casts between a void pointer and an arithmetic type should not be performed.
- V2586. MISRA. Flexible array members should not be declared.
- V2587. MISRA. The '//' and '/*' character sequences should not appear within comments.
- V2588. MISRA. All memory or resources allocated dynamically should be explicitly released.
- V2589. MISRA. Casts between a pointer and a non-integer arithmetic type should not be performed.
- V2590. MISRA. Conversions should not be performed between pointer to function and any other type.
- V2591. MISRA. Bit fields should only be declared with explicitly signed or unsigned integer type
- V2592. MISRA. An identifier declared in an inner scope should not hide an identifier in an outer scope.
- V2593. MISRA. Single-bit bit fields should not be declared as signed type.
- V2594. MISRA. Controlling expressions should not be invariant.
- V2595. MISRA. Array size should be specified explicitly when array declaration uses designated initialization.
- V2596. MISRA. The value of a composite expression should not be assigned to an object with wider essential type.
- V2597. MISRA. Cast should not convert pointer to function to any other pointer type.
- V2598. MISRA. Variable length array types are not allowed.
- V2599. MISRA. The standard signal handling functions should not be used.
- V2600. MISRA. The standard input/output functions should not be used.
- V2601. MISRA. Functions should be declared in prototype form with named parameters.
- V2602. MISRA. Octal and hexadecimal escape sequences should be terminated.
- V2603. MISRA. The 'static' keyword shall not be used between [] in the declaration of an array parameter.
- V2604. MISRA. Features from <stdarg.h> should not be used.
- V2605. MISRA. Features from <tgmath.h> should not be used.
- V2606. MISRA. There should be no attempt to write to a stream that has been opened for reading.
- V2607. MISRA. Inline functions should be declared with the static storage class.
- V2608. MISRA. The 'static' storage class specifier should be used in all declarations of object and functions that have internal linkage.
- V2609. MISRA. There should be no occurrence of undefined or critical unspecified behaviour.
- V2610. MISRA. The ', " or \ characters and the /* or // character sequences should not occur in a header file name.
- V2611. MISRA. Casts between a pointer to an incomplete type and any other type shouldn't be performed.
- V2612. MISRA. Array element should not be initialized more than once.
- V2613. MISRA. Operand that is a composite expression has more narrow essential type than the other operand.
- V2614. MISRA. External identifiers should be distinct.
- V2615. MISRA. A compatible declaration should be visible when an object or function with external linkage is defined.
- V2616. MISRA. All conditional inclusion preprocessor directives should reside in the same file as the conditional inclusion directive to which they are related.
- V2617. MISRA. Object should not be assigned or copied to an overlapping object.
- V2618. MISRA. Identifiers declared in the same scope and name space should be distinct.
- V2619. MISRA. Typedef names should be unique across all name spaces.
- V2620. MISRA. Value of a composite expression should not be cast to a different essential type category or a wider essential type.
- V2621. MISRA. Tag names should be unique across all name spaces.
- V2622. MISRA. External object or function should be declared once in one and only one file.
- V2623. MISRA. Macro identifiers should be distinct.
- V2624. MISRA. The initializer for an aggregate or union should be enclosed in braces.
- V2625. MISRA. Identifiers that define objects or functions with external linkage shall be unique.
Стандарт AUTOSAR
- V3501. AUTOSAR. Octal constants should not be used.
- V3502. AUTOSAR. Size of an array is not specified.
- V3503. AUTOSAR. The 'goto' statement shouldn't jump to a label declared earlier.
- V3504. AUTOSAR. The body of a loop\conditional statement should be enclosed in braces.
- V3505. AUTOSAR. The function with the 'atof/atoi/atol/atoll' name should not be used.
- V3506. AUTOSAR. The function with the 'abort/exit/getenv/system' name should not be used.
- V3507. AUTOSAR. The macro with the 'setjmp' name and the function with the 'longjmp' name should not be used.
- V3508. AUTOSAR. Unbounded functions performing string operations should not be used.
- V3509. AUTOSAR. Unions should not be used.
- V3510. AUTOSAR. Declaration should contain no more than two levels of pointer nesting.
- V3511. AUTOSAR. The 'if' ... 'else if' construct should be terminated with an 'else' statement.
- V3512. AUTOSAR. Literal suffixes should not contain lowercase characters.
- V3513. AUTOSAR. Every switch-clause should be terminated by an unconditional 'break' or 'throw' statement.
- V3514. AUTOSAR. The 'switch' statement should have 'default' as the last label.
- V3515. AUTOSAR. All integer constants of unsigned type should have 'U' suffix.
- V3516. AUTOSAR. A switch-label should only appear at the top level of the compound statement forming the body of a 'switch' statement.
- V3517. AUTOSAR. The functions from time.h/ctime should not be used.
- V3518. AUTOSAR. A switch-expression should not have Boolean type. Consider using of 'if-else' construct.
- V3519. AUTOSAR. The comma operator should not be used.
- V3520. AUTOSAR. Any label should be declared in the same block as 'goto' statement or in any block enclosing it.
- V3521. AUTOSAR. The loop counter should not have floating-point type.
- V3522. AUTOSAR. Unreachable code should not be present in the project.
- V3523. AUTOSAR. Functions should not have unused parameters.
- V3524. AUTOSAR. The value of uninitialized variable should not be used.
- V3525. AUTOSAR. Function with a non-void return type should return a value from all exit paths.
- V3526. AUTOSAR. Expression resulting from the macro expansion should be surrounded by parentheses.
- V3527. AUTOSAR. The return value of non-void function should be used.
- V3528. AUTOSAR. The address of an object with local scope should not be passed out of its scope.
- V3529. AUTOSAR. Floating-point values should not be tested for equality or inequality.
- V3530. AUTOSAR. Variable should be declared in a scope that minimizes its visibility.
- V3531. AUTOSAR. Expressions with enum underlying type should have values corresponding to the enumerators of the enumeration.
- V3532. AUTOSAR. Unary minus operator should not be applied to an expression of the unsigned type.
- V3533. AUTOSAR. Expression containing increment (++) or decrement (--) should not have other side effects.
- V3534. AUTOSAR. Incorrect shifting expression.
- V3535. AUTOSAR. Operand of sizeof() operator should not have other side effects.
- V3536. AUTOSAR. A pointer/reference parameter in a function should be declared as pointer/reference to const if the corresponding object was not modified.
- V3537. AUTOSAR. Subtraction, >, >=, <, <= should be applied only to pointers that address elements of the same array.
- V3538. AUTOSAR. The result of an assignment expression should not be used.
- V3539. AUTOSAR. Array indexing should be the only form of pointer arithmetic and it should be applied only to objects defined as an array type.
- V3540. AUTOSAR. There should be no implicit integral-floating conversion.
- V3541. AUTOSAR. A function should not call itself either directly or indirectly.
- V3542. AUTOSAR. Constant expression evaluation should not result in an unsigned integer wrap-around.
- V3543. AUTOSAR. Cast should not remove 'const' / 'volatile' qualification from the type that is pointed to by a pointer or a reference.
- V3544. AUTOSAR. The 'operator &&', 'operator ||', 'operator ,' and the unary 'operator &' should not be overloaded.
- V3545. AUTOSAR. Operands of the logical '&&' or the '||' operators, the '!' operator should have 'bool' type.
- V3546. AUTOSAR. Conversions between pointers to objects and integer types should not be performed.
- V3547. AUTOSAR. Identifiers that start with '__' or '_[A-Z]' are reserved.
- V3548. AUTOSAR. Functions should not be declared at block scope.
- V3549. AUTOSAR. The global namespace should only contain 'main', namespace declarations and 'extern "C"' declarations.
- V3550. AUTOSAR. The identifier 'main' should not be used for a function other than the global function 'main'.
- V3551. AUTOSAR. An identifier with array type passed as a function argument should not decay to a pointer.
- V3552. AUTOSAR. Cast should not convert a pointer to a function to any other pointer type, including a pointer to function type.
- V3553. AUTOSAR. The standard signal handling functions should not be used.
- V3554. AUTOSAR. The standard input/output functions should not be used.
- V3555. AUTOSAR. The 'static' storage class specifier should be used in all declarations of functions that have internal linkage.
Стандарт OWASP (C++)
- V5001. OWASP. It is highly probable that the semicolon ';' is missing after 'return' keyword.
- V5002. OWASP. An empty exception handler. Silent suppression of exceptions can hide the presence of bugs in source code during testing.
- V5003. OWASP. The object was created but it is not being used. The 'throw' keyword could be missing.
- V5004. OWASP. Consider inspecting the expression. Bit shifting of the 32-bit value with a subsequent expansion to the 64-bit type.
- V5005. OWASP. A value is being subtracted from the unsigned variable. This can result in an overflow. In such a case, the comparison operation can potentially behave unexpectedly.
- V5006. OWASP. More than N bits are required to store the value, but the expression evaluates to the T type which can only hold K bits.
- V5007. OWASP. Consider inspecting the loop expression. It is possible that the 'i' variable should be incremented instead of the 'n' variable.
- V5008. OWASP. Classes should always be derived from std::exception (and alike) as 'public'.
- V5009. OWASP. Unchecked tainted data is used in expression.
- V5010. OWASP. The variable is incremented in the loop. Undefined behavior will occur in case of signed integer overflow.
- V5011. OWASP. Possible overflow. Consider casting operands, not the result.
- V5012. OWASP. Potentially unsafe double-checked locking.
- V5013. OWASP. Storing credentials inside source code can lead to security issues.
- V5014. OWASP. Cryptographic function is deprecated. Its use can lead to security issues. Consider switching to an equivalent newer function.
Стандарт OWASP (C#)
- V5601. OWASP. Storing credentials inside source code can lead to security issues.
- V5602. OWASP. The object was created but it is not being used. The 'throw' keyword could be missing.
- V5603. OWASP. The original exception object was swallowed. Stack of original exception could be lost.
- V5604. OWASP. Potentially unsafe double-checked locking. Use volatile variable(s) or synchronization primitives to avoid this.
- V5605. OWASP. Unsafe invocation of event, NullReferenceException is possible. Consider assigning event to a local variable before invoking it.
- V5606. OWASP. An exception handling block does not contain any code.
- V5607. OWASP. Exception classes should be publicly accessible.
- V5608. OWASP. Possible SQL injection. Potentially tainted data is used to create SQL command.
- V5609. OWASP. Possible path traversal vulnerability. Potentially tainted data is used as a path.
- V5610. OWASP. Possible XSS vulnerability. Potentially tainted data might be used to execute a malicious script.
- V5611. OWASP. Potential insecure deserialization vulnerability. Potentially tainted data is used to create an object using deserialization.
- V5612. OWASP. Do not use old versions of SSL/TLS protocols as it may cause security issues.
- V5613. OWASP. Use of outdated cryptographic algorithm is not recommended.
- V5614. OWASP. Potential XXE vulnerability. Insecure XML parser is used to process potentially tainted data.
- V5615. OWASP. Potential XEE vulnerability. Insecure XML parser is used to process potentially tainted data.
- V5616. OWASP. Possible command injection. Potentially tainted data is used to create OS command.
- V5617. OWASP. Assigning potentially negative or large value as timeout of HTTP session can lead to excessive session expiration time.
- V5618. OWASP. Possible server-side request forgery. Potentially tainted data is used in the URL.
- V5619. OWASP. Possible log injection. Potentially tainted data is written into logs.
- V5620. OWASP. Possible LDAP injection. Potentially tainted data is used in a search filter.
- V5621. OWASP. Error message contains potentially sensitive data that may be exposed.
- V5622. OWASP. Possible XPath injection. Potentially tainted data is used in the XPath expression.
- V5623. OWASP. Possible open redirect vulnerability. Potentially tainted data is used in the URL.
- V5624. OWASP. Use of potentially tainted data in configuration may lead to security issues.
- V5625. OWASP. Referenced package contains vulnerability.
- V5626. OWASP. Possible ReDoS vulnerability. Potentially tainted data is processed by regular expression that contains an unsafe pattern.
- V5627. OWASP. Possible NoSQL injection. Potentially tainted data is used to create query.
- V5628. OWASP. Possible Zip Slip vulnerability. Potentially tainted data is used in the path to extract the file.
Стандарт OWASP (Java)
- V5301. OWASP. An exception handling block does not contain any code.
- V5302. OWASP. Exception classes should be publicly accessible.
- V5303. OWASP. The object was created but it is not being used. The 'throw' keyword could be missing.
- V5304. OWASP. Unsafe double-checked locking.
- V5305. OWASP. Storing credentials inside source code can lead to security issues.
- V5306. OWASP. The original exception object was swallowed. Cause of original exception could be lost.
- V5307. OWASP. Potentially predictable seed is used in pseudo-random number generator.
- V5308. OWASP. Possible overflow. The expression will be evaluated before casting. Consider casting one of the operands instead.
- V5309. OWASP. Possible SQL injection. Potentially tainted data is used to create SQL command.
Проблемы при работе анализатора кода
- V001. A code fragment from 'file' cannot be analyzed.
- V002. Some diagnostic messages may contain incorrect line number.
- V003. Unrecognized error found...
- V004. Diagnostics from the 64-bit rule set are not entirely accurate without the appropriate 64-bit compiler. Consider utilizing 64-bit compiler if possible.
- V005. Cannot determine active configuration for project. Please check projects and solution configurations.
- V006. File cannot be processed. Analysis aborted by timeout.
- V007. Deprecated CLR switch was detected. Incorrect diagnostics are possible.
- V008. Unable to start the analysis on this file.
- V010. Analysis of 'Makefile/Utility' type projects is not supported in this tool. Use direct analyzer integration or compiler monitoring instead.
- V011. Presence of #line directives may cause some diagnostic messages to have incorrect file name and line number.
- V012. Some warnings could have been disabled.
- V013. Intermodular analysis may be incomplete, as it is not run on all source files.
- V014. The version of your suppress file is outdated. Appending new suppressed messages to it is not possible. Consider re-generating your suppress file to continue updating it.
- V015. All analyzer messages were filtered out or marked as false positive. Use filter buttons or 'Don't Check Files' settings to enable message display.
- V016. User annotation was not applied to a virtual function. To force the annotation, use the 'enable_on_virtual' flag.
- V017. The analyzer terminated abnormally due to lack of memory.
- V018. False Alarm marks without hash codes were ignored because the 'V_HASH_ONLY' option is enabled.
- V019. Error occurred while working with the user annotation mechanism.
- V020. Error occurred while working with rules configuration files.
- V051. Some of the references in project are missing or incorrect. The analysis results could be incomplete. Consider making the project fully compilable and building it before analysis.
- V052. A critical error had occurred.
- V061. An error has occurred.
- V062. Failed to run analyzer core. Make sure the correct 64-bit Java 11 or higher executable is used, or specify it manually.
- V063. Analysis aborted by timeout.
Как ввести лицензию PVS-Studio и что делать дальше
- Что включает в себя лицензия
- Способы активации через графический интерфейс
- Способы активации через интерфейс командной строки
- Быстрый старт или что дальше?
Анализатор PVS-Studio позволяет производить анализ проектов, написанных на языках программирования C, C++, C# и Java. Он может быть запущен на операционных системах Windows, Linux и macOS. Перед началом использования анализатора необходимо произвести активацию лицензии. В связи с большим числом сценариев использования продукта (например, в IDE, на локальных и облачных CI/CD), далее будут перечислены все возможные способы активации. Перейдите в раздел, который Вам подходит, и следуйте инструкции.
Важно. Все действия выполняются после установки анализатора. Вы можете скачать его на странице "Скачать PVS-Studio".
Что включает в себя лицензия
Лицензия анализатора состоит из имени пользователя и 16-символьного лицензионного ключа в формате "ХХХХ-ХХХХ-ХХХХ-ХХХХ". Если у вас отсутствует лицензия, ее можно получить через форму запроса триальной версии.
Ниже приведен пример того, как может выглядеть лицензионная информация:
JohnSmith <--- Имя пользователя
ASD1-DAS3-5KK3-LODR <--- Лицензионный ключ
Способы активации через графический интерфейс
PVS-Studio Installer
Вы можете ввести лицензию во время установки PVS-Studio. В процессе установки вам предложат запросить лицензию или ввести существующую.
![EnterLicense_ru/image1.png](https://import.viva64.com/docx/manual/EnterLicense_ru/image1.png)
Выберите пункт I have a license and want to activate it и нажмите Next:
![EnterLicense_ru/image2.png](https://import.viva64.com/docx/manual/EnterLicense_ru/image2.png)
В поле 'License Name' необходимо подставить имя пользователя, а в 'License Key' – лицензионный ключ из своей лицензии. Если вы ввели валидные данные, то у вас отобразится сообщение с данными лицензии.
Microsoft Visual Studio
Перейдите в меню Visual Studio Extensions > PVS-Studio > Options (до 2015 версии Visual Studio просто PVS-Studio > Options):
![EnterLicense_ru/image3.png](https://import.viva64.com/docx/manual/EnterLicense_ru/image3.png)
После этого справа в меню перейдите на страницу PVS-Studio > Registration:
![EnterLicense_ru/image4.png](https://import.viva64.com/docx/manual/EnterLicense_ru/image4.png)
В поле 'Name' необходимо подставить имя пользователя, а в 'LicenseKey' – лицензионный ключ из своей лицензии. Если вы ввели валидные данные, то у вас отобразится сообщение с данными лицензии:
![EnterLicense_ru/image5.png](https://import.viva64.com/docx/manual/EnterLicense_ru/image5.png)
В случае если введённые данные лицензии недействительны, то вам также отобразится уведомление об этом:
![EnterLicense_ru/image6.png](https://import.viva64.com/docx/manual/EnterLicense_ru/image6.png)
JetBrains IntelliJ IDEA / Rider / CLion
Для ввода лицензии анализатора необходимо открыть любой проект, после чего открыть окно настроек вашей IDE:
![EnterLicense_ru/image7.png](https://import.viva64.com/docx/manual/EnterLicense_ru/image7.png)
В открывшемся окне настроек плагина перейти на страницу PVS-Studio > Registration.
В поле 'Name' необходимо подставить имя пользователя, а в 'License Key' – лицензионный ключ из своей лицензии:
![EnterLicense_ru/image8.png](https://import.viva64.com/docx/manual/EnterLicense_ru/image8.png)
Если вы ввели правильную лицензию, то надпись 'Invalid License' будет заменена на 'Valid License'. Для подтверждения и сохранения введённой лицензии нажмите кнопку Apply или OK.
C and C++ Compiler Monitoring UI
Перейдите в меню утилиты Tools > Options > Registration, чтобы ввести лицензию:
![EnterLicense_ru/image9.png](https://import.viva64.com/docx/manual/EnterLicense_ru/image9.png)
В поле 'Name' необходимо подставить имя пользователя, а в 'LicenseKey' – лицензионный ключ из своей лицензии.
Visual Studio Code
Для ввода лицензии в Visual Studio Code откройте View > Command Palette.
![EnterLicense_ru/image10.png](https://import.viva64.com/docx/manual/EnterLicense_ru/image10.png)
Введите в строку 'PVS-Studio: Show settings' и откройте их.
![EnterLicense_ru/image11.png](https://import.viva64.com/docx/manual/EnterLicense_ru/image11.png)
В открывшемся окне выберите вкладку 'License'.
![EnterLicense_ru/image12.png](https://import.viva64.com/docx/manual/EnterLicense_ru/image12.png)
В поле 'User name' необходимо подставить имя пользователя, а в 'Key' – лицензионный ключ из своей лицензии. Если вы ввели валидные данные, то у вас отобразится сообщение с данными лицензии:
![EnterLicense_ru/image13.png](https://import.viva64.com/docx/manual/EnterLicense_ru/image13.png)
Qt Creator
Для ввода лицензии в Qt Creator перейдите в Analyze > PVS-Studio > Options...
![EnterLicense_ru/image14.png](https://import.viva64.com/docx/manual/EnterLicense_ru/image14.png)
Далее выберите PVS-Studio и перейдите на вкладку Registration. В поле 'Name' необходимо подставить имя пользователя, а в 'License Key' – лицензионный ключ из своей лицензии. Если вы ввели валидные данные, то у вас отобразится сообщение с данными лицензии:
![EnterLicense_ru/image15.png](https://import.viva64.com/docx/manual/EnterLicense_ru/image15.png)
В случае если введённые данные лицензии недействительны, то вам также отобразится уведомление об этом:
![EnterLicense_ru/image16.png](https://import.viva64.com/docx/manual/EnterLicense_ru/image16.png)
Для подтверждения и сохранения введённой лицензии нажмите кнопку Apply или OK.
Способы активации через интерфейс командной строки
Windows
На Windows, когда нет возможности ввести лицензию через GUI, можно воспользоваться самим анализатором в специальном режиме.
Строка запуска может выглядеть следующим образом:
PVS-Studio_Cmd.exe credentials --userName %USER_NAME% ^
--licenseKey %LICENSE_KEY%
Вместо переменной 'USER_NAME' необходимо подставить имя пользователя, а вместо 'LICENSE_KEY' – лицензионный ключ из своей лицензии.
При таком запуске анализатор запишет лицензию в файл настроек с расположением по умолчанию: "%APPDATA%/PVS-Studio/Settings.xml". Если файла настроек не существует, он будет создан. Используя флаг ‑‑settings, можно указать путь до файла настроек в нестандартном расположении.
С помощью флага ‑‑licInfo можно получить информацию о текущей лицензии.
Linux/macOS
При использовании анализатора на Linux/macOS платформах, когда нет возможности ввести лицензию при помощи GUI, используется специальная утилита pvs-studio-analyzer.
На Linux / macOS строка запуска может выглядеть следующим образом:
pvs-studio-analyzer credentials ${USER_NAME} ${LICENSE_KEY}
Вместо переменной 'USER_NAME' необходимо подставить имя пользователя, а вместо 'LICENSE_KEY' – лицензионный ключ из своей лицензии.
При таком запуске анализатор запишет лицензию в файл настроек с расположением по умолчанию: "~/.config/PVS-Studio/PVS-Studio.lic". Если файла настроек не существует, он будет создан.
Java анализатор
Поскольку Java анализатор может быть установлен независимо от других компонентов PVS-Studio, активацию лицензии можно также произвести через плагины для сборочных систем (Maven, Gradle) и ядро Java анализатора.
При использовании Maven команда для ввода лицензии может выглядеть следующим образом:
mvn pvsstudio:pvsCredentials "-Dpvsstudio.userName=${USER_NAME}" \
"-Dpvsstudio.licenseKey=${LICENSE_KEY}"
При использовании Gradle активация происходит с помощью следующей команды:
./gradlew pvsCredentials "-Ppvsstudio.userName=${USER_NAME}" \
"-Ppvsstudio.licenseKey=${LICENSE_KEY}"
При использовании ядра Java анализатора из консоли активировать лицензию возможно командой:
java -jar pvs-studio.jar --activate-license --user-name $USER_NAME \
--license-key $LICENSE_KEY
Вместо переменной 'USER_NAME' необходимо подставить имя пользователя, а вместо 'LICENSE_KEY' – лицензионный ключ из своей лицензии.
Быстрый старт или что дальше?
Способы запуска анализатора приведены на соответствующих страницах:
- Знакомство со статическим анализатором кода PVS-Studio на Windows
- Как запустить PVS-Studio в Linux и macOS (C, C++)
- Установка PVS-Studio C# на Linux и macOS
- Работа с ядром Java анализатора из командной строки
- Работа PVS-Studio в Visual Studio
- Работа PVS-Studio в JetBrains Rider и CLion
- Работа PVS-Studio в IntelliJ IDEA и Android Studio
- Использование PVS-Studio в среде Qt Creator
- PVS-Studio для Embedded-разработки
- Проверка Unreal Engine проектов
- Проверка проектов Visual Studio / MSBuild / .NET Core из командной строки с помощью PVS-Studio
- Анализ C++ проектов на основе JSON Compilation Database
- Проверка проектов независимо от сборочной системы (C и C++)
- Интеграция PVS-Studio в CMake с помощью CMake-модуля
- Интеграция PVS-Studio Java в сборочную систему Gradle
- Интеграция PVS-Studio Java в сборочную систему Maven
Ознакомительный режим PVS-Studio
После загрузки дистрибутива PVS-Studio и запроса ключа для знакомства с инструментом, вы получаете полнофункциональную версию, которая работает одну неделю. В этой версии нет совершенно никаких ограничений – это абсолютно полноценная лицензия. При заполнении формы вы можете выбрать, какой тип лицензии хотели бы испробовать: Team License или Enterprise License.
Отличия Enterprise License от Team License представлены на этой странице.
Если вам не хватило недели на знакомство с инструментом – просто напишите нам об этом в ответном письме. И мы пришлем еще один ключ.
Системные требования анализатора PVS-Studio
PVS-Studio работает на Windows (x86-64 и ARM), Linux (x86-64) и macOS (Intel и Apple Silicon). Поддерживается анализ кода для кроссплатформенных компиляторов, предназначенных для 32-битных, 64-битных, встраиваемых ARM платформ и других.
PVS-Studio требует как минимум 2 GB оперативной памяти (рекомендуется 4 GB и больше) для каждого процессорного ядра, когда анализатор работает на многоядерной системе (чем больше ядер, тем быстрее работает анализ кода).
Поддерживаемые языки программирования и компиляторы
Список поддерживаемых анализатором языков программирования и компиляторов доступен здесь.
Минимально поддерживаемая версия GCC — 4.2.
Кроссплатформенные IDE
Плагин PVS-Studio может быть интегрирован в:
- VS Code
- QtCreator:
- с 9 по 14 версии включительно;
- версия 14 для устройств с Apple Silicon
- Rider (версия 2022.2 и выше)
- CLion (версия 2022.2 и выше)
- IDEA и Android Studio (версия 2022.2 и выше)
Для всех IDE (кроме IDEA и Android Studio) необходимо иметь в системе установленное ядро анализатора для соответствующего языка (C, C++, C# или Java).
Windows
Поддерживаются Windows 11, Windows 10, Windows 8, Windows Server 2019, Windows Server 2016 и Windows Server 2012. PVS-Studio работает как на 64-битных версиях Windows, так и на версиях для ARM.
Для работы PVS-Studio требуется .NET Framework версии 4.7.2 или выше (будет автоматически установлен при установке PVS-Studio, если подходящей версии нет в системе).
Для анализа .NET, .NET Standard и .NET Framework SDK-style проектов требуется .NET SDK 9.0. Для анализа классических .NET Framework проектов достаточно .NET Framework 4.7.2 при наличии установленных в системе Visual Studio или MSBuild версий 2017, 2019 или 2022.
Плагин PVS-Studio может быть интегрирован в Microsoft Visual Studio 2022, 2019, 2017, 2015, 2013, 2012, 2010. Для анализа C и C++ кода для встраиваемых систем соответствующие компиляторы должны быть установлены в системе, на которой запускается анализатор.
Примечание: интеграция с Visual Studio 2022 для версий 17.12 и выше поддерживается, начиная с версии PVS-Studio 7.33.
Linux
PVS-Studio работает в 64-битных дистрибутивах Linux с ядром версий 3.2.0 и выше. Для анализа C и C++ проектов для Linux, кросс-платформенных приложений или встраиваемых систем, соответствующие компиляторы должны быть установлены в системе. Для утилиты оповещения команд разработчиков blame-notifier должен быть установлен .NET Runtime 9.0.
Список протестированных дистрибутивов, на которых работа PVS-Studio гарантируется:
- Arch Linux
- Astra Linux
- CentOS
- Debian GNU/Linux
- Fedora
- Linux Mint
- openSUSE
- Ubuntu
- РЕД ОС
РЕД ОС
Анализаторы PVS-Studio были проверены на совместимость и корректную работу с операционными системами РЕД ОС 7.3 и РЕД ОС 8.
macOS
PVS-Studio работает на процессорах Intel (x86-64) в macOS 10.13.2 High Sierra и выше. Также поддерживается работа на процессорах Apple Silicon (arm64) в macOS 11 Big Sur и выше. Для анализа C и C++ кода соответствующие компиляторы должны быть установлены в системе. Для утилиты оповещения команд разработчиков blame-notifier должен быть установлен .NET Runtime 9.0.
Java
PVS-Studio для Java работает на Windows (x86-64 и ARM), Linux (x86-64) и macOS (Intel и Apple Silicon). Java 11 (64-битная) является минимальной версией для работы анализатора. Анализируемый проект может использовать любую версию Java.
Технологии, используемые в PVS-Studio (соответствует ГОСТ Р 71207—2024)
- Определения
- Поддерживаемые языки и методы анализа
- Анализ программы на синтаксическом уровне
- Внутрипроцедурный анализ потоков данных и управления
- Межпроцедурный и межмодульный контекстно-чувствительный анализ потока данных
- Чувствительный к путям выполнения анализ потоков данных и управления
- Межпроцедурный и межмодульный контекстно-чувствительный анализ помеченных данных
- Вспомогательные методы анализа
- Выявляемые типы критических ошибок
- Соответствие требованиям к методам анализа
- Соответствие требованиям к инструментам статического анализа исходных текстов
- Анализ проекта целиком, включая используемые заимствованные компоненты
- Время анализа проекта
- Результаты применения анализатора
- Принятие решений и автоматизация разметки предупреждений
- Автоматизации действий
- Обеспечивается хранение результатов запуска, разметки и сравнения
- Документации с описанием всех типов ошибок
- Выдача результатов анализа в открытом документированном формате
- Доработки алгоритмов и правил пользователями
- Дополнительные ссылки по теме РБПО и ГОСТ Р 71207–2024
Инструментальное средство PVS-Studio разрабатывается с учётом требований, предъявляемых к статическим анализаторам в ГОСТ Р 71207–2024, выявляет критические ошибки и может использоваться при разработке безопасного программного обеспечения. Здесь рассмотрены функциональные возможности, реализованные в PVS-Studio на конец 2024 года в отношении анализа исходного кода программного обеспечения, написанного на компилируемых языках программирования C, C++, C#, Java.
Определения
ГОСТ Р 71207–2024 — РАЗРАБОТКА БЕЗОПАСНОГО ПРОГРАММНОГО ОБЕСПЕЧЕНИЯ. Статический анализ программного обеспечения. Общие требования. Разработан ФСТЭК России и ИСП РАН. Впервые введён в действие 01.04.2024.
Примечание. Все приводимые далее в тексте ссылки на разделы и пункты (п. x.x.x.) относятся к стандарту ГОСТ Р 71207–2024.
Стандарт устанавливает требования к:
- внедрению и выполнению статического анализа ПО (раздел 5);
- классификации критических ошибок (раздел 6);
- методам статического анализа (раздел 7);
- инструментам анализа (раздел 8);
- специалистам, участвующим в анализе (раздел 9);
- методике проверки соответствия статических анализаторов ГОСТ (раздел 10).
Входит в комплекс стандартов, направленных на предотвращение уязвимостей в программах, и применяется совместно с ГОСТ Р 56939.
Критическая ошибка в программе. Термин введён в ГОСТ Р 71207–2024 (п. 3.1.13.). Это ошибка, которая может привести к нарушению безопасности обрабатываемой информации. С точки зрения безопасности, это ошибки, которые должны обнаруживаться и исправляться в первую очередь.
Статические анализаторы должны выявлять следующие виды критических ошибок в коде программ на компилируемых языках (п. 6.3.):
- ошибки непроверенного использования чувствительных данных;
- ошибки целочисленного переполнения и некорректного совместного использования знаковых и беззнаковых чисел;
- ошибки переполнения буфера;
- ошибки некорректного использования системных процедур и интерфейсов, связанных с обеспечением информационной безопасности;
- ошибки при работе с многопоточными примитивами.
Дополнительно для C и C++ (п. 6.5.):
- ошибки разыменования нулевого указателя;
- ошибки деления на ноль;
- ошибки управления динамической памятью;
- ошибки использования форматной строки;
- ошибки использования неинициализированных переменных;
- ошибки утечек памяти, незакрытых файловых дескрипторов и дескрипторов сетевых соединений.
Примечание. Набор требований ГОСТ по обнаружению критических ошибок совпадает для языков C и C++. Анализатор PVS-Studio использует общее ядро для анализа программ на этих языках, поэтому далее для сокращения текста эти языки будут рассматривать вместе, а не по отдельности.
PVS-Studio. Инструментальное средство статического анализа кода, разрабатываемое с учётом требований, изложенных в ГОСТ Р 71207–2024. Выявляет все виды критических ошибок, перечисленных в стандарте (п. 6.3., п. 6.5.), и может использоваться для предотвращения появления и устранения уязвимостей при разработке безопасного ПО (РБПО). Поддерживает языки: C, C++, C#, Java. Работает под управлением операционных систем Windows, Linux, macOS.
Анализатор содержит 3 ядра:
- Ядро для анализа С и C++ кода. Написано на C++.
- Ядро для анализа С# кода. Написано на C#.
- Ядро для анализа Java кода. Написано на Java.
Анализатор удовлетворяет требованиям ГОСТ Р 71207–2024 к методам анализа (раздел 7), что обеспечивает выявление всех видов критических ошибок для поддерживаемых языков. Выполняются требования, изложенные в разделе 8, такие как: выдача результатов в открытых форматах (например, SARIF), указание соответствия типа ошибки согласно системе классификации MITRE CWE и так далее.
Инструмент разрабатывается в России с 2008 года (запись в Едином Реестре российского ПО N9837) и содержит более 1000 диагностических правил. Возможно использование в полностью закрытом контуре. Является SAST-решением.
Поддерживаемые языки и методы анализа
PVS-Studio поддерживает анализ кода программ, написанных на языках программирования C, C++, C#, Java.
В ГОСТ Р 71207–2024 (п. 7.4.) перечислены методы, которые должен реализовывать статический анализатор. PVS-Studio реализует все эти методы.
Виды анализа (п. 7.4.) |
C и C++ |
C# |
Java |
---|---|---|---|
Внутрипроцедурный анализ потоков данных и управления |
✓ |
✓ |
✓ |
Межпроцедурный и межмодульный контекстно-чувствительный анализ потока данных |
✓ |
✓ |
✓ |
Чувствительный к путям выполнения анализ потоков данных и управления |
✓ |
✓ |
✓ |
Межпроцедурный и межмодульный контекстно-чувствительный анализ помеченных данных |
✓ |
✓ |
✓* |
Анализ программы на синтаксическом уровне |
✓ |
✓ |
✓ |
Таблица N1. Виды анализа, которые должен реализовывать статический анализатор кода согласно ГОСТ Р 71207–2024 (п. 7.4.).
Примечание *. На момент написания этого раздела в 2024 году для Java реализован анализ помеченных данных, но отсутствует механизм пользовательских аннотаций для задания процедур-источников и процедур-стоков чувствительных данных (п. 7.6.). Реализация поддержки аннотаций запланирована на первую половину 2025 года.
Также в стандарте (п. 7.4.) перечислены вспомогательные методы анализа, которые может реализовывать инструмент для поиска дополнительных типов ошибок. PVS-Studio поддерживает следующие из них:
Необязательные вспомогательные виды анализа (п. 7.4.) |
C и C++ |
C# |
Java |
---|---|---|---|
Сигнатурный поиск |
✓ |
✓ |
✓ |
Анализ псевдонимов |
✓ |
||
Анализ косвенных вызовов |
|||
Статистический анализ |
✓ |
✓ |
✓ |
Анализ иерархии классов |
✓ |
✓ |
✓ |
Таблица N2. Виды анализа, которые согласно ГОСТ Р 71207–2024 (п. 7.4.) следует использовать в качестве вспомогательных методов.
Разберём перечисленные методы более подробно и приведём примеры их использования.
Анализ программы на синтаксическом уровне
Согласно ГОСТ (п 3.1.6.), анализ программы на синтаксическом уровне — это статический анализ, при котором обрабатывается представление программы, полностью отражающее её синтаксическую структуру, например, абстрактное синтаксическое дерево.
Хотя этот вид анализа приводится в списке последним, мы начнём именно с него, так как он является основой для всех остальных. Без разбора кода на синтаксическом уровне и построения абстрактного синтаксического дерева невозможно проведение полноценного анализа кода. Более того, обязательным также является и семантический анализ, позволяющий вывести типы данных и другую информацию, требуемую для реализации подавляющего числа диагностических правил.
В PVS-Studio все диагностические правила для всех языков работают с деревом, полученным в ходе синтаксического анализа кода. Поэтому примером использования анализа программы на синтаксическом уровне может являться любое из них.
Редчайшим исключением являются несколько диагностических правил, работающих на уровне лексем. Примером такого исключения является поиск невидимых символов, позволяющих проводить атаку Trojan Source.
Синтаксический анализ C и C++ кода
Для C и C++ построение дерева осуществляется собственным парсером, написанным на языке C++ и развиваемым силами команды PVS-Studio. Наши доклады и статьи на эту тему:
- Юрий Минаев: "Как забраться на дерево".
- C++ Zero Cost Conf 2024, Юрий Минаев: "Семантика для кремниевых мозгов".
- Вебинар, Олег Лысый: "Парсим С++".
Синтаксический анализ C# кода
Работа с C# кодом базируется на использовании .NET Compiler Platform (Roslyn). Наши доклады и статьи на эту тему:
- Сергей Васильев: "Введение в Roslyn. Использование для разработки инструментов статического анализа".
- DotNext 2022 Autumn, Сергей Васильев: "Анализ C# кода на Roslyn: от теории к практике".
- Валерий Комаров: "Создание статического анализатора для C# на основе Roslyn API".
Синтаксический анализ Java кода
Работа с Java кодом базируется на использовании Spoon. Статья Егора Бредихина о том, почему была выбрана библиотека Spoon — "Разработка нового статического анализатора: PVS-Studio Java".
Пример использования синтаксического анализа для поиска ошибок
Синтаксический анализ — неотъемлемая часть всех диагностических правил, реализованных в PVS-Studio для всех поддерживаемых языков. Поэтому разберём только один пример.
Ошибка была найдена с помощью PVS-Studio в проекте LLVM (язык C++) и описана в этой статье.
std::unique_ptr<OptionDefinition> m_options_definition_up;
....
Status SetOptionsFromArray(StructuredData::Dictionary &options) {
Status error;
m_num_options = options.GetSize();
m_options_definition_up.reset(new OptionDefinition[m_num_options]);
....
}
Предупреждение PVS-Studio: V554 Incorrect use of unique_ptr. The memory allocated with 'new []' will be cleaned using 'delete'. CommandObjectCommands.cpp 1384
Умный указатель m_options_definition_up ориентирован на хранение одиночного элемента, но туда помещается указатель на массив. Результат — неопределённое поведение в момент разрушения объекта. Корректный вариант кода:
std::unique_ptr<OptionDefinition []> m_options_definition_up;
Чтобы найти эту ошибку, необходимо в момент вызова функции reset иметь информацию, какой тип имеет переменная m_options_definition_up. Эта информация собирается при обходе дерева, построенного с помощью синтаксического разбора кода и механизма вывода типов переменных.
Внутрипроцедурный анализ потоков данных и управления
Определения:
- анализ потока данных (п 3.1.4.) — статический анализ, при котором определяются свойства обрабатываемых программой данных. Могут определяться возможные значения переменных и констант, точки программы, в которых используются определённые переменные и прочее;
- анализ потока управления (п 3.1.5.) — статический анализ, при котором выделяются процедуры программы, линейные участки кода процедур и условия переходов между этими участками.
Анализ потоков данных позволяет анализатору PVS-Studio делать предположения о значениях переменных и выражений в различных частях исходного кода. Некоторые виды предполагаемых значений:
- конкретные значения (числа, строки);
- диапазоны значений;
- множество возможных значений.
Бывают и более сложные виды данных, сопоставляемые с какой-то переменной. Например, анализатор может знать, что указатель находится в одном из следующих состояний:
- неинициализированный (нельзя разыменовывать и сравнивать с другим указателем);
- нулевой (нельзя разыменовывать);
- указывает на буфер памяти определённого размера (можно проверить выход за границу буфера);
- указывает на освобождённую память (нельзя разыменовывать или повторно освобождать);
- и так далее.
Анализ потока управления в PVS-Studio неразрывно связан с анализом потока данных. Поясним это примером на языке C++:
void foo()
{
int A = 1;
int B = 2;
if (A == 3)
{
B = 0;
}
A = 10 / B;
}
В момент проверки (A == 3) анализатор благодаря анализу потока данных знает, что условие будет всегда ложным, так как переменная A равна 1. Следовательно, с точки зрения потока управления, тело оператора if не выполняется, и переменной B не может быть присвоено значение 0.
Информация о потоке выполнения (что не выполняется код, где 0 записывается в переменную B) влияет на поток данных. Известно, что значение переменной B остаётся равно 2. Следовательно, деление 10 / B всегда безопасно, и анализатор не выдаёт предупреждение о потенциальном делении на ноль.
Анализ потоков данных и управления так или иначе участвует почти во всех алгоритмах выявления критических ошибок. Например, именно благодаря ему удаётся определить, каков размер массива, и происходит ли в определённой ветке кода запись за его границу.
Механизмы анализа потока данных схоже реализованы в PVS-Studio для всех языков и нет смысла их рассматривать отдельно. Дальнейшие разделы созданы с целью разделить ссылки на публикации и примеры для разных языков.
Пример внутрипроцедурного анализа потоков данных и управления для C и C++ кода
Хорошим примером использования внутрипроцедурного анализа потоков данных и управления является выявление ошибки в проекте Protocol Buffers (protobuf), которая описана в статье "31 февраля".
static const int kDaysInMonth[13] = {
0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
};
bool ValidateDateTime(const DateTime& time) {
if (time.year < 1 || time.year > 9999 ||
time.month < 1 || time.month > 12 ||
time.day < 1 || time.day > 31 ||
time.hour < 0 || time.hour > 23 ||
time.minute < 0 || time.minute > 59 ||
time.second < 0 || time.second > 59) {
return false;
}
if (time.month == 2 && IsLeapYear(time.year)) {
return time.month <= kDaysInMonth[time.month] + 1;
} else {
return time.month <= kDaysInMonth[time.month];
}
}
Функция ValidateDateTime принимает на вход дату и должна определить, корректна она или нет. Вначале выполняются основные проверки. Проверяется, что номер месяца лежит в диапазоне [1..12], дни находятся в диапазоне [1..31], минуты находятся в диапазоне [0..59] и так далее.
Затем идёт более сложная проверка: есть ли определённый день в определённом месяце. Чтобы проверить дни, используется вспомогательный массив kDaysInMonth. В массиве записано количество дней в различных месяцах. По номеру месяца из массива извлекается максимальное количество дней, которое и используется для проверки.
Дополнительно учитывается, что год может быть високосным, и тогда в феврале на 1 день больше.
Из-за опечатки дни проверяются неправильно. Обратите внимание, что с максимально возможным количеством дней в месяце сравнивается не день, а месяц.
if (time.month == 2 && IsLeapYear(time.year)) {
return time.month <= kDaysInMonth[time.month] + 1;
} else {
return time.month <= kDaysInMonth[time.month];
}
В сравнениях "time.month <= ...." следует использовать day, а не month.
Номер месяца (от 1 до 12) всегда меньше количества дней в любом из месяцев.
Из-за этой ошибки корректными будут считаться такие дни, как, например, 31 февраля или 31 ноября.
Предупреждения PVS-Studio:
- V547 Expression 'time.month <= kDaysInMonth[time.month] + 1' is always true. time.cc 83
- V547 Expression 'time.month <= kDaysInMonth[time.month]' is always true. time.cc 85
Обнаружение этой ошибки возможно благодаря одновременной работе анализа потоков данных и управления.
Если значение месяца лежит вне диапазона [1..12], то функция завершает работу. Следовательно, анализ потока управления будет выполняться дальше только в том случае, если значение переменной time.month лежит в диапазоне [1..12].
Анализатор заглядывает внутрь массива и понимает, что оттуда извлекаются значения в диапазоне [28..31]. Он учитывает, что 0 из массива kDaysInMonth не извлекается, так как возможный диапазон time.month, используемого в качестве индекса, равен [1..12].
В итоге анализатор видит, что происходят следующие сравнения диапазонов:
- [2..2] <= [28..31]
- [1..12] <= [29..32]
Условия всегда истинны, о чём анализатор и выдаёт предупреждения.
Почему первый диапазон [2..2] представлен только одним числом 2? Дело в том, что учитывается уточняющее условие time.month == 2.
Наши доклады и статьи на тему анализа потока данных C++ кода:
- Андрей Карпов: "Зачем PVS-Studio использует анализ потока данных: по мотивам интересной ошибки в Open Asset Import Library".
- CoreHard 2018, Павел Беликов: "Как работает анализ Data Flow в статическом анализаторе кода".
- Сергей Васильев: "Под капотом SAST: как инструменты анализа кода ищут дефекты безопасности".
Пример внутрипроцедурного анализа потоков данных и управления для C# кода
Пример для C# будет проще, но фактически всё работает аналогичным образом. Аномалия была выявлена в проекте Unity3D.
public NetworkConnection Get(int connId)
{
if (connId < 0)
{
return m_LocalConnections[Mathf.Abs(connId) - 1];
}
if (connId < 0 || connId > m_Connections.Count)
....
}
Предупреждение PVS-Studio: V3063 A part of conditional expression is always false: connId < 0. ConnectionArray.cs 59
Если первое условие выполнилось (connId < 0), то поток управления прерывается (происходит выход из функции с помощью оператора return). Следовательно, функция продолжит выполнение только в том случае, если значение переменной connId больше или равно 0.
Анализ потока данных учитывает тот факт, что connId >= 0, и на его основе диагностическое правило V6063 делает вывод, что часть условия всегда ложна.
Наши публикации на тему анализа потока данных C# кода:
- Никита Липилин: "Эволюция PVS-Studio: анализ потока данных для связанных переменных".
- Артём Ровенский: "Анализ потока данных PVS-Studio распутывает всё больше связанных переменных".
Пример внутрипроцедурного анализа потоков данных и управления для Java кода
При создании ядра для анализа языка Java был переиспользован механизм анализа потока данных и управления, реализованный в ядре C++ анализатора. То есть Java анализатор использует часть функциональности C++ анализатора с помощью SWIG (средство для автоматической генерации врапперов и интерфейсов для связывания программ на C и C++ с программами, написанными на других языках).
Это позволило быстрее разработать первую версию Java анализатора, однако повлекло за собой ряд сложностей и усложнение процесса дальнейшего развития. Например, достаточно неудобно отлаживать код из-за этой связки. Правки C++ ядра могут неожиданно влиять на Java анализатор и так далее.
Поэтому наша команда планирует в 2025 году переписать используемые механизмы на Java и развивать их независимо.
Использование анализа потоков данных и управления для Java кода будет показано на примере ошибки в проекте GeoGebra.
private void updateOrdering(GeoElement geo, ObjectMovement movement) {
....
if (index == firstIndex) {
if (index != 0) {
geo.setOrdering(orderingDepthMidpoint(index));
}
else {
geo.setOrdering(drawingOrder.get(index - 1).getOrdering() - 1);
}
}
....
}
Предупреждение PVS-Studio: V6025 Index 'index - 1' is out of bounds. LayerManager.java 393
Анализируя поток управления, анализатор знает, что:
geo.setOrdering(drawingOrder.get(index - 1).getOrdering() - 1);
Выполняется только в том случае, если переменная index равна 0. Следовательно, фактическим аргументом, передаваемым в функцию get, будет значение -1. Результат: генерация исключения типа IndexOutOfBoundsException.
Межпроцедурный и межмодульный контекстно-чувствительный анализ потока данных
Определения:
- межмодульный анализ (п. 3.1.17.) — статический анализ, при котором выполняется совместный анализ программы или нескольких программ, состоящих из нескольких программных модулей, и выявляемые свойства программы затрагивают процедуры или переменные из различных модулей.
- межпроцедурный контекстно-чувствительный анализ (п. 3.1.18.) — статический анализ, при котором выявляемые свойства программы учитывают взаимодействие нескольких процедур, в том числе возникающее в результате выполнения нескольких процедур или вызовов процедурами друг друга, а также контексты их вызова. В ходе анализа учитывается контекст вызова процедуры при обработке её вызова, то есть сопоставляется информация из вызывающей и вызываемой процедур применительно к каждому месту вызова и его окружению: фактическим параметрам, состоянию глобальных переменных и тому подобное.
Статические анализаторы кода могут учитывать данные, которые передаются между процедурами/функциями, чтобы выявить больше критических ошибок. Это важно при выявлении таких ошибок, как утечки памяти, разыменование нулевых указателей, выход за границы массивов и так далее. Это связано с тем, что создание некого ресурса, его использование и освобождение часто разнесены по разным функциях.
Для выявления ошибок, возникающих при взаимодействии нескольких процедур, статические анализаторы используют технологию межпроцедурного контекстно-чувствительного анализа кода.
Ситуация усложняется, если требуется анализировать взаимодействие функций, находящихся в различных единицах трансляции/программных модулях. В этом случае говорят, что выполняется межмодульный анализ.
PVS-Studio реализует межпроцедурный и межмодульный контекстно-чувствительный анализ потока данных для всех поддерживаемых языков. Однако межмодульный анализ С и C++ более сложен по сравнению с C# и Java, так как требует дополнительных действий по объединению информации, получаемой из различных единиц трансляции.
Межпроцедурный и межмодульный контекстно-чувствительный анализ потока данных C и С++ кода
Межмодульный анализ в PVS-Studio для С и C++ выполняется в 3 этапа:
- Семантический анализ каждой отдельной единицы трансляции. Анализатор собирает информацию о каждом символе программы, для которого нашлись потенциально интересные факты. После эта информация записывается в файлы в специальном формате. Такая обработка может выполняться параллельно, что хорошо для многопоточной сборки.
- Слияние символов. На этом этапе анализатор объединяет информацию из разных файлов с фактами в один, попутно решая конфликты между символами. На выходе получаем один файл с необходимой для межмодульного анализа информацией.
- Запуск диагностических правил. Анализатор вновь проходит каждую единицу трансляции. Однако в отличие от режима с выключенным межмодульным анализом, во время выполнения правил загружается информация о символах из объединённого файла. Таким образом, становится доступной информация о фактах для символов из других модулей.
Наши доклады и статьи на эту тему:
- Олег Лысый, Сергей Ларин: "Межмодульный анализ C++ проектов в PVS-Studio".
- C++ Russia 2023, Олег Лысый: "Межмодульный анализ C++ проектов".
- Олег Лысый: "Межмодульный анализ C и C++ проектов в деталях: часть 1, часть 2".
Рассмотрим пример ошибки, найденной с помощью межмодульного контекстно-чувствительного анализа инструментом PVS-Studio в коде проекта Midnight Commander (язык C).
Начнём с функции widget_destroy в файле widget-common.c:
void widget_destroy (Widget * w)
{
send_message (w, NULL, MSG_DESTROY, 0, NULL);
g_free (w);
}
Функция освобождает буфер памяти, адрес которого она получает через аргумент w.
Теперь посмотрим на код в файле editcmd.c:
gboolean edit_close_cmd (WEdit * edit)
{
Widget *w = WIDGET (edit);
....
widget_destroy (w); // <= Здесь освободили память
if (....) .... else
{
edit = find_editor (DIALOG (g));
if (edit != NULL)
widget_select (w); // <= Передаём указатель дальше
}
}
Обратите внимание, что в начале адрес структуры Widget передаётся в функцию widget_destroy, где происходит освобождение буфера памяти. Далее этот указатель передаётся в функцию widget_select, приведённую ниже:
void widget_select (Widget * w)
{
WGroup *g;
if (!widget_get_options (w, WOP_SELECTABLE))
return;
....
}
Она просто передаёт указатель дальше в функцию widget_get_options:
static inline gboolean
widget_get_options (const Widget * w, widget_options_t options)
{
return ((w->options & options) == options);
}
Здесь мы добрались до места, где возникает неопределённое поведение, связанное с использованием данных в уже освобождённом буфере памяти. Анализатор PVS-Studio сигнализирует об этом предупреждением: V774 The 'w' pointer was used after the memory was released.
Межпроцедурный и межмодульный контекстно-чувствительный анализ потока данных С# кода
.NET Compiler Platform предоставляет инфраструктуру для работы сразу со всеми файлами исходного кода, включёнными в проект. Это делает межмодульный анализ C# кода более простым в реализации, чем в случае C++.
Рассмотрим два примера реального кода, первый из которых хорошо демонстрирует суть контекстно-чувствительного анализа, а второй — межмодульного анализа.
Первая ошибка найдена в проекте AvalonStudio. Рассмотрим вначале функцию IsBuiltInType. Обратите внимание, что, если её входной аргумент cursor окажется нулевой ссылкой, то функция вернёт значение false. Другими словами, результат работы функции зависит от контекста её вызова.
private static bool IsBuiltInType(ClangType cursor)
{
var result = false;
if (cursor != null && ....)
{
return true;
}
return result;
}
Теперь рассмотрим другой фрагмент кода, где вызывается рассмотренная функция:
private static StyledText InfoTextFromCursor(ClangCursor cursor)
{
....
if (cursor.ResultType != null)
{
result.Append(cursor.ResultType.Spelling + " ",
IsBuiltInType(cursor.ResultType) ? theme.Keyword
: theme.Type);
}
else if (cursor.CursorType != null)
{
switch (kind)
{
....
}
result.Append(cursor.CursorType.Spelling + " ",
IsBuiltInType(cursor.ResultType) ? theme.Keyword
: theme.Type);
}
....
}
Если cursor.ResultType != null, то выполняется тело первого оператора if. Соответственно, если управление будет предано внутрь тела второго оператора if, то точно известно, что ссылка cursor.ResultType является нулевой.
Изучим место вызова рассмотренной ранее функции IsBuiltInType:
result.Append(cursor.CursorType.Spelling + " ",
IsBuiltInType(cursor.ResultType) ? theme.Keyword
: theme.Type);
Анализатор знает, что cursor.ResultType — нулевая ссылка. Из этого он делает вывод, что при таком входном аргументе функция всегда возвращает false.
Это и есть межпроцедурный контекстно-чувствительный анализ.
Если условие тернарного оператора всегда ложно, то это подозрительно, о чём анализатор и сообщает, выдавая предупреждение: V3022 Expression 'IsBuiltInType(cursor.ResultType)' is always false.
Действительно, если присмотреться к коду, то можно заметить опечатку. В теле второго оператора if при вызове функции IsBuiltInType в качестве фактического аргумента следует передать переменную cursor.CursorType.
Рассмотрим второй пример кода из игры Starlight, где для выявления ошибки требуется межмодульный анализ. Здесь задействовано 3 файла:
- NavMeshGenerator.cs — метод ScanInternal;
- AstarData.cs — метод GetGraphIndex;
- TriangleMeshNode.cs — метод SetNavmeshHolder.
protected override IEnumerable<Progress> ScanInternal ()
{
....
TriangleMeshNode.SetNavmeshHolder(
AstarPath.active.data.GetGraphIndex(this), this);
....
}
Предупреждение PVS-Studio: V3106 The 1st argument 'AstarPath.active.data.GetGraphIndex(this)' is potentially used inside method to point beyond collection's bounds. NavMeshGenerator.cs 225
Анализатор сообщает о том, что внутри метода TriangleMeshNode.SetNavmeshHolder происходит доступ по индексу за пределами допустимого диапазона. При этом в качестве индекса выступает первый аргумент.
Взглянем на метод AstarPath.active.data.GetGraphIndex:
public int GetGraphIndex (NavGraph graph) {
if (graph == null) throw new System.ArgumentNullException("graph");
var index = -1;
if (graphs != null) {
index = System.Array.IndexOf(graphs, graph);
if (index == -1) Debug.LogError("Graph doesn't exist");
}
return index;
}
Как мы видим, метод может вернуть в качестве результата -1. Теперь взглянем на метод TriangleMeshNode.SetNavmeshHolder:
public static void SetNavmeshHolder (int graphIndex, INavmeshHolder graph) {
// We need to lock to make sure that
// the resize operation is thread safe
lock (lockObject) {
if (graphIndex >= _navmeshHolders.Length) {
var gg = new INavmeshHolder[graphIndex+1];
_navmeshHolders.CopyTo(gg, 0);
_navmeshHolders = gg;
}
_navmeshHolders[graphIndex] = graph; // <=
}
}
Анализатор сообщает, что проблемный доступ происходит на последней строке. Доступ по индексу происходит без предварительной проверки.
Межпроцедурный и межмодульный контекстно-чувствительный анализ потока данных Java кода
Библиотека Spoon предоставляет инфраструктуру для работы сразу со всеми файлами исходного кода, входящими в проект. Это делает межмодульный анализ Java кода схожим с анализом C# кода и более простым в реализации по сравнению с C++.
Для Java анализатора нашей командой пока собрано мало случаев реальных ошибок в открытых проектах, из которых можно подбирать примеры. Рассмотрим синтетический пример:
class Main {
static class NetworkTextTransmitter {
private final Socket socket = new Socket();
private final PrintWriter socketWriter;
public NetworkTextTransmitter(InetSocketAddress host,
InetSocketAddress source)
throws IOException {
socket.bind(host);
socket.connect(source);
socketWriter = new PrintWriter(socket.getOutputStream());
}
public void transmit(String message) {
socketWriter.println(message);
}
....
public void closeConnection() {
socketWriter.close();
}
}
public static void main(String[] args) throws IOException {
....
InetSocketAddress hostAddress =
new InetSocketAddress(Integer.parseInt(args[0]));
InetSocketAddress sourceAddress =
new InetSocketAddress(Integer.parseInt(args[1]));
NetworkTextTransmitter textTransmitter =
new NetworkTextTransmitter(hostAddress, sourceAddress);
Scanner scanner = new Scanner(System.in);
for (int i = 0; i < Integer.parseInt(args[0]); i++) {
textTransmitter.transmit(scanner.next());
}
textTransmitter.closeConnection();
}
Предупреждение PVS-Studio: V6114 The 'NetworkTextTransmitter' class contains the 'socket' Closeable field, but the resources that the field is holding are not released inside the class. Main.java 10
Пример демонстрирует использование информации о состоянии класса (контекстно-чувствительный анализ) в процессе взаимодействия с ним (межпроцедурный анализ).
Программа выполняет передачу текстовых сообщений по сетевому подключению через сокет. Текстовые сообщения вводятся через консоль и передаются по подключению. Для передачи сообщений используется класс NetworkTextTransmitter, который создаёт подключение и поток передачи. По завершению передачи N сообщений метод main вызывает метод closeConnection. Внутри данного метода закрывается только поток передачи текстовых данных, однако само подключение через сокет остаётся открытым.
Чувствительный к путям выполнения анализ потоков данных и управления
Согласно ГОСТ, чувствительный к путям выполнения анализ (3.1.36.) — это статический анализ программы, при котором могут быть определены её свойства, проявляющиеся лишь на некоторых путях выполнения программы, и условия (или часть условий), при обращении которых в истину выполнение программы пойдёт по указанному анализатором пути.
Не очень понятно, почему стандарт выделяет чувствительность к путям выполнения в отдельный вид анализа потока данных и управления. На наш взгляд, анализ потока данных (п 3.1.4.) и анализ потока управления (п 3.1.5.) уже подразумевают учёт путей выполнения кода. В противном случае, если не учитывать пути выполнения, эти виды анализа становятся вырожденными и почти непригодными к практическому применению.
Возможно, стандарт содержит не очень удачную формулировку или не даёт дополнительных пояснений и примеров.
Мы интерпретируем этот вид анализа следующим образом: стандарт предлагает учитывать те ситуации, когда некоторое действие может как произойти, так и не произойти. Следует выдавать предупреждение с учётом того, что выполнение программы пойдёт по пути, приводящему к ошибке.
Поясним нашу интерпретацию синтетическим примером на языке C++:
void foo(bool A)
{
int *B = new int;
if (A)
{
delete B;
}
*B = 1;
}
Если условие выполнится, то анализатор должен выдать предупреждение о том, что происходит запись в уже освобождённую память.
Если условие не выполнится, то анализатор должен выдать предупреждение об утечке памяти.
Если анализатор может вычислить с помощью межпроцедурного и межмодульного контекстно-чувствительного анализа потока данных чему равна переменная A, то он должен выдать одно предупреждение из двух.
Если вычислить значение A невозможно или известно, что оно может быть как false, так и true, то помогает анализ потоков данных и управления, чувствительный к путям выполнения. Анализатор должен выдать оба предупреждения, по возможности показав пути выполнения программы, приводящие к ним.
Анализатор PVS-Studio использует чувствительный к путям выполнения анализ потоков данных, но не выделяет его в отдельную сущность или алгоритм. Фактически все 3 рассмотренные виды анализа:
- межпроцедурный и межмодульный контекстно-чувствительный анализ потока данных;
- чувствительный к путям выполнения анализ потоков данных и управления;
- межпроцедурный и межмодульный контекстно-чувствительный анализ помеченных данных.
Реализуются в каждом языковом ядре PVS-Studio в виде единого механизма (алгоритма).
Пример анализа потока данных и управления, чувствительных путям выполнения C и C++ кода
Ошибка, используемая в качестве примера, была найдена в проекте MPC-HC (С++):
void CSyncAP::RenderThread()
{
....
REFERENCE_TIME rtRefClockTimeNow;
if (m_pRefClock) {
m_pRefClock->GetTime(&rtRefClockTimeNow);
}
LONG lLastVsyncTime =
(LONG)((m_llEstVBlankTime - rtRefClockTimeNow) / 10000);
....
}
Предупреждение PVS-Studio: V614 Potentially uninitialized variable 'rtRefClockTimeNow' used. syncrenderer.cpp 3604
Переменная rtRefClockTimeNow останется неинициализированной, если указатель m_pRefClock является нулевым. Соответственно, возможен путь выполнения программы, приводящий к ошибке — использованию неинициализированной переменной. При этом это необязательно произойдёт, поэтому анализатор сообщает о потенциальной ошибке. Таким образом, анализ здесь чувствителен к путям выполнения.
В случае, если переменная не инициализирована всегда, анализатор будет более категоричен. Код из проекта Trans-Proteomic Pipeline (язык С++):
double mscore_c::dot_hr(unsigned long *_v)
{
....
int iSeqSize;
for (int a = 0; a < iSeqSize; a++) {
....
}
Здесь нет вариантов, поэтому PVS-Studio выдаёт предупреждение: V614 Uninitialized variable 'iSeqSize' used. mscore_c.cpp 552
Пример анализа потока данных и управления, чувствительных путям выполнения C# кода
Ошибка была обнаружена нами в проекте RunUO:
public static string ConstructFromString( .... )
{
object toSet;
bool isSerial = IsSerial( type );
if ( isSerial ) // mutate into int32
type = m_NumericTypes[4];
if ( IsEnum( type ) )
{
try
{
toSet = Enum.Parse( type, value, true ); // <= (А)
}
catch
{
return "That is not a valid enumeration member.";
}
}
else if ( IsType( type ) )
{
try
{
toSet = ScriptCompiler.FindTypeByName( value ); // <= (Б)
if ( toSet == null )
return "No type with that name was found.";
}
catch
{
return "No type with that name was found.";
}
}
....
else if ( value == null )
{
toSet = null; // <= (В)
}
....
if ( isSerial ) // mutate back
toSet = (Serial)((Int32)toSet);
constructed = toSet;
return null;
}
Переменной toSet могут присваиваться как ссылки на существующие объекты (точки: А, Б), так и нулевая ссылка (точка В). Анализатор чувствителен к тому, что существуют эти различные пути выполнения, и предупреждает, что ссылка потенциально может оказаться нулевой.
Предупреждение PVS-Studio: V3148 Casting potential 'null' value of 'toSet' to a value type can lead to NullReferenceException. Properties.cs 502
Пример анализа потока данных и управления, чувствительных путям выполнения Java кода
Рассмотрим ошибку возможного разыменования нулевой ссылки в проекте Keycloak:
private void checkRevocationUsingOCSP(X509Certificate[] certs)
throws GeneralSecurityException {
....
if (rs == null) { // <= (А)
if (_ocspFailOpen)
logger.warnf(....); // <= (Б)
else
throw new GeneralSecurityException(....); // <= (В)
}
if (rs.getRevocationStatus() == // <= (Г)
OCSPProvider.RevocationStatus.UNKNOWN) {
....
}
Если rs хранит нулевую ссылку (точка А), то нормальный поток выполнения может быть прерван генерацией исключения (точка В). Но может быть и не прерван (точка Б), что приведёт к доступу по нулевой ссылке (точка Г).
Итого ссылка может быть как нулевая, так и не нулевая. Если она нулевая, то до её использования управление может как дойти, так и не дойти. Таким образом, задействован анализ потока данных и управления, чувствительный к путям выполнения.
Анализатор PVS-Studio сообщает о потенциальной ошибке: V6008 Potential null dereference of 'rs'. CertificateValidator.java 701 , CertificateValidator.java 708
В общем случае подобные предупреждения могут быть ложными, если между ссылкой rs и переменной ocspFailOpen существует сложная косвенная взаимосвязь, которую анализатор не смог выявить (см. статью про связанные переменные). Собственно, и в стандарте говорится (примечание к п. 3.1.2.): анализ потока управления, анализ потока данных, анализ помеченных данных, анализ псевдонимов и анализ косвенных вызовов в общем случае дают приближённые результаты.
Однако даже в этом случае ложные предупреждения могут быть полезны, так как выявляют сложный, неочевидный код, который может быть непонятен не только анализатору, но и разработчикам. Целесообразно провести его рефакторинг или, по крайне мере, написать соответствующий комментарий про косвенную связь между переменными.
Межпроцедурный и межмодульный контекстно-чувствительный анализ помеченных данных
Согласно ГОСТ, анализ помеченных данных (3.1.3.) — статический анализ, при котором анализируется течение потока данных от источников до стоков. Под источниками понимаются точки программы, в которых данные начинают иметь пометку — некоторое заданное свойство. Под стоками понимаются точки программы, в которых данные перестают иметь пометку. Распространённая (но не единственная) цель анализа помеченных данных — показать, что помеченные данные не могут попасть из источников — точек ввода пользователя в стоки — процедуры записи на диск или в сеть. Факт такого попадания означает утечку конфиденциальных данных.
Механизмы анализа помеченных данных схожи с механизмами анализа потоков данных, но имеют существенное различие. Основная задача анализа потока данных — попытаться выяснить состояние переменных в различных точках программы, чтобы в дальнейшем использовать эту информацию в диагностических правилах. Например, если известно, что значение целочисленной переменной A лежит в диапазоне от 0 до 10, то её нельзя использовать в качестве индекса для массива, содержащего только 5 элементов.
Контекстно-чувствительный анализ помеченных данных не ставит задачей определить значение переменных, а оперирует понятием недостоверности данных. Если значение целочисленной переменной A взято из ненадёжного источника и не проверено, его опасно использовать в качестве индекса массива. При этом диапазон значений A может быть полностью неизвестен. Он и не важен. Важен факт использования опасных данных.
Источники заражения. Первичным понятием в данной теме являются заражённые данные. Под этим термином подразумеваются некоторые значения, которые могут позволить злоумышленнику выполнить несанкционированные и, как правило, вредоносные операции при взаимодействии с системой. В зависимости от способа использования внешних данных приложение может быть уязвимо к тем или иным атакам. Например, если приложение использует непроверенные внешние данные при формировании запросов к БД, то оно может быть уязвимо к SQL injection.
Таким образом, внешние данные являются потенциально заражёнными. Точки, в которых приложение получает к ним доступ, называют источниками заражения. Например, источником заражения может быть операция получения значения параметра HTTP-запроса:
void ProcessRequest(HttpRequest request)
{
....
string name = request.Form["name"]; // источник
// теперь "name" содержит недостоверные/заражённые данные
....
}
Передача заражения. Важным аспектом при проведении анализа помеченных данных является определение "трасс распространения" заражённых данных по приложению. В приведённом примере заражённые данные из источника передаются в переменную name. Впоследствии они могут также переходить в другие переменные или выступать в качестве аргументов функций:
void ProcessRequest(HttpRequest request)
{
string name = request.Form["name"]; // источник
// теперь "name" содержит недостоверные/заражённые данные
string sql = $"SELECT * FROM Users WHERE name='{name}'";
// недостоверные данные передаются далее как аргумент
ExecuteReaderCommand(sql);
....
}
void ExecuteReaderCommand(string sql)
{
// sql содержит недостоверные/заражённые данные
....
}
Стоит отметить, что заражение может передаваться далеко не только при присваивании и передаче аргументов. В примере выше переменная name, хранящая потенциально заражённые данные, используется для формирования строки, которая будет записана в переменную sql. В результате значение sql также будет потенциально заражённым.
Приёмники заражения (стоки). Приложение уязвимо в случае, если заражённые данные могут попасть в некоторые ключевые точки приложения. Их называют приёмниками заражения (taint sink). Каждой потенциальной уязвимости соответствуют свои приёмники. Для SQL injection, к примеру, приёмником может являться точка передачи строки запроса в объект SQL-команды:
void ProcessRequest(HttpRequest request)
{
string name = request.Form["name"]; // <= источник
// теперь "name" содержит недостоверные/заражённые данные
string sql = $"SELECT * FROM Users WHERE name='{name}'";
ExecuteReaderCommand(sql); // данные передаются далее как аргумент
....
}
void ExecuteReaderCommand(string sql)
{
using (var command = new SqlCommand(sql, _connection)) // <= sink
{
using (var reader = command.ExecuteReader()) { /*....*/ }
}
....
}
Здесь внешние данные из источника (request.Form["name"]) непосредственно используются при формировании SQL-запроса, который далее передаётся в приёмник — конструктор SqlCommand. Задача анализа помеченных данных состоит в проверке наличия пути передачи заражённых данных от источника к приёмнику.
Если проверить вышеприведённый код с помощью PVS-Studio, то результатом станет следующее предупреждение: V5608 Possible SQL injection inside method. Potentially tainted data in the first argument 'sql' is used to create SQL command.
Устранение потенциальных уязвимостей. Для устранения потенциальной уязвимости внешние данные необходимо проверять или преобразовывать в некоторый безопасный вид. Конкретный способ защиты зависит от типа атаки. Например, в случае с SQL injection могут быть использованы параметризованные запросы:
String userName = Request.Form["userName"];
String query = "SELECT * FROM Users WHERE UserName = @userName";
using (var command = new SqlCommand(query, _connection))
{
var userNameParam = new SqlParameter("@userName", userName);
command.Parameters.Add(userNameParam);
using (var reader = command.ExecuteReader())
....
}
Соответственно, при проведении статического анализа, предупреждение на данный код выдано не будет.
Наши доклады и статьи на тему анализа помеченных данных:
- Описание уязвимости Path Traversal.
- Описание уязвимости XSS (межсайтовый скриптинг).
- Описание XEE-атаки (billion laughs attack).
- Описание XXE-атаки (XML External Entity).
- Heisenbug 2022 Spring, Сергей Васильев: "Правильно ли вы парсите XML? Разбираемся с уязвимостями".
- DotNext 2022: "Обработка XML-файлов как причина появления уязвимостей".
- Сергей Васильев: "Уязвимость XSS в приложении ASP.NET: разбираем CVE-2023-24322 в CMS mojoPortal".
- Сергей Васильев: "Парсинг string в enum ценой в 50 Гб: разбираем уязвимость CVE-2020-36620".
- Сергей Васильев: "Почему моё приложение при открытии SVG-файла отправляет сетевые запросы?"
Межпроцедурный и межмодульный контекстно-чувствительный анализ помеченных данных C++ кода
Начнём с простого, но реального примера воспроизводимой уязвимости, обнаруженной в проекте FreeSWITCH:
static const char *basic_gets(int *cnt)
{
....
int c = getchar();
if (c < 0) {
if (fgets(command_buf, sizeof(command_buf) - 1, stdin)
!= command_buf) {
break;
}
command_buf[strlen(command_buf)-1] = '\0'; /* remove endline */
break;
}
....
}
Предупреждение PVS-Studio: V1010 Unchecked tainted data is used in index: 'strlen(command_buf)'.
Анализатор предупреждает о подозрительном обращении по индексу к массиву command_buf. Подозрительным оно считается по той причине, что в качестве индекса используются непроверенные внешние данные. Внешние — потому что получены через функцию fgets из потока stdin, непроверенные — так как никакой проверки перед использованием выполнено не было. Выражение fgets(command_buf, ....) != command_buf не в счёт, так как таким образом проверяется только факт получения данных, но не их содержимое.
Проблема данного кода в том, что при определённых условиях произойдёт запись '\0' за пределы массива, что приведёт к возникновению неопределённого поведения. Для этого достаточно ввести строку нулевой длины. Более подробно найденный дефект и его воспроизведение описано в этой статье в главе про FreeSWITCH.
Рассмотренный реальный пример выявляется с помощью анализа помеченных данных. Однако он не очень интересен, так как всё происходит в одной функции на почти линейном участке кода.
Для демонстрации межпроцедурного анализа и контекстно-чувствительного анализа воспользуемся синтетическим примером:
int getindex() {
int index;
scanf("%d", &index);
return index;
}
void useindex(char *buf, int index) {
buf[index] = 1;
}
void foo() {
char buf[10];
int i = getindex();
useindex(buf, i);
}
Предупреждение PVS-Studio: V1010 Unchecked tainted data is used in the second argument: 'i'. Check lines: 14, 20, 9.
Недостоверные чувствительные данные записываются в переменную index в процессе получения данных извне (вызов функции ввода scanf). Функция getindex возвращает эти недостоверные данные, и они попадают в функцию foo. Далее недостоверное значение передаются в функцию useindex, где используется для обращения к массиву фиксированного размера.
Соответственно, если пользователь введёт, например, значение 33, то возникнет критическая ошибка выхода за границу массива.
Истоком здесь является функция scanf, а стоком — использование помеченных данных в качестве индекса. Приведённый код демонстрирует межпроцедурный контекстно-чувствительный анализ, так как помеченные данные передаются между функциями. Если функции будут находиться в разных файлах, то этот пример будет демонстрировать межпроцедурный контекстно-чувствительный анализ помеченных данных.
Если добавить валидацию введённых данных, например, так:
void foo() {
char buf[10];
int i = getindex();
if (i < 10)
useindex(buf, i);
}
То анализатор PVS-Studio уже не будет выдавать предупреждение V1010.
Наши доклады и статьи на тему анализа помеченных данных C++ кода:
- C++ Russia 2018, Сергей Васильев: "Статический анализ: ищем ошибки... и уязвимости?"
- Сергей Васильев: "Стреляем в ногу, обрабатывая входные данные".
Межпроцедурный и межмодульный контекстно-чувствительный анализ помеченных данных C# кода
Рассмотрим анализ помеченных данных на примере XXE-уязвимости. Описание реального примера будет длинным (вы можете ознакомиться с одним из них здесь), поэтому рассмотрим синтетический вариант.
Представим приложение, которое принимает запросы в виде XML-файлов и обрабатывает товары с соответствующим идентификатором. Если идентификатор задан неверно, приложение сообщает об этом.
Формат XML-файла, с которым работает приложение:
<?xml version="1.0" encoding="utf-8" ?>
<shop>
<itemID>62</itemID>
</shop>
Допустим, обработкой занимается следующий код:
static void ProcessItemWithID(String pathToXmlFile)
{
XmlReaderSettings settings = new XmlReaderSettings()
{
XmlResolver = new XmlUrlResolver(),
DtdProcessing = DtdProcessing.Parse
};
using (var fileReader = File.OpenRead(pathToXmlFile))
{
using (var reader = XmlReader.Create(fileReader, settings))
{
while (reader.Read())
{
if (reader.Name == "itemID")
{
var itemIDStr = reader.ReadElementContentAsString();
if (long.TryParse(itemIDStr, out var itemIDValue))
{
// Process item with the 'itemIDValue' value
Console.WriteLine(
$"An item with the '{itemIDValue}' ID was processed.");
}
else
{
Console.WriteLine($"{itemIDStr} is not valid 'itemID' value.");
}
}
}
}
}
}
Предупреждение PVS-Studio: V5614. OWASP. Potential XXE vulnerability. Insecure XML parser is used to process potentially tainted data.
Для приведённого выше XML-файла приложение распечатает следующую строку:
An item with the '62' ID was processed.
Если вместо номера в ID будет записано что-то другое (например, строка "Hello world"), приложение сообщит об ошибке:
"Hello world" is not valid 'itemID' value.
Несмотря на то, что код делает то, что от него ожидается, он уязвим к XXE-атакам за счёт соблюдения всех перечисленных ранее факторов:
- содержимое XML поступает от пользователя;
- XML-парсер сконфигурирован таким образом, чтобы обрабатывать внешние сущности;
- вывод может передаваться обратно пользователю.
Ниже представлен XML-файл, через который можно скомпрометировать данный код:
<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE foo [
<!ENTITY xxe SYSTEM "file://D:/MySecrets.txt">
]>
<shop>
<itemID>&xxe;</itemID>
</shop>
В этом файле объявляется внешняя сущность xxe, которая будет обработана парсером. Вследствие этого содержимое файла D:/MySecrets.txt (например, такое: 'This is an XXE attack target.'), находящегося на машине, где запущено приложение, будет выдано пользователю:
This is an XXE attack target. is not valid 'itemID' value.
Для того, чтобы обезопаситься от подобной атаки, можно запретить обработку внешних сущностей (присвоить свойству XmlResolver значение null), а также запретить или игнорировать обработку DTD (записать в свойство DtdProcessing значение Prohibit или Ignore соответственно).
Анализатор также учитывает и межпроцедурные вызовы. Рассмотрим пример:
static FileStream GetXmlFileStream(String pathToXmlFile)
{
return File.OpenRead(pathToXmlFile);
}
static XmlDocument GetXmlDocument()
{
XmlDocument xmlDoc = new XmlDocument()
{
XmlResolver = new XmlUrlResolver()
};
return xmlDoc;
}
static void LoadXmlInternal(XmlDocument xmlDoc, Stream input)
{
xmlDoc.Load(input);
Console.WriteLine(xmlDoc.InnerText);
}
static void XmlDocumentTest(String pathToXmlFile)
{
using (var xmlStream = GetXmlFileStream(pathToXmlFile))
{
var xmlDoc = GetXmlDocument();
LoadXmlInternal(xmlDoc, xmlStream);
}
}
В данном случае анализатор выдаст предупреждение на вызов метода LoadXmlInternal, так как отследит, что:
- парсер, полученный из метода GetXmlDocument, может обрабатывать внешние сущности;
- поток, полученный из метода GetXmlStream, содержит данные, полученные из внешнего источника (прочитанные из файла);
- парсер и недостоверные данные передаются в метод LoadXmlInternal, где выполняется обработка XML-файла.
Наши доклады и статьи на тему анализа помеченных данных C# кода:
- Сергей Васильев: "Уязвимости из-за обработки XML-файлов: XXE в C# приложениях в теории и на практике".
- Сергей Васильев: "Под капотом SAST: как инструменты анализа кода ищут дефекты безопасности".
- TechLead Conf 2022, Сергей Васильев: "Под капотом SAST: как инструменты анализа кода ищут дефекты безопасности".
- Никита Липилин, Сергей Васильев: "Почему важно проверять значения параметров общедоступных методов".
- Никита Паневин: "Поймай уязвимость своими руками: пользовательские аннотации C# кода".
- Никита Липилин: "Как taint-анализ защищает код от атак? [SQL Injection] [Path traversal]".
- Сергей Васильев: "OWASP, уязвимости и taint-анализ в PVS-Studio C#. Смешать, но не взбалтывать".
Межпроцедурный и межмодульный контекстно-чувствительный анализ помеченных данных Java кода
Рассмотрим синтетический пример (с использованием Spring Boot) межмодульного контекстно-чувствительного анализа помеченных данных, источником которых является сетевой запрос.
Первый файл — DemoController.java:
@Controller
public class DemoController {
@Autowired
private DemoService service;
@RequestMapping("demo")
public ResponseEntity<DemoObject>
demoEndpoint(@RequestParam(name="name") String name) {
return service.findByName(name)
.map(ResponseEntity::ok)
.orElse(ResponseEntity.notFound().build());
}
}
Метод получает недостоверную информацию (строку). Далее эта строка передаётся без предварительной обработки/проверки в метод findByName.
Второй файл — DemoService.java:
@Service
public class DemoService {
@Autowired
DemoRepository demoRepository;
Optional<DemoObject> findByName(String name) {
return demoRepository.findByName(name);
}
}
Здесь нет обработки/проверки, и метод передаёт строку далее в метод другого класса, также имеющий имя findByName.
Третий файл — DemoRepository.java:
public class DemoRepository {
@Autowired
private JdbcTemplate jdbcTemplate;
Optional<DemoObject> findByName(String name) {
var sql = "SELECT * FROM demoTable WHERE name = '" + name + "'";
if (name.equals("demoCondition")) {
sql = "SELECT * FROM demoTable WHERE name = demoName";
return Optional.ofNullable(
jdbcTemplate.queryForObject(sql, DemoObject.class));
}
return Optional.ofNullable(
jdbcTemplate.queryForObject(sql, DemoObject.class));
}
}
Формируется SQL-запрос, в котором присутствует недостоверная строка. Это является уязвимостью типа SQL-инъекция.
Предупреждение PVS-Studio: V5309 Possible SQL injection. Potentially tainted data in 'sql' variable is used to create SQL command. DemoRepository.java 18, DemoController.java 15
Наши доклады и статьи на тему анализа помеченных данных Java кода:
- JPoint 2023, Сергей Васильев: "Как анализаторы кода ищут ошибки и дефекты безопасности".
- Константин Волоховский: "Поиск потенциальных уязвимостей в коде".
Вспомогательные методы анализа
В стандарте сказано (п. 7.4.), что в состав реализуемых методов статического анализа следует включать следующие методы анализа для поиска дополнительных типов ошибок, а также в качестве вспомогательных анализов:
- Сигнатурный поиск;
- Анализ псевдонимов;
- Анализ косвенных вызовов;
- Статистический анализ;
- Анализ иерархии классов.
Наличие этих видов анализа является не обязательными для статических анализаторов, но желательными. Разберёмся, в чём состоят эти анализы, и приведём примеры использования этих технологий в PVS-Studio.
Сигнатурный поиск
Сигнатурный анализ (п 3.1.28.) — статический анализ, определяющий наличие свойства программы при помощи поиска строк в её исходном коде по некоторому образцу, в том числе заданному с помощью формального языка поиска, например, при помощи регулярных выражений.
Сигнатурный анализ используется в PVS-Studio для реализации диагностических правил для всех языков: C, C++, C#, Java.
Упоминание в определении регулярных выражений может вызвать неправильное представление о сути данной технологии. Большинство диагностических правил, выполняющих сигнатурный анализ, работают с абстрактным синтаксическим деревом и при этом учитывают дополнительную информацию, такую как типы переменных. Соответственно, это более сложный и комплексный вид анализа по сравнению с простым поиском текста по какому-то шаблону. Например, ядро PVS-Studio для анализа C и C++ кода использует регулярные выражения (причём для вспомогательных целей) только в 5 из примерно 700 правил, реализованных на момент написания этого раздела.
Пример диагностического правила для C++ кода
В среднем диагностические правила, построенные на сигнатурном поиске, достаточно просты. Однако это не значит, что выявляемые ими ошибки будут несущественными.
Например, достаточно простым выглядит правило, которое выявляет сравнение переменной с самой собой:
lowerBound[0] == lowerBound[0]
Однако это не придуманный синтетический код, а реальный фрагмент из проекта LLVM (язык C++):
FailureOr<ConstantOrScalableBound>
ScalableValueBoundsConstraintSet::computeScalableBound(....)
{
....
SmallVector<AffineMap, 1> lowerBound(1), upperBound(1);
scalableCstr.cstr.getSliceBounds(pos, 1, value.getContext(), &lowerBound,
&upperBound, closedUB);
auto invalidBound = [](auto &bound) {
return !bound[0] || bound[0].getNumResults() != 1;
};
AffineMap bound = [&] {
if (boundType == BoundType::EQ && !invalidBound(lowerBound) &&
lowerBound[0] == lowerBound[0]) { // <=
return lowerBound[0];
} else if (boundType == BoundType::LB && !invalidBound(lowerBound)) {
return lowerBound[0];
....
}
Предупреждение PVS-Studio: V501 There are identical sub-expressions to the left and to the right of the '==' operator: lowerBound[0] == lowerBound[0]. ScalableValueBoundsConstraintSet.cpp 110
Перед нами опечатка, от которой не застрахованы даже профессиональные разработчики компиляторов. Корректный вариант кода:
lowerBound[0] == upperBound[0]
Примечание. Здесь можно познакомиться с публикациями, посвящёнными поиску ошибок в различных компиляторах с помощью PVS-Studio.
Теперь рассмотрим примеры сигнатурного анализа для C# и Java.
Проект Space Engineers (C#):
private static bool IsTriangleDangerous(int triIndex)
{
if (MyPerGameSettings.NavmeshPresumesDownwardGravity)
{
return triIndex == -1;
}
else
{
return triIndex == -1;
}
}
Предупреждение PVS-Studio: V3004 The 'then' statement is equivalent to the 'else' statement. Sandbox.Game MyNavigationTriangle.cs 189
Проект jBullet (Java):
public class ConeTwistConstraint extends TypedConstraint {
....
private boolean solveTwistLimit;
private boolean solveSwingLimit;
....
public boolean getSolveTwistLimit() {
return solveTwistLimit;
}
public boolean getSolveSwingLimit() {
return solveTwistLimit;
}
}
Предупреждение PVS-Studio: V6091 Suspicious getter implementation. The 'solveSwingLimit' field should probably be returned instead. ConeTwistConstraint.java(407), ConeTwistConstraint.java(74)
Анализ псевдонимов
Анализ псевдонимов (п. 3.1.7.) — статический анализ, позволяющий установить наличие в программе доступа к одной и той же переменной или функции с помощью различных ссылок (указателей).
На момент написания данного раздела анализ псевдонимов используется в PVS-Studio только при анализе C# кода. Продемонстрируем данный вид анализа на синтетическом коде:
object GetPotentialNull() {
Random random = new();
return random.NextDouble() > 0.5 ? new object() : null;
}
void Example_1() {
object potentialNull = GetPotentialNull();
ref object alias = ref potentialNull;
if (alias != null) {
// Правило V3080 не срабатывает,
// т. к. alias и potentialNull - одно и то же значение.
_ = potentialNull.ToString();
}
}
void Example_2()
{
var obj = new object();
ref object alias = ref obj;
alias = GetPotentialNull();
// Срабатывает правило V3080, так как при
// изменении значения alias, меняется и obj.
_ = obj.ToString(); // V3080: Possible null dereference.
}
Анализ косвенных вызовов
Анализ косвенных вызовов (3.1.2.) — статический анализ, позволяющий в программе, использующей вызовы по указателю или вызовы виртуальных функций, установить множество процедур, которые могут вызываться при выполнении заданного косвенного вызова.
На данный момент анализатор PVS-Studio не поддерживает анализ косвенных вызовов. Однако на 2025 год запланирована реализация поиска, например, такой ошибки (язык C):
char *(*fp)(const char* str, int ch);
void f(void) {
char *c;
fp = strchr;
c = fp(0, 2); // Разыменование NULL
}
Анализ косвенных вызовов позволит обнаружить, что первым аргументом функции strchr окажется нулевой указатель.
Статистический анализ
Статистический анализ (п. 3.1.32) — статический анализ, определяющий статистику для некоторого свойства программы, например, насколько часто в программе проверяется возвращаемое значение некоторой функции.
Статистический анализ используется в PVS-Studio для реализации диагностических правил для всех языков: C, C++, C#, Java.
Например, для всех языков реализованы правила, выявляющие аномалию, описанную в определении из ГОСТ. Диагностические правила V1071 (C, C++), V3201 (C#), V6121 (Java) проверяют, насколько часто в программе проверяется/используется возвращаемое значение некоторой функции.
Демонстрационные примеры для перечисленных правил рассматривать не будем, так как они будут достаточно длинные и не очень интересные. Рассмотрим статистический анализ на примере другого правила. Проект Linux Kernel (язык C):
static const
struct XGI330_LCDDataDesStruct2 XGI_LVDSNoScalingDesData[] = {
{0, 648, 448, 405, 96, 2}, /* 00 (320x200,320x400,
640x200,640x400) */
{0, 648, 448, 355, 96, 2}, /* 01 (320x350,640x350) */
{0, 648, 448, 405, 96, 2}, /* 02 (360x400,720x400) */
{0, 648, 448, 355, 96, 2}, /* 03 (720x350) */
{0, 648, 1, 483, 96, 2}, /* 04 (640x480x60Hz) */
{0, 840, 627, 600, 128, 4}, /* 05 (800x600x60Hz) */
{0, 1048, 805, 770, 136, 6}, /* 06 (1024x768x60Hz) */
{0, 1328, 0, 1025, 112, 3}, /* 07 (1280x1024x60Hz) */
{0, 1438, 0, 1051, 112, 3}, /* 08 (1400x1050x60Hz)*/
{0, 1664, 0, 1201, 192, 3}, /* 09 (1600x1200x60Hz) */
{0, 1328, 0, 0771, 112, 6} /* 0A (1280x768x60Hz) */
};
Предупреждение PVS-Studio: V536 Be advised that the utilized constant value is represented by an octal form. Oct: 0771, Dec: 505. vb_table.h 1379
Статистическая аномалия состоит в том, что только одно число в массиве является восьмеричным (0771 в последней строке). Ноль, делающий литерал восьмеричным, лишний, и вписан для выравнивания столбика чисел.
Анализ иерархии классов
Анализ иерархии классов (п 3.1.1.) — статический анализ, позволяющий выявить в программах на объектно-ориентированных языках список классов, реализованных в программе, а также отношения наследования между этими классами.
Анализ иерархии классов используется в PVS-Studio для реализации диагностических правил для всех объектно-ориентированных языков: C++, C#, Java.
Данный вид анализа, также как синтаксический анализ, является базовым и активно используется всеми ядрами анализатора PVS-Studio. Без него невозможно большинство других видов анализа.
Поскольку анализ иерархии классов является неотъемлемой частью всех ядер PVS-Studio и работает схожим образом для всех поддерживаемых языков, то рассмотрим только один пример использования.
Проект Blender (язык C++). Для начала рассмотрим базовый класс CurvesFieldInput:
typedef struct CurvesGeometry { .... };
namespace bke
{
....
class CurvesGeometry : public ::CurvesGeometry { .... };
class CurvesFieldInput : public fn::FieldInput
{
....
virtual std::optional<AttrDomain> preferred_domain(
const CurvesGeometry &curves) const;
};
....
}
Обратим внимание, что виртуальная функция preferred_domain принимает параметр типа bke::CurvesGeometry. Теперь посмотрим на класс-наследник:
namespace blender::nodes::node_geo_input_curve_handles_cc
{
class HandlePositionFieldInput final : public bke::CurvesFieldInput
{
....
std::optional<AttrDomain> preferred_domain(
const CurvesGeometry & /*curves*/) const;
};
}
Предупреждение PVS-Studio: V762 It is possible a virtual function was overridden incorrectly. See first argument of function 'preferred_domain' in derived class 'HandlePositionFieldInput' and base class 'CurvesFieldInput'. node_geo_input_curve_handles.cc 95
В базовом классе виртуальная функция принимает параметр с неквалифицированным именем CurvesGeometry. Когда компилятор будет осуществлять поиск этого типа, он начнёт с области видимости класса CurvesFieldInput и будет заглядывать во все обрамляющие области видимости, пока не встретит этот тип. В итоге будет найден тип bke::CurvesGeometry.
Теперь посмотрим на производный класс. Он определён в пространстве имён, отличном от того, где располагается базовый класс. Компилятор также начнёт поиск нужного имени CurvesGeometry, не встретит его в обрамляющих областях видимости и дойдёт до глобального. А в глобальном пространстве имён тоже есть CurvesGeometry, только не тот, что нам нужен для переопределения функции.
Чтобы выявлять такую ошибку, анализатор должен собрать информацию о типах, иерархии классов и областях видимости.
Выявляемые типы критических ошибок
PVS-Studio выявляет все типы критических ошибок для поддерживаемых языков: C, C++, C#, Java. В будущем возможно расширение списка поддерживаемых языков.
Для компилируемых языков PVS-Studio выявляет следующие типы критических ошибок, перечисленных в ГОСТ (п. 6.3.).
Типы критических ошибок в компилируемых языках (п. 6.3.) |
C и C++ |
C# |
Java |
---|---|---|---|
Ошибки непроверенного использования чувствительных данных (ввода пользователя, файлов, сети и пр.) |
✓ |
✓ |
✓ |
Ошибки целочисленного переполнения и некорректного совместного использования знаковых и беззнаковых чисел |
✓ |
✓ |
✓ |
Ошибки переполнения буфера (записи или чтения за пределами выделенной для буфера памяти) |
✓ |
✓ |
✓ |
Ошибки некорректного использования системных процедур и интерфейсов, связанных с обеспечением информационной безопасности (шифрования, разграничения доступа и пр.) |
✓ |
✓ |
✓ |
Ошибки при работе с многопоточными примитивами (интерфейсами запуска потоков на выполнение, синхронизации и обмена данными между потоками и пр.) |
✓ |
✓ |
✓ |
Таблица N3. Выявляемые типы критических ошибок в компилируемых языках, перечисленные в ГОСТ Р 71207–2024 (п. 6.3.).
Стандарт дополнительно перечисляет несколько типов критических ошибок, специфичных для языков C и C++ (п. 6.5.). Анализатор PVS-Studio обеспечивает их обнаружение.
Дополнительные типы критических ошибок для C и C++ (п. 6.5.) |
C и C++ |
---|---|
Ошибки разыменования нулевого указателя |
✓ |
Ошибки деления на ноль |
✓ |
Ошибки управления динамической памятью (выделения, освобождения, использования освобождённой памяти) |
✓ |
Ошибки использования форматной строки |
✓ |
Ошибки использования неинициализированных переменных |
✓ |
Ошибки утечек памяти, незакрытых файловых дескрипторов и дескрипторов сетевых соединений |
✓ |
Таблица N4. Выявляемые типы критических ошибок, являющиеся дополнительными для языков C и C++ и перечисленные в ГОСТ Р 71207–2024 (п. 6.5.).
Пояснение. Анализатор PVS-Studio умеет обнаруживать, например, деление на ноль не только в C и C++ коде, но и в C# и Java. Однако с точки зрения ГОСТ Р 71207–2024 деление на ноль в C# и Java коде не является критической ошибкой. Этому есть обоснование. Деление на ноль в программе на языке C или C++ приводит к неопределённому поведению, то есть к серьёзной критической ошибке. Деление на ноль в C# или Java приведёт к возникновению исключения. Это тоже ошибка, но она, скорее всего, не вызовет критические последствия. Аналогично с доступом к нулевой ссылке и так далее.
Детекторы критических ошибок
Для выявления перечисленных выше типов критических ошибок в PVS-Studio реализованы детекторы ошибок (диагностические правила), со списком которых вы можете познакомиться здесь.
Другие детекторы ошибок
Надо понимать, что список типов критических ошибок условен. Критическая ошибка, приводящая к записи за границу буфера в некотором приложении, может максимум только испортить какой-то рисунок, но не влияет на безопасность.
И наоборот, опечатка в коде, формально не попадающая ни под один тип перечисленных в ГОСТ Р 71207–2024 критических ошибок, может являться серьёзным дефектом безопасности. Из-за неё, например, неправильно происходит проверка каких-то приватных данных. Фактически эта ошибка является критической.
Рассмотрим в качестве примера баг, найденный нами в проекте RavenDB (язык C#):
public enum SecurityClearance
{
UnauthenticatedClients, //Default value
ClusterAdmin,
ClusterNode,
Operator,
ValidUser
}
public override void VerifyCanExecuteCommand(....)
{
....
var definition = JsonDeserializationServer.CertificateDefinition(read);
if (
definition.SecurityClearance != SecurityClearance.ClusterAdmin ||
definition.SecurityClearance != SecurityClearance.ClusterNode
)
return;
AssertClusterAdmin(isClusterAdmin);
}
Предупреждение PVS-Studio: V3022 Expression is always true. Probably the '&&' operator should be used here. DeleteCertificateFromClusterCommand.cs 21
Проверка не имеет смысла. Переменная всегда будет не равна или одной, или другой константе. Поэтому результат проверки всегда истинный. Здесь должно быть написано:
definition.SecurityClearance != SecurityClearance.ClusterAdmin &&
definition.SecurityClearance != SecurityClearance.ClusterNode
Или
definition.SecurityClearance == SecurityClearance.ClusterAdmin ||
definition.SecurityClearance == SecurityClearance.ClusterNode
Ошибка связана с неправильной проверкой некоторого внутреннего состояния, что приводит к неверному пути выполнения программы. Это однозначно серьёзная ошибка в функции, связанной с логикой управления правами. Однако непонятно, каким типом критической ошибки можно классифицировать найденную опечатку.
Мы рассмотрели пример, где сложно классифицировать опечатку как критическую ошибку, но по факту она ей является. Как же тогда интерпретировать типы критических ошибок, описанных в ГОСТ, и работать с предупреждениями анализаторов?
Одни ошибки с большей вероятностью могут привести к дефектам безопасности, чем другие. Выход за границу буфера потенциально более опасен, чем неправильное использование #pragma warning (V665).
ГОСТ Р 71207–2024 выделяет группу ошибок, которые с наибольшим шансом могут привести к возникновению уязвимости. Это и есть список критических ошибок. Эти ошибки должны выявляться в первую очередь и обязательно исправляться. Предупреждения про критические ошибки являются первоочередными в сравнении со всеми другими предупреждениями анализаторов, так как их исправление вносят наибольший вклад в безопасность приложения.
Однако это не значит, что другие предупреждения должны быть проигнорированы. Их можно и нужно изучать, хотя не в таких жёстких временных рамках. Временные рамки поиска и исправления критических ошибок описаны в п.5.6., п.5.8., п.5.9.
Анализатор PVS-Studio, помимо критических ошибок, выявляет большое количество других ошибок, которые также могут являться дефектами безопасности. С полным списком детекторов можно ознакомиться на этой странице.
Примеры выявления всех типов критических ошибок с помощью PVS-Studio
Кратко опишем каждый из типов критических ошибок и приведём примеры их выявления с помощью PVS-Studio. Предпочтение будет отдаваться реальным случаям выявления ошибок, взятых из нашей коллекции багов в открытых проектах. Эти ошибки не обязательно являются дефектами безопасности, но зато демонстрируют работу PVS-Studio в реальных условиях. В случае, если короткого и красивого примера нет, будет составлен синтетический пример.
Ошибки непроверенного использования чувствительных данных (п. 6.3.а.)
Описание данного вида дефектов и соответствующие примеры уже были рассмотрены в главе "Межпроцедурный и межмодульный контекстно-чувствительный анализ помеченных данных".
Ошибки целочисленного переполнения и некорректного совместного использования знаковых и беззнаковых чисел (п. 6.3.б.)
Данные вид дефектов может быть использован в атаках для получения неких недопустимых значений, влияющих на ход выполнения программы, отличный от предусмотренного.
Дополнительные ссылки:
- Википедия. Целочисленное переполнение.
- CWE-190: Integer Overflow or Wraparound.
- CWE-680: Integer Overflow to Buffer Overflow.
- Peng Li and John Regehr: "Understanding Integer Overflow in C/C++".
- Дэвин МакКолл: "Почему перенос при целочисленном переполнении - не очень хорошая идея".
- Андрей Карпов, Дмитрий Свиридкин: "Путеводитель C++ программиста по неопределённому поведению: часть 2 из 11" (см. главу "Целые и вещественные числа: переполнение целых знаковых чисел").
Пример выявления ошибки в C или C++ коде (проект Hypertext Preprocessor, C)
PHP_CLI_API size_t sapi_cli_single_write(....)
{
....
size_t shell_wrote;
shell_wrote = cli_shell_callbacks.cli_shell_write(....);
if (shell_wrote > -1) {
return shell_wrote;
}
....
}
Предупреждение PVS-Studio: V605 Consider verifying the expression: shell_wrote > - 1. An unsigned value is compared to the number -1. php_cli.c 266
Пример демонстрирует некорректное совместное использование знаковых и беззнаковых чисел. Перед сравнением числовой литерал -1 типа int будет неявно преобразован в значение SIZE_MAX типа size_t. Условие никогда не выполнится.
Пример выявления ошибки в C# коде
bool IsValidAddition(ushort x, ushort y)
{
if (x + y < x)
return false;
return true;
}
Предупреждение PVS-Studio: V3204. The expression is always false due to implicit type conversion. Overflow check is incorrect.
Цель данного метода — проверить, произойдёт ли переполнение при сложении двух положительных чисел. В случае переполнения результат суммы должен оказаться меньше любого из её операндов.
Однако проверка не выполнит свою задачу, поскольку оператор '+' не имеет перегрузки для сложения чисел с типом ushort. В результате оба числа будут в начале приведены к типу int, после чего выполнится их сложение. Так как складываются значения типа int, никакого переполнения не произойдёт, и условие всегда будет давать значение false.
Пример выявления ошибки в Java коде (проект Apache Hive)
public void logSargResult(int stripeIx, boolean[] rgsToRead)
{
....
long val = 0;
for (int j = 0; j < 64; ++j) {
int ix = valOffset + j;
if (rgsToRead.length == ix) break;
if (!rgsToRead[ix]) continue;
val = val | (1 << j); // <=
}
....
}
Предупреждение PVS-Studio: V6034 Shift by the value of 'j' could be inconsistent with the size of type: 'j' = [0 .. 63]. IoTrace.java 272
Ошибка заключается в невозможности корректно выставить 32 старших разряда в 64-битной переменной val.
В указанной строке индуктивная переменная (п.3.1.10.) j может принимать значение в диапазоне [0..63]. В выражении (1 << j) числовой литерал 1 имеет 32-битный тип int. Соответственно, при сдвиге единицы на 32 и более разряда будет происходить переполнение.
Для исправления ситуации необходимо написать (1L << j).
Ошибки переполнения буфера (п. 6.3.в.)
Переполнение буфера (Buffer Overflow) — запись или чтение программой данных за пределами выделенного для этого в памяти буфера. Обычно возникает из-за неправильной работы с данными и памятью, при отсутствии жёсткой защиты со стороны подсистемы программирования и ОС.
Так как большинство языков программирования размещают данные программы в стеке процесса, смешивая их с управляющими данными, переполнение буфера является одним из способов атаки на ПО, позволяющим загрузить и выполнить произвольный машинный код от имени программы или повлиять на логику работы программы, модифицировав данные за пределом буфера.
Дополнительные ссылки:
- Brendan Watters: "Stack-Based Buffer Overflow Attacks: Explained and Examples".
- Dhaval Kapil: "Buffer Overflow Exploit".
- Андрей Карпов, Дмитрий Свиридкин: "Путеводитель C++ программиста по неопределённому поведению: часть 8 из 11" (см. главу "Исполнение программы: переполнение буфера").
Пример выявления ошибки в C или C++ коде (проект ICU, C)
static char plugin_file[2048] = "";
U_CAPI void U_EXPORT2 uplug_init(UErrorCode *status)
{
....
// uprv_strncat раскрывается в strncat
uprv_strncpy(plugin_file, plugin_dir, 2047);
uprv_strncat(plugin_file, U_FILE_SEP_STRING, 2047);
uprv_strncat(plugin_file, "icuplugins", 2047);
uprv_strncat(plugin_file, U_ICU_VERSION_SHORT, 2047);
uprv_strncat(plugin_file, ".txt", 2047);
....
}
Здесь анализатор PVS-Studio выдаёт несколько однотипных предупреждений: V645 The 'strncat' function call could lead to the 'plugin_file' buffer overflow. The bounds should not contain the size of the buffer, but a number of characters it can hold. icuplug.c
Многие программисты используют эту функцию вместо strcat, чтобы предотвратить выход за границу буфера, но делают это неправильно. Это как раз такой случай. Третий аргумент функции strncat задаёт не размер буфера, а максимальное количество символов, которые можно добавить. В результате этот код конкатенации строк не защищён от переполнения буфера.
Пример выявления ошибки в C# коде (проект Flax Engine)
Выход за границу массива в C# не представляет существенную опасность, так как в этом случае будет сгенерировано исключение. Так что, пожалуй, для программ на языке C# эту ошибку, на самом деле, не стоит считать критической. Но раз формально стандарт требует выявления в компилируемых языках данного вида дефекта, то рассмотрим соответствующий пример:
public Matrix2x2(float[] values)
{
....
if (values.Length != 4)
throw new ArgumentOutOfRangeException(....);
M11 = values[0];
M12 = values[1];
M21 = values[3];
M22 = values[4];
}
Предупреждение PVS-Studio: V3106 Possibly index is out of bound. The '4' index is pointing beyond 'values' bound. Matrix2x2.cs 98
Выполняя анализ потока данных и управления, анализатор знает, что, если управление дошло до извлечения значений массива, то этот массив содержит 4 элемента. Соответственно, последний индекс должен быть равен 3, а не 4.
Если присмотреться, то становится очевидна опечатки при написании кода — случайно написали 3 вместо 2, а затем 4 вместо 3. Так что, на самом деле, здесь даже не одна ошибка, а сразу две.
Пример выявления ошибки в Java коде (проект ELKI)
Как и в C#, выход за границу массива в Java не представляет существенную опасность, так как в этом случае будет сгенерировано исключение.
@Override
public double[] computeMean() {
return points.size() == 1 ? points.get(1) : null;
}
Предупреждение PVS-Studio: V6025 Index '1' is out of bounds. GeneratorStatic.java(104)
Простая опечатка, приводящая к выходу за границу массива. Чтобы извлечь один единственный элемент из массива, следовало написать points.get(0).
Ошибки некорректного использования системных процедур и интерфейсов, связанных с обеспечением информационной безопасности (п. 6.3.г.)
Достаточно обобщённое название критической ошибки, что в общем-то неизбежно. Существует огромное количество вариантов неправильного использования функций шифрования, разграничения доступа и так далее. Соответственно, решение этой задачи — в выявлении большого количества модельных вариантов ошибок (п. 3.1.19.).
Пример выявления ошибки в C или C++ коде (проект Android, C)
static void FwdLockGlue_InitializeRoundKeys() {
unsigned char keyEncryptionKey[KEY_SIZE];
....
memset(keyEncryptionKey, 0, KEY_SIZE); // Zero out key data.
}
Предупреждение PVS-Studio: V597 The compiler could delete the 'memset' function call, which is used to flush 'keyEncryptionKey' buffer. The memset_s() function should be used to erase the private data. FwdLockGlue.c 102
Компилятор вправе удалить вызов функции memset, так как это не изменит наблюдаемое поведение программы с точки зрения C и C++. После вызова memset буфер гарантированно не используется, следовательно, его не нужно заполнять нулями. В результате в памяти остаются приватные данные, которые потенциально могут быть куда-то переданы.
Детальнее про этот дефект безопасности:
- CWE-14: Compiler Removal of Code to Clear Buffers.
- Безопасная очистка приватных данных.
- Это очень распространённая ошибка. Примеры детектирования в различных проектах.
Пример выявления ошибки в C# коде
private static string CalculateSha1(string text, Encoding enc)
{
var buffer = enc.GetBytes(text);
using var cryptoTransformSha1 = new SHA1CryptoServiceProvider();
var hash = BitConverter.ToString(cryptoTransformSha1.ComputeHash(buffer))
.Replace("-", string.Empty);
return hash.ToLower();
}
Предупреждение PVS-Studio: V5613. Use of outdated cryptographic algorithm is not recommended.
Используется устаревшая криптографическая функция.
Пример выявления ошибки в Java коде
public void foo() {
Random rnd = new Random(4040);
....
}
Предупреждение PVS-Studio: V6109. Potentially predictable seed is used in pseudo-random number generator.
Анализатор обнаружил подозрительный код, инициализирующий генератор псевдослучайных чисел константным значением. Числа, сгенерированные таким генератором, можно предугадать — они будут воспроизводиться снова и снова при каждом запуске программы. Потенциально это может сказаться на безопасности приложения, использующего псевдослучайные числа в задачах, связанных с криптографией (см. также "CWE-336: Same Seed in Pseudo-Random Number Generator (PRNG)").
Ошибки при работе с многопоточными примитивами (интерфейсами запуска потоков на выполнение, синхронизации и обмена данными между потоками и пр.) (п. 6.3.д.)
Выявление ошибок, связанных с использованием многопоточных примитивов, — одна из самых сложных задач для статических анализаторов кода. Отслеживание взаимодействия различных частей программы, которые могут одновременно обращаться к одним и тем же ресурсам, обладает высокой вычислительной сложностью.
По причине сложности задачи выявление этого вида критических ошибок является необязательным для реализации в статических анализаторах (п. 7.3.).
Как и в случае с предыдущим разделом, выявление ошибок при работе с многопоточными примитивами в основном сводится к обнаружению множества модельных вариантов ошибок (3.1.19).
Пример выявления ошибки в C или C++ коде (проект Zephyr, C)
static int nvs_startup(struct nvs_fs *fs)
{
....
k_mutex_lock(&fs->nvs_lock, K_FOREVER);
....
if (fs->ate_wra == fs->data_wra && last_ate.len) {
return -ESPIPE; // <= (A)
}
....
end:
k_mutex_unlock(&fs->nvs_lock);
return rc;
}
Предупреждение PVS-Studio: V1020 The function exited without calling the 'k_mutex_unlock' function. Check lines: 620, 549. nvs.c 620
Мьютекс останется захваченным, если выход из программы произойдёт в точке (A).
Пример выявления ошибки в C# коде (проект RunUO)
private Packet m_RemovePacket;
....
private object _rpl = new object();
public Packet RemovePacket
{
get
{
if (m_RemovePacket == null)
{
lock (_rpl)
{
if (m_RemovePacket == null)
{
m_RemovePacket = new RemoveItem(this);
m_RemovePacket.SetStatic();
}
}
}
return m_RemovePacket;
}
}
Предупреждение PVS-Studio: V3054 Potentially unsafe double-checked locking. Use volatile variable(s) or synchronization primitives to avoid this. Item.cs 1624
В данном коде паттерн блокировки с двойной проверкой реализован некорректно. При обращении к свойству RemovePacket геттер осуществляет проверку поля m_RemovePacket на равенство null. Если проверка проходит, то мы попадаем в тело оператора lock, где и происходит инициализация поля m_RemovePacket.
Сбой возникает в тот момент, когда главный поток уже инициализировал переменную m_RemovePacket посредством конструктора, но ещё не вызвал метод SetStatic. Теоретически другой поток может обратиться к свойству RemovePacket именно в этот самый неудачный момент. Проверка m_RemovePacket на равенство null уже не пройдёт, и вызывающий поток получит ссылку на неполностью готовый к использованию объект.
Пример выявления ошибки в Java коде (проект DBeaver)
public class MultiPageWizardDialog extends .... {
....
private volatile int runningOperations = 0;
....
@Override
public void run(....) {
....
try {
runningOperations++; // <=
ModalContext.run(
runnable,
true,
monitorPart,
getShell().getDisplay()
);
} finally {
runningOperations--; // <=
....
}
}
}
Предупреждения PVS-Studio:
- V6074 Non-atomic modification of volatile variable. Inspect 'runningOperations'. MultiPageWizardDialog.java(590)
- V6074 Non-atomic modification of volatile variable. Inspect 'runningOperations'. MultiPageWizardDialog.java(593)
Неатомарное изменение volatile-переменной может привести к состоянию гонки. Известно, что использование модификатора volatile гарантирует, что все потоки будут видеть актуальное значение соответствующей переменной. К этому можно добавить, что модификатор volatile используется для того, чтобы указать JVM, что все операции присвоения этой переменной и все операции чтения из неё должны быть атомарными.
Можно посчитать, что пометки переменных как volatile будет достаточно, чтобы безопасно их использовать в многопоточном приложении. Однако инкремент переменной — неатомарная операция, состоящая из чтения, изменения и записи данных. Подробнее суть проблемы описана здесь.
Ошибки разыменования нулевого указателя (6.5.а., только для C и C++)
Проблема разыменования нулевых указателей вечна и сложнее, чем может показаться на первый взгляд. Любое ли разыменование нулевого указателя приводит к неопределённому поведению? Есть ли исключения и нюансы? Обсуждение этих вопросов вы можете найти здесь:
- Андрей Карпов: "Разыменовывание нулевого указателя приводит к неопределённому поведению".
- Андрей Карпов, Дмитрий Свиридкин: "Путеводитель C++ программиста по неопределённому поведению: часть 9 из 11" (см. главу "Исполнение программы: разыменование нулевых указателей").
- Андрей Карпов: "Четыре причины проверять, что вернула функция malloc".
- C++ on Sea 2023, JF Bastien: "*(char*)0 = 0; - What Does the C++ Programmer Intend With This Code?"
Анализатор использует для поиска разыменования нулевых указателей несколько технологий:
- Межпроцедурный и межмодульный контекстно-чувствительный анализ потока данных;
- Чувствительный к путям выполнения анализ потоков данных и управления;
- Эмпирические диагностические правила (поиск модельных вариантов ошибок).
С первыми двумя всё понятно: анализатор пытается вычислить, может ли указатель быть нулевым в момент разыменования. Пример ошибки, найденной в проекте LLVM (язык C++).
Вначале рассмотрим функцию SetInsertPoint в файле IRBuilder.h:
void SetInsertPoint(Instruction *I)
{
BB = I->getParent();
InsertPt = I->getIterator();
assert(InsertPt != BB->end() && "Can't read debug loc from end()");
SetCurrentDebugLocation(I->getStableDebugLoc());
}
Обратите внимание, что указатель I сразу разыменовывается без какой-либо проверки.
Теперь рассмотрим использование это функции, происходящее в другом файле OMPIRBuilder.cpp (межмодульный анализ):
std::pair<Value *, Value *> OpenMPIRBuilder::emitAtomicUpdate
(InsertPointTy AllocaIP, ...., bool IsXBinopExpr)
{
....
if (UnreachableInst *ExitTI = dyn_cast<UnreachableInst>
(ExitBB->getTerminator()))
{
CurBBTI->eraseFromParent();
Builder.SetInsertPoint(ExitBB); // <= ненулевой указатель
}
else
{
Builder.SetInsertPoint(ExitTI); // <= нулевой указатель
}
return Res;
}
Предупреждение PVS-Studio: V522 Dereferencing of the null pointer 'I' might take place. The null pointer is passed into 'SetInsertPoint' function. Inspect the first argument. Check lines: 'IRBuilder.h:188', 'OMPIRBuilder.cpp:5983'.
Если выполняется ветка else, то указатель ExitTI будет нулевым. Соответственно, в функцию SetInsertPoint будет передан нулевой указатель, где он и будет разыменован.
Однако в общем виде вычислить возможные значение указателей невозможно. Тогда могут помочь вспомогательные механизмы, построенные на эмпирических алгоритмах. Рассмотрим пример работы одного из таких детекторов ошибок (проект MuseScore, С++):
Ms::Segment* NotationSelectionRange::rangeStartSegment() const
{
Ms::Segment* startSegment = score()->selection().startSegment();
startSegment->measure()->firstEnabled(); // <= разыменование
if (!startSegment) { // <= проверка
return nullptr;
}
if (!startSegment->enabled()) {
startSegment = startSegment->next1MMenabled();
}
....
}
Пусть анализатор не может вычислить значение startSegment. Однако он замечает следующую аномалию: указатель сначала разыменовывается, а затем проверяется. Раз указатель проверяется, значит автор кода предполагает, что он может быть нулевым. Следовательно, разыменование является опасным.
Анализатор PVS-Studio выдаёт предупреждение: V595 The 'startSegment' pointer was utilized before it was verified against nullptr. Check lines: 129, 131. notationselectionrange.cpp 129 (подробнее про данный детектор — Пояснение про диагностическое правило V595).
Ошибки деления на ноль (6.5.б., только для C и C++)
Известная классическая ошибка. Кстати, в силу того, что все программисты про неё знают, она встречается на практике в коде значительно реже, чем может казаться (см. доклад "Ошибки в коде: ожидания и реальность").
Проект VNL (язык C):
integer pow_ii(integer *ap, integer *bp)
{
integer pow, x, n;
....
if (x != -1)
return x == 0 ? 1/x : 0;
....
}
Предупреждение PVS-Stuidio: V609 Divide by zero. Denominator 'x' == 0. pow_ii.c 28
Если x равен 0, то произойдёт деление на ноль. Видимо, это опечатка, и, скорее всего, программист планировал написать так:
return x != 0 ? 1/x : 0;
Ошибки управления динамической памятью (выделения, освобождения, использования освобождённой памяти) (6.5.в., только для C и C++)
Первый пример
Проект Shareaza (язык C):
int SetSkinAsDefault()
{
TCHAR szXMLNorm[MAX_PATH];
....
else {
free(szXMLNorm);
return 0;
}
return 1;
}
Предупреждение PVS-Studio: V726 An attempt to free memory containing the 'szXMLNorm' array by using the 'free' function. This is incorrect as 'szXMLNorm' was created on stack. utils.c 92
В одной из веток выполнения программы происходит попытка освобождения памяти, выделенной на стеке, с помощью функции free.
Второй пример
Проект CodeLite (язык C++):
int clSocketBase::ReadMessage(wxString& message, int timeout)
{
....
size_t message_len(0);
....
message_len = ::atoi(....);
....
std::unique_ptr<char> pBuff(new char[message_len]);
....
}
Предупреждение PVS-Studio: V554 Incorrect use of unique_ptr. The memory allocated with 'new []' will be cleaned using 'delete'. clSocketBase.cpp:282
Неправильное использование умного указателя. Для освобождения памяти будет использован оператор delete, а не delete []. Это приводит к неопределённому поведению (см. "Почему в С++ массивы нужно удалять через delete[]"). Правильный вариант кода:
std::unique_ptr<char []> pBuff(new char[message_len]);
Ошибки использования форматной строки (6.5.г., только для C и C++)
Некорректное использование форматной строки может приводить к разнообразным ошибкам, в том числе являться уязвимостью (см. публикацию "Не зная брода, не лезь в воду. Часть вторая").
Проект Open X-Ray Engine (язык C++):
void safe_verify(....)
{
....
printf("FATAL ERROR (%s): failed to verify data\n");
....
}
Предупреждение PVS-Studio: V576 Incorrect format. A different number of actual arguments is expected while calling 'printf' function. Expected: 2. Present: 1. entry_point.cpp 41
Отсутствует аргумент, который должен быть распечатан в качестве строки.
Дополнительные ссылки:
- Михаил Зинин: "C++: сеанс спонтанной археологии и почему не стоит использовать вариативные функции в стиле C".
- LiveOverflow: "A simple Format String exploit example - bin 0x11".
Ошибки использования неинициализированных переменных (6.5.д., только для C и C++)
Проект System Shock (язык C):
errtype uiInit(uiSlab* slab)
{
....
errtype err;
....
// err = ui_init_cursors();
....
if (err != OK) return err;
....
}
Предупреждение PVS-Studio: V614 Uninitialized variable 'err' used. EVENT.C 953
В какой-то момент строчка, где происходила запись в переменную err, была закомментирована, а проверка этой переменной осталась. Получается, что в условии используется неинициализированная переменная.
Дополнительные ссылки:
- Терминология. Неинициализированная переменная.
- Терминология. Использование неинициализированной памяти.
- Андрей Карпов, Дмитрий Свиридкин: "Путеводитель C++ программиста по неопределённому поведению: часть 10 из 11" (см. главу "Исполнение программы: неинициализированные переменные").
- Андрей Карпов: "Исследование COVID-19 и неинициализированная переменная".
Ошибки утечек памяти, незакрытых файловых дескрипторов и дескрипторов сетевых соединений (6.5.е., только для C и C++)
Первый пример
Проект Notepad++ (язык C++):
bool ProjectPanel::openWorkSpace(const TCHAR *projectFileName)
{
TiXmlDocument *pXmlDocProject = new TiXmlDocument(....);
bool loadOkay = pXmlDocProject->LoadFile();
if (!loadOkay)
return false;
....
}
Предупреждение PVS-Studio: V773 The function was exited without releasing the 'pXmlDocProject' pointer. A memory leak is possible. projectpanel.cpp 326
Утечка памяти. Если не удастся загрузить файл, то функция досрочно завершит работу, не освободив указатель pXmlDocProject.
Второй пример
Проект CMake (язык C):
RHASH_API int rhash_file(....)
{
FILE* fd;
rhash ctx;
int res;
hash_id &= RHASH_ALL_HASHES;
if (hash_id == 0) {
errno = EINVAL;
return -1;
}
if ((fd = fopen(filepath, "rb")) == NULL) return -1;
if ((ctx = rhash_init(hash_id)) == NULL) return -1;
....
}
Предупреждение PVS-Studio: V773 The function was exited without closing the file referenced by the 'fd' handle. A resource leak is possible. rhash.c 450
Утечка файлового дескриптора. Если функция rhash_init вернёт NULL, то функция rhash_file досрочно завершится, вернув статус ошибки. При этом не будет закрыт файловый дескриптор, хранящийся в переменной fd.
Соответствие требованиям к методам анализа
В предыдущих главах уже было подробно разобрано соответствие PVS-Studio требованиям, перечисленным в ГОСТ Р 71207–2024 (раздел 7):
- методы анализа обеспечивают поиск критических ошибок всех типов (п. 7.3.);
- реализованы все основные методы и ряд вспомогательных анализов, перечисленные в стандарте (п. 7.4.).
Остановимся на оставшихся пунктах из 7-го раздела стандарта.
Глубина поддерживаемого статическим анализатором межпроцедурного анализа
Согласно ГОСТ Р 71207–2024 (п. 7.4.), максимальная глубина поддерживаемого межпроцедурного анализа (количество вызовов процедур, через которые может передаваться собираемая в ходе анализа информация о потоке данных программы) не должна быть заранее ограничена, но может определяться с учётом доступных для анализа вычислительных ресурсов.
В PVS-Studio нет фиксированного ограничения на глубину анализа. Остановка осуществляется на основании эмпирических алгоритмов, защищающих от зацикливания (рекурсивных вызовов), и слишком сложном/долгом анализе вызываемых процедур.
Учёт межмодульных связей и параметров сборки
Согласно ГОСТ Р 71207–2024 (п. 7.5.), при анализе должны уточняться межмодульные связи и параметры компиляторов.
PVS-Studio учитывает параметры (ключи) компиляторов, используемые при сборке ПО. Это неотъемлемая часть выполнения анализа, так как без этого, например, невозможно в C++ программе корректно выяснить, какая модель данных используется (размеры типов), раскрыть макросы, найти подключаемые библиотеки и так далее. Анализатор учитывает межмодульные связи, так как без этого невозможен межмодульный анализ.
Способы конфигурации анализа помеченных данных
Согласно ГОСТ Р 71207–2024 (п. 7.6.), если статический анализатор для поиска ошибок (п. 6.3.а.) применяет анализ помеченных данных, должна быть предоставлена возможность конфигурации анализа: должны задаваться процедуры-источники и процедуры-стоки чувствительных данных.
PVS-Studio поддерживает анализ помеченных данных для поиска критических ошибок, описанных в п. 6.3.а:
6.3. а) ошибки непроверенного использования чувствительных данных (ввода пользователя, файлов, сети и пр.).
Соответственно, PVS-Studio реализует и возможность конфигурации анализа.
Исключением является ядро Java анализатора, для которого на момент написания данного раздела возможность разметки истоков и стоков отсутствует. Поддержка данной функциональности запланирована на первую половину 2025 года.
Аннотация процедур-источников и стоков помеченных данных осуществляется с помощью специализированных файлов в формате JSON. Подключить файл аннотаций можно следующими способами:
Способ N1. Добавить специальный комментарий в исходный код или в файл конфигурации диагностических правил (.pvsconfig):
//V_PVS_ANNOTATIONS, language:%язык_проекта%, path:%путь/до/файла.json%
Вместо символа подстановки %язык_проекта% предполагается использование одного из следующих значений:
- для С — с;
- для С++ — cpp;
- для С# — csharp.
Вместо символа подстановки %путь/до/файла.json% предполагается путь до подключаемого файла аннотаций. Поддерживаются как абсолютные, так и относительные пути. Относительные пути раскрываются относительно файла, в котором указан комментарий для подключения аннотации.
Способ N2 (только для С и C++ анализатора). Указать специальный флаг ‑‑annotation-file (-A) при запуске pvs-studio-analyzer или CompilerCommandsAnalyzer:
pvs-studio-analyzer --annotation-file=%путь/до/файла.json%
Вместо символа подстановки %путь/до/файла.json% предполагается путь до подключаемого файла аннотаций. Поддерживаются как абсолютные, так и относительные пути. Относительные пути раскрываются относительно текущей рабочей директории (CWD).
Может быть подключено несколько файлов с аннотациями. Для каждого файла необходимо указать отдельный флаг или комментарий.
Формат файлов описан в разделе "Механизм пользовательских аннотаций в формате JSON". Пример разметки функции как источника недостоверных данных:
{
"version": 1,
"annotations": [
{
"type": "function",
"name": "ReadStrFromStream",
"params": [
{
"type": "std::istream &input"
},
{
"type": "std::string &str",
"attributes": [ "taint_source" ]
}
],
"returns": { "attributes": [ "taint_source" ] }
}
]
}
Для облегчения знакомства с механизмом пользовательских аннотаций мы подготовили в документации примеры для наиболее часто встречающихся сценариев.
Соответствие требованиям к инструментам статического анализа исходных текстов
Рассмотрим соответствие PVS-Studio различным функциональным требованиям, предъявляемых в ГОСТ Р 71207–2024 (раздел 8) к инструментальным средствам статического анализа исходного кода.
Анализ проекта целиком, включая используемые заимствованные компоненты
Согласно ГОСТ Р 71207–2024 (п. 8.2.), статический анализатор должен поддерживать анализ ПО с используемыми заимствованными компонентами целиком, при этом удовлетворяя требованиям п. 7.3—7.6, п. 8.3 и п. 8.4.
Под этим понимается следующее:
- если вы используете код сторонних библиотек, то вы несёте риски от наличия в них уязвимостей. Если возможна эксплуатация уязвимости в вашем ПО, то нет разницы, где именно она возникла: в коде, написанном вашей командой, или в заимствованном коде. Соответственно, вы должны проводить поиск критических ошибок во всём исходном коде вашего проекта, включая заимствованные компоненты;
- статический анализатор должен обеспечивать поиск критических ошибок в коде заимствованных компонентов на том же уровне и с применением тех же технологий;
- при анализе заимствованных компонентов также должны учитываться параметры сборки, выполняться межмодульный анализ и так далее;
- следует использовать такой статический анализатор (набор анализаторов), чтобы поиск критических ошибок при полном анализе ПО с используемыми заимствованными компонентами занимал не более 2-х суток. Время анализа проектов будет обсуждено в следующей главе.
PVS-Studio удовлетворяет всем перечисленным требованиям и позволяет проводить анализ сторонних компонентов на наличие всех типов критических ошибок.
Проверка кода заимствованных компонентов не отличается от проверки кода разрабатываемого программного обеспечения. Код компонентов аналогичным образом должен быть включён в проект, если речь идёт об использовании таких сред разработки, как Visual Studio, IntelliJ IDEA, CLion и так далее. Плагины PVS-Studio используют информацию о проверяемых файлах и конфигурационных настройках, получаемую от IDE. При этом необходимо убрать из настроек ряд популярных библиотек, которые PVS-Studio исключает из анализа (zlib, jpeglib и так далее), так как они фактически тоже являются заимствованными компонентами и должны проверяться.
В случае использования утилиты мониторинга компиляции заимствованные компоненты должны компилироваться вместе с исходным кодом проекта. Подробнее про утилиты мониторинга для проверки проектов независимо от сборочной системы (C и C++):
Время анализа проекта
В ГОСТ Р 71207—2024 (п. 8.3.) сказано:
Следует использовать такой статический анализатор (набор анализаторов), чтобы на технических средствах разработчика ПО для поиска критических ошибок обеспечивался полный анализ ПО с используемыми заимствованными компонентами за время, не превышающее двое суток.
Разумное требование. С одной стороны, оно достаточно мягкое в плане требований к скорости работы инструментов анализа. С другой стороны, это приемлемое время, за которое разработчики получат результаты анализа всего проекта, который они, согласно ГОСТ, должны выполнять в течении 10 дней после изменения кода (п.5.6.).
Фактически это означает, что рационально настроить анализ всего разрабатываемого ПО, включая заимствованные компоненты, на выходные дни. Анализ как раз гарантированно должен проходить за 2 дня.
Примечание. В стандарте также сказано, что статический анализ добавленных или изменённых частей ПО следует выполнять после каждого внесённого изменения (п.5.6.). Зачем тогда нужен полный анализ? Дело в межмодульном анализе проекта. Допустим, были внесены изменения в файл AA, которые косвенно повлияли на работу функций в файле BB. Это приведёт к ошибкам в файле BB. Но закладываться в систему контроля версий и проверяться с помощью статического анализа будет только файл AA, в котором ошибок нет. Чтобы выявить такую распределённую ошибку, нужен межмодульный анализ, то есть полная перепроверка проекта.
Таким образом, встаёт вопрос оценки верхней границы времени, которое требуется PVS-Studio для анализа проектов различного размера.
Проведённые измерения
Наиболее ресурсоёмким является межмодульный анализ C++ кода, в котором активно используются шаблоны и современные возможности языка. Размер проекта, выбранного для измерения скорости, составляет 10 млн. строк кода.
Конфигурация: 2 процессора Intel Xeon E5 2666 v3 (каждый процессор по 10 физических ядер / 20 логических ядер), частота 3.5 ГГц, 128 ГБ памяти, SSD диск.
Время анализа (включая межмодульный): 10 часов.
Обратите внимание, что ниже оценка проводится для использования не двух, а одного процессора с 10 физическими ядрами.
Расчёт ожидаемого времени для проектов различного размера:
- Для анализа 100 тыс. строк кода будет достаточно одного процессора класса Intel Xeon E5 2666 v3 (10 физических ядер / 20 логических ядер), частота 3.5 ГГц, 64 ГБ памяти. Ожидаемое время анализа: 12 минут.
- Для анализа 1 млн. строк кода будет достаточно одного процессора класса Intel Xeon E5 2666 v3 (10 физических ядер / 20 логических ядер), частота 3.5 ГГц, 64 ГБ памяти. Ожидаемое время анализа: 2 часа.
- Для анализа 10 млн. строк кода будет достаточно одного процессора класса Intel Xeon E5 2666 v3 (10 физических ядер / 20 логических ядер), частота 3.5 ГГц, 64 ГБ памяти. Ожидаемое время анализа: 20 часов.
Таким образом, PVS-Studio с запасом удовлетворяет требованиям по производительности, заданных в ГОСТ Р 71207—2024 (п. 8.3.).
Если складывается ситуация, что анализ с помощью PVS-Studio занимает аномально длительное время, то, скорее всего, возникла одна из следующих ситуаций:
- Используется много процессорных ядер, но в системе мало оперативной памяти. В результате начинает использоваться файл подкачки, что может замедлять работу анализатора в десяток раз. Можно получить ускорение, указав в настройках анализатора, сколько ядер следует использовать, или увеличить в системе объём оперативной памяти.
- Существует какая-то ошибка в анализе кода, которая даёт существенное замедление на определённых конструкциях кода или даже приводит к зацикливанию, которое прерывается только по таймауту. В этом случае просим обратиться к нам в поддержку, и мы постараемся устранить проблему.
Дополнительно см. раздел "Советы по повышению скорости работы PVS-Studio".
Примечание. Одним из советов является исключение из анализа лишних библиотек. С точки зрения ГОСТ Р 71207—2024, этим советом воспользоваться, возможно, не получится, так как все заимствованные компоненты также должны проверяться при РБПО.
Результаты применения анализатора
Результаты применения статического анализатора PVS-Studio содержат всю информацию, перечисленную в ГОСТ Р 71207—2024 (п. 8.5.):
- перечень предупреждений о найденных ошибках (п. 8.5.а.);
- описание ошибок (п. 8.5.б.);
- тип ошибок (п. 8.5.в.);
- место в исходном коде программы, где найдены ошибки (п. 8.5.г.).
Остановимся подробнее на пункте "Тип ошибок".
Согласно стандарту, тип ошибки — это категория ошибок в программе, отражающая их общность в свойствах или характеристиках (п. 3.1.35).
Анализатор PVS-Studio детектирует более 1000 ошибок разного типа. Соответственно, для каждого типа ошибки есть своё предупреждение, состоящее из идентификатора (Vxxx), сообщения и документации. Полный список типов выявляемых ошибок.
Если смотреть более обобщённо, то анализатор PVS-Studio классифицирует свои предупреждения согласно типам критических ошибок, перечисленным в ГОСТ Р 71207—2024 (п.6.3, п.6.5.).
Если вы включили опцию "маркировать предупреждения анализатора PVS-Studio согласно ГОСТ Р 71207—2024", то в поле SAST появятся следующие идентификаторы типа критических ошибок:
- SEC-TAINT — ошибки непроверенного использования чувствительных данных (ввода пользователя, файлов, сети и пр.);
- SEC-OVERFLOW-OR-INT-UINT — ошибки целочисленного переполнения и некорректного совместного использования знаковых и беззнаковых чисел;
- SEC-BUF-OVERFLOW — ошибки переполнения буфера (записи или чтения за пределами выделенной для буфера памяти);
- SEC-SECURITY — ошибки некорректного использования системных процедур и интерфейсов, связанных с обеспечением информационной безопасности (шифрования, разграничения доступа и пр.);
- SEC-SYNCHRONIZATION — ошибки при работе с многопоточными примитивами (интерфейсами запуска потоков на выполнение, синхронизации и обмена данными между потоками и пр.);
- SEC-NULL — ошибки разыменования нулевого указателя;
- SEC-DIV-0 — ошибки деления на ноль;
- SEC-MEMORY — ошибки управления динамической памятью (выделения, освобождения, использования освобождённой памяти);
- SEC-STR-FORMAT — ошибки использования форматной строки;
- SEC-UNINITIALIZED — ошибки использования неинициализированных переменных;
- SEC-LEAKS — ошибки утечек памяти, незакрытых файловых дескрипторов и дескрипторов сетевых соединений.
Вы можете использовать фильтрацию поля SAST в плагинах для IDE или в конверторе отчётов, чтобы выбрать для изучения только список критических ошибок или даже только один конкретный тип критических ошибок.
Принятие решений и автоматизация разметки предупреждений
В ГОСТ Р 71207—2024 (п. 8.6.) говорится, что:
- В ходе разметки предупреждений (согласно п. 5.5.) должна быть обеспечена возможность автоматизаций с целью сокращения времени, затрачиваемого на принятие решения к какой категории отнести предупреждение;
- Требуется возможность навигации по коду при работе с предупреждениями, обеспечено соотнесение выданных предупреждений с исходным кодом;
- Поддержка в принятии решения и автоматизация могут быть обеспечены как средствами статического анализатора, так и сторонними средствами;
- Поддержка в принятии решения и автоматизация могут быть реализованы графическим интерфейсом анализатора.
PVS-Studio соответствует всем требованиям и обеспечивает автоматизацию принятия решения с помощью следующих средств:
- Возможна навигация по коду и соотнесение предупреждений с кодом. Для этого можно использовать отчёты в различных форматах, а также плагины PVS-Studio для различных сред разработки (Visual Studio, Visual Studio Code, Qt Creator и т.д.);
- Фильтрация критических ошибок по их типу;
- Внутренний механизм задания base-line уровня сообщений;
- Использование платформы SonarQube (реализован плагин для встраивания PVS-Studio в SonarQube);
- Использование платформы DefectDojo;
- Утилита blame-notifier. Позволяет автоматически размечать предупреждения (назначение на разработчика, дата внесения дефекта, сортировка по группам) на основе информации из систем контроля версий (SVN, GIT, Mercurial, Perforce).
Автоматизации действий
Согласно стандарту (п. 8.7.), статический анализатор должен обеспечивать возможность автоматизации действий (приведённых в п. 5.6.) для использования в системах непрерывной интеграции.
Анализатор PVS-Studio поддерживает следующие системы непрерывной интеграции:
Обеспечивается хранение результатов запуска, разметки и сравнения
Согласно п. 8.8., должно быть обеспечено хранение результатов запуска статического анализатора и разметки этих результатов. Предупреждение должно быть снабжено идентификатором, с помощью которого его можно найти в результатах анализа. Допускается использовать для хранения результатов сторонние системы.
Результатом анализа проекта с помощью PVS-Studio может быть:
- неотфильтрованный вывод анализатора (JSON);
- отфильтрованный XML-отчёт;
- отфильтрованный JSON-отчёт.
Эти файлы могут быть преобразованы с помощью специальных утилит в другие форматы. Описание этих и других поддерживаемых форматов приведено в разделе "Просмотр и конвертация результатов анализа (форматы SARIF, HTML и др.)".
Разметка результатов осуществляется средствами плагинов PVS-Studio для различных IDE или сторонними системами, такими как SonarQube, DefectDojo, CodeChecker.
Для выполнения задачи сравнения результатов различных запусков стандарт допускает использование сторонних систем (п. 8.9.). В случае PVS-Studio такими сторонними системами являются SonarQube, DefectDojo и CodeChecker. Также эти системы обеспечивают идентификацию предупреждений.
Документации с описанием всех типов ошибок
Данная документация расположена на сайте и содержит раздел с описанием всех предупреждений (детекторов).
Дополнительно документация поставляется вместе с анализатором на случай его использования в закрытом контуре.
В случае использования анализатора без доступа в интернет (в закрытом контуре) рекомендуется включить настройку UseOfflineHelp. В это случае плагины PVS-Studio при нажатии на идентификатор ошибки будут открывать не страницы сайта, а локальные файлы с описанием диагностических правил, поставляемые в составе анализатора.
Согласно ГОСТ Р 71207–2024 (п. 8.10.), статический анализатор должен содержать в документации описание всех типов ошибок, которые находит анализатор, с указанием:
- описания ошибки;
- возможных причин возникновения;
- примеров ошибочного кода, для которого выдаётся предупреждение о данном типе ошибки;
- примеров или рекомендаций исправления данного типа ошибки.
Описание диагностических правил PVS-Studio удовлетворяют всем требованиям, перечисленным в стандарте. Рассмотрим например описание правила V1085, предназначенного для выявления критических ошибок целочисленного переполнения и некорректного совместного использования знаковых и беззнаковых чисел (п. 6.3.б.).
![Technology_ru/image1.png](https://import.viva64.com/docx/manual/Technology_ru/image1.png)
Рисунок 1. Пример документации для диагностического правила V1085.
В документации присутствует:
- (1) описание ошибки (п. 8.10.а.);
- (2) пример ошибочного кода, для которого выдаётся предупреждение о данном типе ошибки (п. 8.10.в.);
- (3) описание возможных причин возникновения (п. 8.10.б.);
- (4) пример и рекомендация исправления данного типа ошибки (п. 8.10.г.).
Также следует (п. 8.10.) указывать соответствие типа ошибки в анализаторе одному или нескольким идентификаторам в системе классификации дефектов безопасности Common Weakness Enumeration (CWE). Соответствие присутствует в конце описания диагностического правила (5).
Выдача результатов анализа в открытом документированном формате
Статический анализатор должен (п. 8.11.) поддерживать выдачу результатов анализа в открытом документированном формате. Примером такого стандарта является формат SARIF.
PVS-Studio поддерживает выдачу результатов анализа в следующих открытых форматах:
- SARIF;
- TaskList;
- Html;
- Error File;
- TeamCity;
- GitLab;
- DefectDojo.
Подробнее см. раздел "Просмотр и конвертация результатов анализа (форматы SARIF, HTML и др.)".
Доработки алгоритмов и правил пользователями
ГОСТ Р 71207–2024 (п. 8.12.) не обязывает инструмент статического анализа представлять пользователям механизмы для доработки алгоритмов и создания новых правил, но упоминает такую возможность.
Анализатор PVS-Studio не представляет возможности пользователям изменять логику работы алгоритмов или добавлять новые диагностические правила. Но по запросу наша команда реализует специализированные диагностические правила, необходимые клиентам.
Дополнительные ссылки по теме РБПО и ГОСТ Р 71207–2024
- Андрей Карпов: "ГОСТ Р 71207–2024 глазами разработчика статических анализаторов кода".
- Giga Conf 2024, Андрей Карпов: "Использование статического анализатора в разработке безопасного программного обеспечения (ГОСТ Р 71207-2024) на примере PVS-Studio".
- МАСКОМ УЦ - Вебинар N7 серии вебинаров РБПО - Давайте разбираться вместе. Андрей Карпов. Доклад (начиная с 1:03:10): "Статический анализатор PVS-Studio на страже качества, защищённости и безопасности кода".
- Валерий Филатов: "Использование статических анализаторов кода при разработке безопасного ПО".
История версий PVS-Studio
- PVS-Studio 7.34 (11 декабря 2024)
- PVS-Studio 7.33 (7 октября 2024)
- PVS-Studio 7.32 (06 августа 2024)
- PVS-Studio 7.31 (11 июня 2024)
- PVS-Studio 7.30 (12 апреля 2024)
- PVS-Studio 7.29 (7 февраля 2024)
- PVS-Studio 7.28 (5 декабря 2023)
- PVS-Studio 7.27 (11 октября 2023)
- PVS-Studio 7.26 (9 августа 2023)
- PVS-Studio 7.25 (7 июня 2023)
- PVS-Studio 7.24 (5 апреля 2023)
- PVS-Studio 7.23 (8 февраля 2023)
- PVS-Studio 7.22 (7 декабря 2022)
- PVS-Studio 7.21 (11 октября 2022)
- PVS-Studio 7.20 (10 августа 2022)
- PVS-Studio 7.19 (8 июня 2022)
- PVS-Studio 7.18 (6 апреля 2022)
- PVS-Studio 7.17 (9 февраля 2022)
- PVS-Studio 7.16 (8 декабря 2021)
- PVS-Studio 7.15 (7 октября 2021)
- PVS-Studio 7.14 (9 августа 2021)
- PVS-Studio 7.13 (31 мая 2021)
- PVS-Studio 7.12 (11 марта 2021)
- PVS-Studio 7.11 (17 декабря 2020)
- PVS-Studio 7.10 (5 ноября 2020)
- PVS-Studio 7.09 (27 августа 2020)
- PVS-Studio 7.08 (18 июня 2020)
- PVS-Studio 7.07 (16 апреля 2020)
- PVS-Studio 7.06 (27 февраля 2020)
- PVS-Studio 7.05 (10 декабря 2019)
- PVS-Studio 7.04 (4 сентября 2019)
- PVS-Studio 7.03 (25 июня 2019)
- PVS-Studio 7.02 (25 апреля 2019)
- PVS-Studio 7.01 (13 марта 2019)
- PVS-Studio 7.00 (16 января 2019)
- Старая история версий
PVS-Studio 7.34 (11 декабря 2024)
- Анализатор PVS-Studio для операционных систем семейства macOS портирован на процессоры Apple Silicon с архитектурой ARM64. Скачать PVS-Studio можно на странице загрузок.
- В C# анализатор PVS-Studio добавлена поддержка проектов для .NET 9.
- В Java анализаторе PVS-Studio появился механизм для проведения taint-анализа. На его основе была создана первая диагностика — поиск SQL-инъекций. В следующем году в Java анализаторе будет сделан упор на SAST, покрытие списка наиболее распространённых потенциальных уязвимостей OWASP Top 10, а также будет добавлено больше taint-диагностик.
- В утилиты командной строки
PVS-Studio_Cmd
иpvs-studio-dotnet
был добавлен режим проверки модифицированных файлов, позволяющий автоматически обнаружить изменённые между запусками анализа исходные файлы. Данный режим является альтернативой инкрементальному анализу и может быть полезен при проверке Pull Request'ов. Подробнее о новом режиме можно прочитать в документации. - В плагин PVS-Studio для Visual Studio Code и утилиту командной строки
plog-converter
была добавлена возможность отображения критических ошибок согласно ГОСТ Р 71207-2024. - Добавлена возможность загрузки отчёта PVS-Studio в веб-интерфейс для просмотра и агрегации результатов анализа CodeChecker. Поддержка PVS-Studio при установке CodeChecker из пакетного менеджера pip появится с выходом версии 6.25.0. Подробнее об интеграции можно прочитать в документации.
- Добавлена возможность гибкой настройки включения или выключения из анализа исходных файлов и файлов настроек
.pvsconfig
. Также данный механизм можно будет использовать для проверки Unreal Engine проектов с помощью Unreal Build Tool, начиная с версии 5.5.2. Подробнее можно прочитать в документации. - Анализаторы PVS-Studio были проверены на совместимость и корректную работу с операционными системами РЕД ОС 7.3 и РЕД ОС 8.
- [Breaking change] Изменились требования C# анализатора PVS-Studio на Windows. Для анализа .NET проектов теперь потребуется установка .NET 9 SDK. Для анализа .NET Standard и .NET Framework SDK-style проектов также потребуется .NET SDK 9. Требования по проверке не изменились для классических .NET Framework проектов: если в системе установлены Visual Studio или MSBuild версий 2017, 2019 или 2022, достаточно наличия в системе .NET Framework 4.7.2. Для классических .NET Framework проектов в системах с Visual Studio или MSBuild версий 2015 или более старых теперь также будет требоваться присутствие .NET 9 SDK. При использовании silent режима установки на Windows, если необходимо запускать анализ на проектах, которые теперь требуют наличия в системе .NET 9 SDK, потребуется указать компонент DOTNET для установки .NET 9 SDK, если SDK не был установлен в системе отдельно.
- [Breaking change] В утилите командной строки
pvs-studio-analyzer
изменено поведение флага‑‑sourcetree-root (-r)
. При подмене путей в генерируемом отчёте путь до базовой директории проверяется на существование. Если часть путей не получилось подменить, то выдаётся сообщение с предупреждением, но код возврата остаётся равным 0. Если же не получилось подменить ни один путь, то помимо сообщения с предупреждением код возврата будет ненулевым. - V1116. Creating an exception object without an explanatory message may result in insufficient logging.
- V1117. The declared function type is cv-qualified. The behavior when using this type is undefined.
- V2022. Implicit type conversion from integer type to enum type.
- V5014. OWASP. Cryptographic function is deprecated. Its use can lead to security issues. Consider switching to an equivalent newer function.
- V3207. The 'not A or B' logical pattern may not work as expected. The 'not' pattern is matched only to the first expression from the 'or' pattern.
- V3208. Unity Engine. Using 'WeakReference' instance with 'UnityEngine.Object' is not supported. GC will not properly reclaim memory from this object because it is linked to a native object.
- V3209. Unity Engine. Re-applying await to an Awaitable object will result in an exception.
- V3210. Unity Engine. Unity does not allow removing the 'Transform' component using 'Destroy' or 'DestroyImmediate' methods. The method call will be ignored.
- V4007. Unity Engine. Avoid creating and destroying UnityEngine objects in performance-sensitive context. Consider activating and deactivating them instead.
- V6123. Modified value of the operand is not used after the increment/decrement operation.
- V6124. Converting an integer literal to the type with a smaller value range will result in overflow.
- V6125. Calling the 'wait', 'notify', and 'notifyAll' methods outside of synchronized context will lead to 'IllegalMonitorStateException'.
- V5309. Possible SQL injection. Potentially tainted data is used to create SQL command.
PVS-Studio 7.33 (7 октября 2024)
- Плагин PVS-Studio для IDE Qt Creator портирован на комплект разработчика для операционной системы "Нейтрино". Поддержана работа с Qt Creator 6.0.2 (Qt 5.15) из данного комплекта разработчика.
- В утилиту командной строки PVS-Studio_Cmd была добавлена возможность отображения критических ошибок согласно ГОСТ Р 71207-2024. Для этого необходимо включить настройку "Security Related Issues" в плагине PVS-Studio для Visual Studio.
- В C++ анализаторе PVS-Studio было уменьшено потребление памяти при анализе инстанцирования шаблонов, а также инициализации большого количества глобальных переменных строковыми литералами.
- В C++ анализаторе PVS-Studio было уменьшено количество ложных срабатываний при анализе кода, относящегося к проектам Unreal Engine. Унифицирована обработка встроенных функций компилятора __builtin_expect и доработана обработка выражений явных приведений к bool. Это улучшило анализ check-функций, управляемых макросом DO_CHECK в проектах Unreal Engine.
- Для режима интеграции PVS-Studio с Unreal Engine была добавлена поддержка системы распределённой сборки SN-DBS. Подробнее об этом можно прочитать в нашей документации об интеграции анализатора PVS-Studio с Unreal Engine. Данные изменения актуальны для версии Unreal Engine 5.5.
- В C# анализаторе PVS-Studio была реализована возможность проставления пользовательских аннотаций функций и типов в формате JSON по аналогии со схожей функциональностью C++ анализатора PVS-Studio. Подробнее об этой функциональности можно прочитать в нашей документации.
- Была исправлена ошибка работы плагина PVS-Studio для Visual Studio при его использовании с Visual Studio версий 17.12 и выше.
- Были исправлены проблемы работы С# анализатора PVS-Studio в системе с установленным .NET версий 8.0.400 и выше.
- [Breaking change] Были подняты версии форматов отчётов анализаторов PVS-Studio .json и .plog до версий 3 и 9 соответственно. Теперь у C# проектов, имеющих несколько целевых фреймворков (target framework), имя фреймворка не приписывается к имени проекта.
- [Breaking change] В формат JSON отчёта C++ анализатора PVS-Studio было добавлено новое поле analyzedSourceFiles. В данное поле записывается дополнительная информация о том, в какой единице трансляции произошло срабатывание диагностического правила. Это полезно в случаях, когда потенциальная ошибка содержится в заголовочных файлах.
- [Breaking change] Версия JSON-схемы пользовательских аннотаций функций и типов PVS-Studio поднята до версии 2. В схему была добавлена новая сущность language. Она позволяет использовать пользовательские аннотации только в анализаторе для конкретного языка. Помимо этого, было изменено значение поля id.
- [Breaking change] В системе пользовательских аннотаций функций и типов PVS-Studio комментарий //V_PVS_ANNOTATIONS $path для включения пользовательских аннотаций помечен как устаревший. В качестве замены предлагается использовать комментарий вида //V_PVS_ANNOTATIONS, language: $lang, path: $path.
- [Breaking change] Минимальные поддерживаемые версии IDE JetBrains IDEA, CLion и Rider были подняты до версии 2022.2.
- [Breaking change] Изменено разрешение путей в плагине PVS-Studio для сборочной системы Gradle. Теперь относительные пути из конфигурации разрешаются относительно директории проекта, а не относительно директории gradle daemon.
- [Breaking change] Была удалена возможность конвертации отчёта PVS-Studio при помощи утилит plog converter в специфичный для Visual Studio Code формат SARIF, используемый в плагине SARIF Viewer. Конвертация в соответствующий стандарту отчёт формата SARIF сохранена.
- V1113. Potential resource leak. Calling the 'memset' function will change the pointer itself, not the allocated resource. Check the first and third arguments.
- V1114. Suspicious use of 'dynamic_cast' when working with COM interfaces. Consider using the 'QueryInterface' member function.
- V1115. Function annotated with the 'pure' attribute has side effects.
- V3204. The expression is always false due to implicit type conversion. Overflow check is incorrect.
- V3205. Unity Engine. Improper creation of 'MonoBehaviour' or 'ScriptableObject' object using the 'new' operator. Use the special object creation method instead.
- V3206. Unity Engine. A direct call to the coroutine-like method will not start it. Use the 'StartCoroutine' method instead.
- V4006. Unity Engine. Multiple operations between complex and numeric values. Prioritizing operations between numeric values can optimize execution time.
- V6118. The original exception object was swallowed. Cause of original exception could be lost.
- V6119. The result of '&' operator is always '0'.
- V6120. The result of the '&' operator is '0' because one of the operands is '0'.
- V6121. Return value is not always used. Consider inspecting the 'foo' method.
- V6122. The 'Y' (week year) pattern is used for date formatting. Check whether the 'y' (year) pattern was intended instead.
PVS-Studio 7.32 (06 августа 2024)
- В связи с изменениями в API платформы SonarQube был разработан новый плагин для интеграции анализатора PVS-Studio в платформу SonarQube. Начиная с версии SonarQube 10.1, необходимо использовать новую версию плагина. Версия плагина PVS-Studio для более ранних версий SonarQube продолжает поддерживаться и получать обновления параллельно с новым плагином.
- Добавлена поддержка интеграции анализатора PVS-Studio в проекты, использующие сборочные системы Bazel и Scons.
- Плагин PVS-Studio стал доступен для Qt Creator версий 14.x. Прекращена поддержка плагина для версий Qt Creator 8.x. Мы стараемся обеспечивать обратную совместимость по поддержке последних версий плагинов для всех версий Qt Creator за два года с момента каждого релиза.
- Оптимизировано потребление памяти С++ анализатора при анализе инстанцирования шаблонов. При этом сохранена возможность отключения анализа их инстанцирования с помощью флага настройки DisableTemplateInstantiationCpp в плагине PVS-Studio для Visual Studio или настройки //V_DISABLE_TEMPLATE_INSTANTIATION в файлах конфигурации pvsconfig в случае, если потребление памяти анализатором всё ещё остаётся избыточно высоким.
- Улучшен разбор стандартной библиотеки Microsoft Visual C++, используемой в версии Visual Studio 17.10.
- В C++ анализаторе PVS-Studio добавлена возможность разметки источников и приёмников при анализе помеченных (taint) данных. Она реализована в механизме пользовательских аннотаций в формате JSON.
- Добавлена возможность исключения из анализа проектов при анализе проектов для сборочной системы MSBuild с помощью файлов конфигурации анализатора .pvsconfig. Эта возможность реализуется включением флага V_EXCLUDE_PROJECT в файл конфигурации диагностик pvsconfig.
- Добавлена возможность использования файлов конфигурации диагностик pvsconfig в плагине PVS-Studio для IDE JetBrains CLion.
- [Breaking change] Изменён синтаксис пользовательских аннотаций в формате JSON для С++ анализатора PVS-Studio. Использование атрибутов nullable_initialized и nullable_uninitialized устарело. Вместо них введены атрибуты возвращаемого объекта not_null, maybe_null, always_null.
- [Breaking change] Изменён приоритет флага ‑‑sourceTreeRoot в утилите PVS-Studio_Cmd.exe, задающего корневую часть пути для конвертации путей из абсолютных в относительные. Теперь этот флаг имеет приоритет над настройками UseSolutionDirAsSourceTreeRoot в конфигурационном файле Settings.xml и //V_SOLUTION_DIR_AS_SOURCE_TREE_ROOT в файлах конфигурации диагностик pvsconfig.
- V1111. The index was used without check after it was checked in previous lines.
- V1112. Comparing expressions with different signedness can lead to unexpected results.
- V2021. Using assertions may cause the abnormal program termination in undesirable contexts.
- V3201. Return value is not always used. Consider inspecting the 'foo' method.
- V3202. Unreachable code detected. The 'case' value is out of the range of the match expression.
- V3203. Method parameter is not used.
- V6115. Not all Closeable members are released inside the 'close' method.
- V6116. The class does not implement the Closeable interface, but it contains the 'close' method that releases resources.
- V6117. Possible overflow. The expression will be evaluated before casting. Consider casting one of the operands instead.
PVS-Studio 7.31 (11 июня 2024)
- Добавлена возможность установки настроек в конфигурационных файлах .pvsconfig в зависимости от версии анализатора, использующего данные файлы. Эта возможность доступна в С++ анализаторе PVS-Studio.
- В утилите pvs-studio-analyzer была расширена система анализа отдельных файлов с помощью флага ‑‑source-files. Теперь использование утилиты в условиях отличия кэша зависимостей компиляций для C и C++ файлов от структуры проекта стало более удобным. Такая ситуация может возникнуть, например, при частом переключении веток в одном рабочем пространстве или запуске анализа на разных версиях проекта.
- В систему пользовательских аннотаций C++ анализатора была добавлена возможность задавать диапазон возможных и невозможных значений для целочисленных параметров функций.
- Была доработана и актуализирована документация об использовании анализаторов PVS-Studio в облачной CI-системе CircleCI.
- V1108. Constraint specified in a custom function annotation on the parameter is violated.
- V1109. Function is deprecated. Consider switching to an equivalent newer function.
- V1110. Constructor of a class inherited from 'QObject' does not use a pointer to a parent object.
- V3199. Index from end operator used with the value that is less than or equal to zero. Index is out of bound.
- V3200. Possible overflow. The expression will be evaluated before casting. Consider casting one of the operands instead.
- V6113. Suspicious division. Absolute value of the left operand is less than the value of the right operand.
- V6114. The 'A' class containing Closeable members does not implement the Closeable interface.
PVS-Studio 7.30 (12 апреля 2024)
- В C++ анализаторе PVS-Studio был реализован механизм пользовательских аннотаций —способ разметки типов и функций в формате JSON с целью дать анализатору дополнительную информацию. Благодаря этой информации анализатор может находить больше ошибок в коде. Такие аннотации