Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
SlideShare a Scribd company logo
EVERYTHING
ABOUT STATIC CODE ANALYSIS
FOR A JAVA PROGRAMMER
Maxim Stefanov
PVS-Studio, C++/Java developer, Tula
1
О докладчике
• Максим Стефанов (stefanov@viva64.com)
• C++/Java разработчик в компании PVS-Studio
• Деятельность:
• Участие в разработке ядра C++ анализатора
• Участие в разработке Java анализатора
2
О чем поговорим ...
• Теория
 Качество кода (баги, уязвимости, ...)
 Методологии защиты кода от дефектов
Статический анализ и все с ним связанное
• Инструменты
 Существующие инструменты статического анализа
 SonarQube
 PVS-Studio for Java – что это?
• Несколько обнаруженных примеров кода с дефектами
• Еще про статический анализ
• Итоги
3
Зачем уделять внимание качеству кода
• Не накопить технический долг, если проект молодой
• Не потерять пользователей, если проект с историей
4
Стоимость исправления дефекта
Из книги С. Макконнелла "Совершенный Код"
5
Методы обеспечения качества кода
6
Статический анализ кода
Плюсы Минусы
Выявляет дефекты до начала code review Нельзя выявить
высокоуровневые ошибки
Анализатор не устаёт и готов работать в любое время Ложные срабатывания
Можно найти ошибки, даже не зная о таком паттерне
Можно найти ошибки, которые при обзоре крайне
сложно заметить
7
Технологии, используемые при
статическом анализе
•Сопоставление с шаблоном (pattern-based analysis)
•Вывод типов (type inference)
•Анализ потока данных (data-flow analysis)
•Символьное выполнение (symbolic execution)
•Аннотирование методов (method annotations)
8
Сопоставление с шаблоном
(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
Вывод типов
(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
Аннотирование методов
(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
Аннотирование методов
(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
Анализ потока данных
(data-flow analysis)
void func(int x) // x: [-2147483648..2147483647] //1
{
if (x > 3)
{
// x: [4..2147483647] //2
if (x < 10)
{
// x: [4..9] //3
}
}
else
{
// x: [-2147483648..3] //4
}
}
13
Символьное выполнение
(symbolic execution)
int someMethod(int A, int B)
{
if (A == B)
return 10 / (A - B);
return 1;
}
14
Существующие инструменты
15
SonarQube: что и зачем
• Платформа с открытым исходным кодом для
непрерывного анализа и измерения качества кода
• Содержит ряд анализаторов для разных языков
• Позволяет интегрировать сторонние анализаторы
• Наглядно визуализирует качество вашего продукта
16
SonarQube: визуализация данных
17
SonarQube: визуализация данных
18
SonarQube: визуализация данных
19
SonarQube: визуализация данных
20
История создания PVS-Studio для Java
• Java - популярный язык
• Большая сфера применения языка
• Была возможность использовать механизмы из
C++ анализатора (data-flow analysis, method
annotations)
21
Внутреннее устройство анализатора
22
Spoon для получения синтаксического
дерева и семантической модели
Spoon преобразует код в метамодель:
class TestClass
{
void test(int a, int b)
{
int x = (a + b) * 4;
System.out.println(x);
}
}
23
Внутреннее устройство анализатора
Data-flow analysis, method annotations - использование
механизмов из C++ анализатора при помощи SWIG
24
Внутреннее устройство анализатора
Диагностическое правило – является визитором, у которого
перегружаются методы, в которых обходятся интересующие нас
элементы по дереву
25
Внутреннее устройство анализатора
Некоторые примеры ошибок, найденных
при помощи PVS-Studio
26
Целочисленное деление
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
Всегда 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
Незапланированное количество итераций
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
Никуда без 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
Дубликаты
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
Как начать использовать инструменты
статического анализа на больших проектах и не
пасть духом
1. Проверяем проект
2. Указываем, что все выданные предупреждения нам пока не
интересны, поместив их в специальный файл подавления
3. Закладываем файл с разметкой в систему контроля версий
4. Запускаем анализатор и получаем предупреждения только на
новый или измененный код
5. PROFIT!
33
Вывод
• Статический анализ – дополняющая методология, а не
«серебряная пуля»
• Статический анализ должен использоваться регулярно
• Можно начать использовать анализ сразу, отложив правку старых
ошибок на потом
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
  • 5. Стоимость исправления дефекта Из книги С. Макконнелла "Совершенный Код" 5
  • 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
  • 13. Анализ потока данных (data-flow analysis) void func(int x) // x: [-2147483648..2147483647] //1 { if (x > 3) { // x: [4..2147483647] //2 if (x < 10) { // x: [4..9] //3 } } else { // x: [-2147483648..3] //4 } } 13
  • 14. Символьное выполнение (symbolic execution) int someMethod(int A, int B) { if (A == B) return 10 / (A - B); return 1; } 14
  • 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 Внутреннее устройство анализатора
  • 26. Некоторые примеры ошибок, найденных при помощи PVS-Studio 26
  • 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

  1. Добрый день. Меня зовут Максим. Я разработчик в компании PVS-Studio, которая занимается разработкой статического анализатора для языков программирования C/C++/C#/Java. Сегодня я хочу вам рассказать, что статический анализ кода является такой же неотъемлемой частью разработки как, например, Code Review, тестирование.