Этот доклад для тех, кто не знаком со статическими анализаторами кода, или знаком, но ещё не внедрил эти инструменты в процесс разработки. Будет описана методология статического анализа и как она используется для выявления ошибок и запахов кода. Будут кратко рассмотрены некоторые популярные инструменты статического анализа для языка Java, а также платформа SonarQube способная объединить и визуализировать отчёты различных анализаторов. Немного заглянем внутрь и поговорим о технологиях, используемых в современных статических анализаторах кода и позволяющих находить разнообразнейшие паттерны ошибок. Затронем вопрос, почему несмотря на уже существующие инструменты наша команда решила сделать ещё один: PVS-Studio for Java :). В конце рассмотрим важный вопрос интеграции инструментов статического анализа в большие старые проекты и почему так важно регулярное использование подобных инструментов.
Report
Share
Report
Share
1 of 34
More Related Content
Всё о статическом анализе кода для Java программиста
1. EVERYTHING
ABOUT STATIC CODE ANALYSIS
FOR A JAVA PROGRAMMER
Maxim Stefanov
PVS-Studio, C++/Java developer, Tula
1
2. О докладчике
• Максим Стефанов (stefanov@viva64.com)
• C++/Java разработчик в компании PVS-Studio
• Деятельность:
• Участие в разработке ядра C++ анализатора
• Участие в разработке Java анализатора
2
3. О чем поговорим ...
• Теория
Качество кода (баги, уязвимости, ...)
Методологии защиты кода от дефектов
Статический анализ и все с ним связанное
• Инструменты
Существующие инструменты статического анализа
SonarQube
PVS-Studio for Java – что это?
• Несколько обнаруженных примеров кода с дефектами
• Еще про статический анализ
• Итоги
3
4. Зачем уделять внимание качеству кода
• Не накопить технический долг, если проект молодой
• Не потерять пользователей, если проект с историей
4
7. Статический анализ кода
Плюсы Минусы
Выявляет дефекты до начала code review Нельзя выявить
высокоуровневые ошибки
Анализатор не устаёт и готов работать в любое время Ложные срабатывания
Можно найти ошибки, даже не зная о таком паттерне
Можно найти ошибки, которые при обзоре крайне
сложно заметить
7
8. Технологии, используемые при
статическом анализе
•Сопоставление с шаблоном (pattern-based analysis)
•Вывод типов (type inference)
•Анализ потока данных (data-flow analysis)
•Символьное выполнение (symbolic execution)
•Аннотирование методов (method annotations)
8
9. Сопоставление с шаблоном
(pattern-based analysis)
@Override
public boolean equals(Object obj) {
....
return index.equals(other.index)
&& type.equals(other.type)
&& version == other.version
&& found == other.found
&& tookInMillis == tookInMillis
&& Objects.equals(terms, other.terms);
}
9
10. Вывод типов
(type inference)
interface Human { ... }
class Parent implements Human{ ... }
class Child extends Parent { ... }
...
class Animal { ... }
...
boolean someMethod(List<Child> list, Animal animal)
{
if (list.remove(animal))
return false;
...
}
10
11. Аннотирование методов
(method annotations)
Class("java.lang.Math")
- Function("max", Type::Int32, Type::Int32)
.Pure()
.Set(FunctionClassification::NoDiscard)
.Requires(NotEquals(Arg1, Arg2))
.Returns(Arg1, Arg2, [](const Int &v1, const Int &v2)
{
return v1.Max(v2);
}
)
11
12. Аннотирование методов
(method annotations)
int test(int a, int b) {
Math.max(a, b); //1
if (a > 5 && b < 2) {
// a = [6..INT_MAX]
// b = [INT_MIN..1]
if (Math.max(a, b) > 0) //2
{...}
}
return Math.max(a, a); //3
}
12
16. SonarQube: что и зачем
• Платформа с открытым исходным кодом для
непрерывного анализа и измерения качества кода
• Содержит ряд анализаторов для разных языков
• Позволяет интегрировать сторонние анализаторы
• Наглядно визуализирует качество вашего продукта
16
21. История создания PVS-Studio для Java
• Java - популярный язык
• Большая сфера применения языка
• Была возможность использовать механизмы из
C++ анализатора (data-flow analysis, method
annotations)
21
23. Spoon для получения синтаксического
дерева и семантической модели
Spoon преобразует код в метамодель:
class TestClass
{
void test(int a, int b)
{
int x = (a + b) * 4;
System.out.println(x);
}
}
23
Внутреннее устройство анализатора
24. Data-flow analysis, method annotations - использование
механизмов из C++ анализатора при помощи SWIG
24
Внутреннее устройство анализатора
25. Диагностическое правило – является визитором, у которого
перегружаются методы, в которых обходятся интересующие нас
элементы по дереву
25
Внутреннее устройство анализатора
27. Целочисленное деление
private static boolean checkSentenceCapitalization(@NotNull String value) {
List<String> words = StringUtil.split(value, " ");
....
int capitalized = 1;
....
return capitalized / words.size() < 0.2; // allow reasonable amount of
// capitalized words
}
V6011 [CWE-682] The '0.2' literal of the 'double' type is compared to a value of the 'int' type.
TitleCapitalizationInspection.java 169
IntelliJ IDEA
27
28. Всегда false
PVS-Studio: V6007 [CWE-570] Expression '"0".equals(text)' is always false. ConvertIntegerToDecimalPredicate.java 46
IntelliJ IDEA
public boolean satisfiedBy(@NotNull PsiElement element) {
....
@NonNls final String text = expression.getText().replaceAll("_", "");
if (text == null || text.length() < 2) {
return false;
}
if ("0".equals(text) || "0L".equals(text) || "0l".equals(text)) {
return false;
}
return text.charAt(0) == '0';
}
28
29. Незапланированное количество итераций
public static String getXMLType(@WillNotClose InputStream in) throws
IOException
{
....
String s;
int count = 0;
while (count < 4) {
s = r.readLine();
if (s == null) {
break;
}
Matcher m = tag.matcher(s);
if (m.find()) {
return m.group(1);
}
}
....
}
29
SpotBugs
V6007 [CWE-571] Expression 'count < 4' is always true. Util.java 394
30. Никуда без Copy-Paste
public class RuleDto {
....
private final RuleDefinitionDto definition;
private final RuleMetadataDto metadata;
....
private void setUpdatedAtFromDefinition(@Nullable Long updatedAt) {
if (updatedAt != null && updatedAt > definition.getUpdatedAt()) {
setUpdatedAt(updatedAt);
}
}
private void setUpdatedAtFromMetadata(@Nullable Long updatedAt) {
if (updatedAt != null && updatedAt > definition.getUpdatedAt()) {
setUpdatedAt(updatedAt);
}
}
....
}
30
SonarQube
V6032 It is odd that the body of method 'setUpdatedAtFromDefinition' is fully equivalent to the body of another method
'setUpdatedAtFromMetadata'. Check lines: 396, 405. RuleDto.java 396
31. Дубликаты
V6033 [CWE-462] An item with the same key 'JavaPunctuator.PLUSEQU' has already been added. Check lines: 104, 100.
KindMaps.java 104
SonarJava
private final Map<JavaPunctuator, Tree.Kind> assignmentOperators =
Maps.newEnumMap(JavaPunctuator.class);
public KindMaps() {
....
assignmentOperators.put(JavaPunctuator.PLUSEQU, Tree.Kind.PLUS_ASSIGNMENT);
....
assignmentOperators.put(JavaPunctuator.PLUSEQU, Tree.Kind.PLUS_ASSIGNMENT);
....
}
31
32. Как интегрировать статический анализ в
процесс разработки ПО
• Каждый разработчик имеет на рабочем месте
инструмент статического анализа
• Анализ всей кодовой базы при ночных сборках, и в
случае нахождения подозрительного кода - рассылка
писем виновникам
32
33. Как начать использовать инструменты
статического анализа на больших проектах и не
пасть духом
1. Проверяем проект
2. Указываем, что все выданные предупреждения нам пока не
интересны, поместив их в специальный файл подавления
3. Закладываем файл с разметкой в систему контроля версий
4. Запускаем анализатор и получаем предупреждения только на
новый или измененный код
5. PROFIT!
33
34. Вывод
• Статический анализ – дополняющая методология, а не
«серебряная пуля»
• Статический анализ должен использоваться регулярно
• Можно начать использовать анализ сразу, отложив правку старых
ошибок на потом
34
Editor's Notes
Добрый день. Меня зовут Максим. Я разработчик в компании PVS-Studio, которая занимается разработкой статического анализатора для языков программирования C/C++/C#/Java.
Сегодня я хочу вам рассказать, что статический анализ кода является такой же неотъемлемой частью разработки как, например, Code Review, тестирование.