SlideShare a Scribd company logo

На что способны современные статические анализаторы для C#

Слайды с выступления Владимира Кошелева на IT Global Meetup #7 (Санкт-Петербург, 2.04.2016)

1 of 65
Download to read offline
На что способны
современные статические
анализаторы для C#
О Нас
• Чем занимается ИСП РАН?
• Компиляторное технологии: анализ и оптимизация
• R&D проекты для таких компаний, как Samsung, Intel
Валерий Игнатьев: к.ф.-м.н., 6 лет занимается статическим
анализом.
Владимир Кошелев: 4 года занимаюсь статическим анализом,
пишу диссертацию про анализ C#.
Артем Борзилов: 2 года занимался динамическим анализом и
деобфускацией, последние 2 года - статический анализ.
02.04.2016 ИСП РАН 2
Автоматический анализ программ
• Задача: автоматический поиск ошибок в программах.
• Поиск потенциальных ошибок (дефектов) в исходном
коде программ
• Поиск входных данных, на которых программа упадет
(поиск уязвимостей)
02.04.2016 ИСП РАН 3
Поиск уязвимостей: Фаззинг
02.04.2016 ИСП РАН 4
Генерация
входных
данных
Средства
запуска
программы
Программа
Монитор
нештатных
ситуаций
База
«плохих»
входных
данных
Разница между уязвимостью и дефектом
• Поиск уязвимостей - это прежде всего поиск «плохих»
входных данных.
• Поиск дефектов - это поиск подозрительных мест в коде,
входные данные искать не требуется.
Поэтому его можно сделать менее точным и куда более
быстрым, чем поиск уязвимостей.
02.04.2016 ИСП РАН 5
Виды ошибок анализатора
02.04.2016 ИСП РАН 6

Recommended

TMPA-2015: Lexical analysis of dynamically formed string expressions
TMPA-2015: Lexical analysis of dynamically formed string expressionsTMPA-2015: Lexical analysis of dynamically formed string expressions
TMPA-2015: Lexical analysis of dynamically formed string expressionsIosif Itkin
 
TMPA-2015: Expanding the Meta-Generation of Correctness Conditions by Means o...
TMPA-2015: Expanding the Meta-Generation of Correctness Conditions by Means o...TMPA-2015: Expanding the Meta-Generation of Correctness Conditions by Means o...
TMPA-2015: Expanding the Meta-Generation of Correctness Conditions by Means o...Iosif Itkin
 
TMPA-2013 Vert Krikun: Finding Defects in C and C++ Pointers Using Static Ana...
TMPA-2013 Vert Krikun: Finding Defects in C and C++ Pointers Using Static Ana...TMPA-2013 Vert Krikun: Finding Defects in C and C++ Pointers Using Static Ana...
TMPA-2013 Vert Krikun: Finding Defects in C and C++ Pointers Using Static Ana...Iosif Itkin
 
TMPA-2013 Anureyev: On the Road to Technology of Developing the Means of Dedu...
TMPA-2013 Anureyev: On the Road to Technology of Developing the Means of Dedu...TMPA-2013 Anureyev: On the Road to Technology of Developing the Means of Dedu...
TMPA-2013 Anureyev: On the Road to Technology of Developing the Means of Dedu...Iosif Itkin
 
TMPA-2013 Tsytelov Trifanov Devexperts
TMPA-2013 Tsytelov Trifanov DevexpertsTMPA-2013 Tsytelov Trifanov Devexperts
TMPA-2013 Tsytelov Trifanov DevexpertsIosif Itkin
 
Всё о статическом анализе кода для Java программиста
Всё о статическом анализе кода для Java программистаВсё о статическом анализе кода для Java программиста
Всё о статическом анализе кода для Java программистаAndrey Karpov
 
Николай Волосатов — Работа с крэшами библиотек
Николай Волосатов — Работа с крэшами библиотекНиколай Волосатов — Работа с крэшами библиотек
Николай Волосатов — Работа с крэшами библиотекCocoaHeads
 
Статический анализ: вокруг Java за 60 минут
Статический анализ: вокруг Java за 60 минутСтатический анализ: вокруг Java за 60 минут
Статический анализ: вокруг Java за 60 минутAndrey Karpov
 

More Related Content

Similar to На что способны современные статические анализаторы для C#

20130429 dynamic c_c++_program_analysis-alexey_samsonov
20130429 dynamic c_c++_program_analysis-alexey_samsonov20130429 dynamic c_c++_program_analysis-alexey_samsonov
20130429 dynamic c_c++_program_analysis-alexey_samsonovComputer Science Club
 
static - defcon russia 20
static  - defcon russia 20static  - defcon russia 20
static - defcon russia 20DefconRussia
 
Принципы работы статического анализатора кода PVS-Studio
Принципы работы статического анализатора кода PVS-StudioПринципы работы статического анализатора кода PVS-Studio
Принципы работы статического анализатора кода PVS-StudioAndrey Karpov
 
Михаил Матросов, “С++ без new и delete”
Михаил Матросов, “С++ без new и delete”Михаил Матросов, “С++ без new и delete”
Михаил Матросов, “С++ без new и delete”Platonov Sergey
 
Tech Talks @NSU: Как приручить дракона: введение в LLVM
Tech Talks @NSU: Как приручить дракона: введение в LLVMTech Talks @NSU: Как приручить дракона: введение в LLVM
Tech Talks @NSU: Как приручить дракона: введение в LLVMTech Talks @NSU
 
Как приручить дракона: введение в LLVM
Как приручить дракона: введение в LLVMКак приручить дракона: введение в LLVM
Как приручить дракона: введение в LLVMTech Talks @NSU
 
Формальная верификация кода на языке Си
Формальная верификация кода на языке СиФормальная верификация кода на языке Си
Формальная верификация кода на языке СиPositive Development User Group
 
Формальная верификация кода на языке Си
Формальная верификация кода на языке СиФормальная верификация кода на языке Си
Формальная верификация кода на языке СиPositive Hack Days
 
Formal verification of C code
Formal verification of C codeFormal verification of C code
Formal verification of C codeDenis Efremov
 
Статический анализ кода: Что? Как? Зачем?
Статический анализ кода: Что? Как? Зачем?Статический анализ кода: Что? Как? Зачем?
Статический анализ кода: Что? Как? Зачем?Andrey Karpov
 
МРТ для данных / Анастасия Горячева (Avito)
МРТ для данных / Анастасия Горячева (Avito)МРТ для данных / Анастасия Горячева (Avito)
МРТ для данных / Анастасия Горячева (Avito)Ontico
 
МРТ для данных, Frontend Conf 2016
МРТ для данных, Frontend Conf 2016МРТ для данных, Frontend Conf 2016
МРТ для данных, Frontend Conf 2016Anastasia Goryacheva
 
C++ Базовый. Занятие 02.
C++ Базовый. Занятие 02.C++ Базовый. Занятие 02.
C++ Базовый. Занятие 02.Igor Shkulipa
 
Павел Павлов - Scala для профессионалов - Joker 2013
Павел Павлов - Scala для профессионалов - Joker 2013Павел Павлов - Scala для профессионалов - Joker 2013
Павел Павлов - Scala для профессионалов - Joker 2013ScalaNsk
 
Пояснения к статье про Copy-Paste
Пояснения к статье про Copy-PasteПояснения к статье про Copy-Paste
Пояснения к статье про Copy-PasteTatyanazaxarova
 
Дмитрий Прокопцев — R-ссылки в С++11
Дмитрий Прокопцев — R-ссылки в С++11Дмитрий Прокопцев — R-ссылки в С++11
Дмитрий Прокопцев — R-ссылки в С++11Yandex
 

Similar to На что способны современные статические анализаторы для C# (20)

20130429 dynamic c_c++_program_analysis-alexey_samsonov
20130429 dynamic c_c++_program_analysis-alexey_samsonov20130429 dynamic c_c++_program_analysis-alexey_samsonov
20130429 dynamic c_c++_program_analysis-alexey_samsonov
 
static - defcon russia 20
static  - defcon russia 20static  - defcon russia 20
static - defcon russia 20
 
Принципы работы статического анализатора кода PVS-Studio
Принципы работы статического анализатора кода PVS-StudioПринципы работы статического анализатора кода PVS-Studio
Принципы работы статического анализатора кода PVS-Studio
 
Михаил Матросов, “С++ без new и delete”
Михаил Матросов, “С++ без new и delete”Михаил Матросов, “С++ без new и delete”
Михаил Матросов, “С++ без new и delete”
 
Tech Talks @NSU: Как приручить дракона: введение в LLVM
Tech Talks @NSU: Как приручить дракона: введение в LLVMTech Talks @NSU: Как приручить дракона: введение в LLVM
Tech Talks @NSU: Как приручить дракона: введение в LLVM
 
Как приручить дракона: введение в LLVM
Как приручить дракона: введение в LLVMКак приручить дракона: введение в LLVM
Как приручить дракона: введение в LLVM
 
Parallel STL
Parallel STLParallel STL
Parallel STL
 
Формальная верификация кода на языке Си
Формальная верификация кода на языке СиФормальная верификация кода на языке Си
Формальная верификация кода на языке Си
 
Формальная верификация кода на языке Си
Формальная верификация кода на языке СиФормальная верификация кода на языке Си
Формальная верификация кода на языке Си
 
Formal verification of C code
Formal verification of C codeFormal verification of C code
Formal verification of C code
 
PascalABC.NET 2015-2016
PascalABC.NET 2015-2016PascalABC.NET 2015-2016
PascalABC.NET 2015-2016
 
Статический анализ кода: Что? Как? Зачем?
Статический анализ кода: Что? Как? Зачем?Статический анализ кода: Что? Как? Зачем?
Статический анализ кода: Что? Как? Зачем?
 
МРТ для данных / Анастасия Горячева (Avito)
МРТ для данных / Анастасия Горячева (Avito)МРТ для данных / Анастасия Горячева (Avito)
МРТ для данных / Анастасия Горячева (Avito)
 
МРТ для данных, Frontend Conf 2016
МРТ для данных, Frontend Conf 2016МРТ для данных, Frontend Conf 2016
МРТ для данных, Frontend Conf 2016
 
Java 8 puzzlers
Java 8 puzzlersJava 8 puzzlers
Java 8 puzzlers
 
20110227 csseminar alvor_breslav
20110227 csseminar alvor_breslav20110227 csseminar alvor_breslav
20110227 csseminar alvor_breslav
 
C++ Базовый. Занятие 02.
C++ Базовый. Занятие 02.C++ Базовый. Занятие 02.
C++ Базовый. Занятие 02.
 
Павел Павлов - Scala для профессионалов - Joker 2013
Павел Павлов - Scala для профессионалов - Joker 2013Павел Павлов - Scala для профессионалов - Joker 2013
Павел Павлов - Scala для профессионалов - Joker 2013
 
Пояснения к статье про Copy-Paste
Пояснения к статье про Copy-PasteПояснения к статье про Copy-Paste
Пояснения к статье про Copy-Paste
 
Дмитрий Прокопцев — R-ссылки в С++11
Дмитрий Прокопцев — R-ссылки в С++11Дмитрий Прокопцев — R-ссылки в С++11
Дмитрий Прокопцев — R-ссылки в С++11
 

На что способны современные статические анализаторы для C#

  • 1. На что способны современные статические анализаторы для C#
  • 2. О Нас • Чем занимается ИСП РАН? • Компиляторное технологии: анализ и оптимизация • R&D проекты для таких компаний, как Samsung, Intel Валерий Игнатьев: к.ф.-м.н., 6 лет занимается статическим анализом. Владимир Кошелев: 4 года занимаюсь статическим анализом, пишу диссертацию про анализ C#. Артем Борзилов: 2 года занимался динамическим анализом и деобфускацией, последние 2 года - статический анализ. 02.04.2016 ИСП РАН 2
  • 3. Автоматический анализ программ • Задача: автоматический поиск ошибок в программах. • Поиск потенциальных ошибок (дефектов) в исходном коде программ • Поиск входных данных, на которых программа упадет (поиск уязвимостей) 02.04.2016 ИСП РАН 3
  • 4. Поиск уязвимостей: Фаззинг 02.04.2016 ИСП РАН 4 Генерация входных данных Средства запуска программы Программа Монитор нештатных ситуаций База «плохих» входных данных
  • 5. Разница между уязвимостью и дефектом • Поиск уязвимостей - это прежде всего поиск «плохих» входных данных. • Поиск дефектов - это поиск подозрительных мест в коде, входные данные искать не требуется. Поэтому его можно сделать менее точным и куда более быстрым, чем поиск уязвимостей. 02.04.2016 ИСП РАН 5
  • 7. Как оценивать качество анализа дефектов? • Фиксируем время, отведенное для анализа, например, 10 минут для всего проекта. • Фиксируем порог для ложных срабатываний, например, не более 50%. • Тогда анализатор должен найти как можно больше срабатываний, соблюдая предыдущие два требования. 02.04.2016 ИСП РАН 7
  • 8. Методы поиска дефектов • Анализ текста исходной программы • Анализ внутреннего представления компилятора (например, абстрактных синтаксических деревьев) • Анализ потенциальных путей выполнения программы 02.04.2016 ИСП РАН 8
  • 9. Поиск использований obsolete методов class Foo { [Obsolete] public void Request(string str) { // Some Code } } ... Foo foo; ... foo.Request("abacaba") 02.04.2016 ИСП РАН 9
  • 10. Ищем .Request( class Foo { [Obsolete] public void Request(string str) { // Some Code } } ... Foo foo; ... foo.Request("abacaba") 02.04.2016 ИСП РАН 10
  • 11. Проблема: поиск найдет использование всех методов Request. class Bar { public Bar Request(string request, string out response) ... } class Baz { public void Request(Bar request) ... } ... Bar bar; Baz baz; baz.Request(bar.Request(s1, s2)) 02.04.2016 ИСП РАН 11
  • 12. Можно, конечно, попытаться отфильтровать с помощью RegEx Однако, RegEx не может распарсить даже HTML, куда там до C#. 02.04.2016 ИСП РАН 12
  • 13. Абстрактное синтаксическое дерево static void Bar(bool f, Foo foo, string s) { if (f) { foo.Request(s); } } 02.04.2016 ИСП РАН 13 Bar bool f Foo foo string s iff (bool) callfoo (Foo) Request s (string) Метод Переменная Оператор Выражение
  • 14. Как найти все obsolete? • Подписываемся на тип вершины call (для обхода АСТ используется паттерн Visitor). • Проверяем, что тип переменной - Foo. • Проверяем, что вызываемый метод – Request. 02.04.2016 ИСП РАН 14 callfoo (Foo) Request s (string) callfoo (Foo) Request c (char []) i (int)
  • 15. Поиск бесконечных циклов Правило: Если индексная переменная имеет тип int и увеличивается в цикле, то в условии она должна проверяться на “меньше”. for (int i = startIdx; i < endIdx; i++) { expected[i] = false; } 02.04.2016 ИСП РАН 15
  • 16. Пример ошибки for (int idx = startIdx; idx > endIdx; idx++) { expected[i] = false; } 02.04.2016 ИСП РАН 16 for = > ++ int idx startIdx idx endIdx idx
  • 17. Можно ли найти с помощью AST обращение к null? 02.04.2016 ИСП РАН 17 В простом случае – можно: public static void AddRange<T>(this IList<T> list, IEnumerable<T> values) { var lt = list as List<T>; if (lt != null) lt.AddRange(values); else { foreach (var item in values) { lt.Add(item); } } }
  • 18. А в реальности – есть проблемы int numDiagnostics = diagnostics == null ? 0 : diagnostics.Count; if (numDiagnostics > 0) { foreach (var diagEntry in diagnostics) { ... } } 02.04.2016 ИСП РАН 18
  • 19. А в реальности – есть проблемы int numDiagnostics = diagnostics == null ? 0 : diagnostics.Count; if (numDiagnostics > 0) { foreach (var diagEntry in diagnostics) { ... } } Условие ошибки: 1) Если diagnostics == null, то numDiagnostics == 0 2) В foreach заходим, только если numDiagnostics > 0 Ошибка невозможна 02.04.2016 ИСП РАН 19
  • 20. Нужны методы анализа путей выполнения И не только для поиска использований null! Также можно искать: • утечку ресурсов, • использование освобожденных объектов (после Dispose), • деление на ноль, • ошибочное явное приведение типов, • дефекты, делающие возможными SQL Injection, XML Injection и т.д. 02.04.2016 ИСП РАН 20
  • 21. Идея символьного выполнения • Разрешим параметрам функции иметь неизвестные (символьные) значения: 1) int Sum(int a, int b) 2) { // a:= xa, b:= xb 3) int c = a + b; 4) int d = c*5; 5) return d; 6) } 02.04.2016 ИСП РАН 21
  • 22. Идея символьного выполнения • Разрешим параметрам функции иметь неизвестные (символьные) значения: 1) int Sum(int a, int b) 2) { // a:= xa, b:= xb 3) int c = a + b; // a:= xa, b:= xb, c:= xa+xb 4) int d = c*5; 5) return d; 6) } 02.04.2016 ИСП РАН 22
  • 23. Идея символьного выполнения • Разрешим параметрам функции иметь неизвестные (символьные) значения: 1) int Sum(int a, int b) 2) { // a:= xa, b:= xb 3) int c = a + b; // a:= xa, b:= xb, c:= xa+xb 4) int d = c*5; // a:= xa, b:= xb, c:= xa+xb, d:= (xa+xb)*5 5) return d; 6) } 02.04.2016 ИСП РАН 23
  • 24. Идея символьного выполнения • Разрешим параметрам функции иметь неизвестные (символьные) значения: 1) int Sum(int a, int b) 2) { // a:= xa, b:= xb 3) int c = a + b; // a:= xa, b:= xb, c:= xa+xb 4) int d = c*5; // a:= xa, b:= xb, c:= xa+xb, d:= (xa+xb)*5 5) return d; // a:= xa, b:= xb, c:= xa+xb, d:= (xa+xb)*5 6) } 02.04.2016 ИСП РАН 24
  • 25. Проблема: как обрабатывать if? 1) int Choose(int a) 2) { // a:= xa, 3) int c = 0; 4) if (a % 4 != 0) 5) c = 1; 6) else 7) c = 2; 8) if (a % 2 != 0 && c == 2) 9) c = 3; 10) return c; 11) } 02.04.2016 ИСП РАН 25
  • 26. Проблема: как обрабатывать if? 1) int Choose(int a) 2) { // a:= xa, 3) int c = 0; // a:= xa, c:= 0 4) if (a % 4 != 0) 5) c = 1; 6) else 7) c = 2; 8) if (a % 2 != 0 && c == 2) 9) c = 3; 10) return c; 11) } 02.04.2016 ИСП РАН 26
  • 27. Проблема: как обрабатывать if? 1) int Choose(int a) 2) { // a:= xa, 3) int c = 0; // a:= xa, c:= 0 4) if (a % 4 != 0) // a:= xa, c:= 0, куда идти?! 5) c = 1; 6) else 7) c = 2; 8) if (a % 2 != 0 && c == 2) 9) c = 3; 10) return c; 11) } 02.04.2016 ИСП РАН 27
  • 28. Давайте определимся с порядком переходов 1) int Choose(int a) 2) { // a:= xa, 3) int c = 0; 4) if (a % 4 != 0) 5) c = 1; 6) else 7) c = 2; 8) if (a % 2 != 0 && c == 2) 9) c = 3; 10) return c; 11) } 02.04.2016 ИСП РАН 28
  • 29. Давайте определимся с порядком переходов 1) int Choose(int a) 2) { // a:= xa, 3) int c = 0; // a:= xa, c:= 0 4) if (a % 4 != 0) 5) c = 1; 6) else 7) c = 2; 8) if (a % 2 != 0 && c == 2) 9) c = 3; 10) return c; 11) } 02.04.2016 ИСП РАН 29
  • 30. Давайте определимся с порядком переходов 1) int Choose(int a) 2) { // a:= xa, 3) int c = 0; // a:= xa, c:= 0 4) if (a % 4 != 0) // a:= xa, c:= 0 5) c = 1; 6) else 7) c = 2; 8) if (a % 2 != 0 && c == 2) 9) c = 3; 10) return c; 11) } 02.04.2016 ИСП РАН 30
  • 31. Давайте определимся с порядком переходов 1) int Choose(int a) 2) { // a:= xa, 3) int c = 0; // a:= xa, c:= 0 4) if (a % 4 != 0) // a:= xa, c:= 0 5) c = 1; 6) else 7) c = 2; // a:= xa, c:= 2 8) if (a % 2 != 0 && c == 2) 9) c = 3; 10) return c; 11) } 02.04.2016 ИСП РАН 31
  • 32. Давайте определимся с порядком переходов 1) int Choose(int a) 2) { // a:= xa, 3) int c = 0; // a:= xa, c:= 0 4) if (a % 4 != 0) // a:= xa, c:= 0 5) c = 1; 6) else 7) c = 2; // a:= xa, c:= 2 8) if (a % 2 != 0 && c == 2) 9) c = 3; // a:= xa, c:= 3 10) return c; 11) } 02.04.2016 ИСП РАН 32
  • 33. Давайте определимся с порядком переходов 1) int Choose(int a) 2) { // a:= xa, 3) int c = 0; // a:= xa, c:= 0 4) if (a % 4 != 0) // a:= xa, c:= 0 5) c = 1; 6) else 7) c = 2; // a:= xa, c:= 2 8) if (a % 2 != 0 && c == 2) 9) c = 3; // a:= xa, c:= 3, не могли прийти! 10) return c; 11) } 02.04.2016 ИСП РАН 33
  • 34. Давайте определимся с порядком переходов 1) int Choose(int a) 2) { // a:= xa, 3) int c = 0; // a:= xa, c:= 0 4) if (a % 4 != 0) // a:= xa, c:= 0, [xa % 4 == 0] 5) c = 1; 6) else 7) c = 2; 8) if (a % 2 != 0 && c == 2) 9) c = 3; 10) return c; 11) } 02.04.2016 ИСП РАН 34
  • 35. Давайте определимся с порядком переходов 1) int Choose(int a) 2) { // a:= xa, 3) int c = 0; // a:= xa, c:= 0 4) if (a % 4 != 0) // a:= xa, c:= 0, [xa % 4 == 0] 5) c = 1; 6) else 7) c = 2; // a:= xa, c:= 2, [xa % 4 == 0] 8) if (a % 2 != 0 && c == 2) 9) c = 3; 10) return c; 11) } 02.04.2016 ИСП РАН 35
  • 36. Символьное состояние состоит из: Значений переменных, выраженных через символьные значения a:= xa, c:= 2, [xa % 4 != 0], (7) Условий пройденных переходов (Предикат пути) a:= xa, c:= 2, [xa % 4 != 0], (7) Текущей точки в программе a:= xa, c:= 2, [xa % 4 != 0], (7) 02.04.2016 ИСП РАН 36
  • 37. Как с помощью этого искать использование null? 1) int Index(IList<string> diags, string elem) 2) { 3) int nd; // diags:= xd 4) if (diags == null) 5) nd = 0; 6) else 7) nd = diags.Count; 8) if (nd >= 0) 9) { 10) return diags.IndexOf(elem); 11) } 12) return -1; 13) } 02.04.2016 ИСП РАН 37
  • 38. Как с помощью этого искать использование null? 1) int Index(IList<string> diags, string elem) 2) { 3) int nd; // diags:= xd 4) if (diags == null) // diags:= xd, [xd = null] 5) nd = 0; 6) else 7) nd = diags.Count; 8) if (nd >= 0) 9) { 10) return diags.IndexOf(elem); 11) } 12) return -1; 13) } 02.04.2016 ИСП РАН 38
  • 39. Как с помощью этого искать использование null? 1) int Index(IList<string> diags, string elem) 2) { 3) int nd; // diags:= xd 4) if (diags == null) // diags:= xd, [xd = null] 5) nd = 0; // diags:= xd, nd:= 0 [xd = null] 6) else 7) nd = diags.Count; 8) if (nd >= 0) 9) { 10) return diags.IndexOf(elem); 11) } 12) return -1; 13) } 02.04.2016 ИСП РАН 39
  • 40. Как с помощью этого искать использование null? 1) int Index(IList<string> diags, string elem) 2) { 3) int nd; // diags:= xd 4) if (diags == null) // diags:= xd, [xd = null] 5) nd = 0; // diags:= xd, nd:= 0 [xd = null] 6) else 7) nd = diags.Count; 8) if (nd >= 0) // diags:= xd, nd:= 0 [xd = null, 0>= 0] 9) { 10) return diags.IndexOf(elem); 11) } 12) return -1; 13) } 02.04.2016 ИСП РАН 40
  • 41. Как с помощью этого искать использование null? 1) int Index(IList<string> diags, string elem) 2) { 3) int nd; // diags:= xd 4) if (diags == null) // diags:= xd, [xd = null] 5) nd = 0; // diags:= xd, nd:= 0 [xd = null] 6) else 7) nd = diags.Count; 8) if (nd > 0) // diags:= xd, nd:= 0 [xd = null, 0 > 0] 9) { 10) return diags.IndexOf(elem); 11) } 12) return -1; 13) } 02.04.2016 ИСП РАН 41
  • 42. Как решить предикат пути? • Для решения используются специальные сторонние программы: SMT-решатели (Z3, stp, etc.). • Полученные формулы из символьных значений можно практически «как есть» отдавать решателям. • Если есть решение, то решатель его явно приведет, если его нет, то скажет, что формула несовместна. 02.04.2016 ИСП РАН 42
  • 43. Как добиться масштабируемости анализа? • Проблема: даже если не учитывать циклы, путей выполнения функции экспоненциально много. • Если в функции 10 операторов If, то через них проходит 1024 различных пути. • С учетом циклов, путей выполнения становится бесконечно много. 02.04.2016 ИСП РАН 43
  • 44. Можно объединять символьные состояния if (p == null) c = 1; // p:= xp, c:= 1, …, [… && xp = null], else c = 0; // p:= xp, c:= 0, …, [… && xp != null], // p:= xp, c:= (xp=null ? 1: 0), [… && (xp!=null || xp=null), Итого 1024 возможных пути превращаются в 10 объединений. 02.04.2016 ИСП РАН 44
  • 45. Анализ циклов На практике, для получения хороших результатов достаточно анализировать лишь несколько итераций цикла. Как следствие, работа с массивами и коллекциями поддерживается только частично. 02.04.2016 ИСП РАН 45
  • 46. Использование указателя после сравнения с null в цикле. public int IndexOf(T item, IList<int> list) { for (int i = fromIndex, fakeIndex = 0; i < toIndex; i++, fakeIndex++) { var current = list[i]; if (current == null && item == null) return fakeIndex; if (current.Equals(item)) return fakeIndex; } return -1; } 02.04.2016 ИСП РАН 46
  • 47. Использование нулевого указателя: нужно поддерживать вызовы функции if (fcontext == null) { // some code here } else { // some code there } vs.CreateWeight(fcontext, weightSearcher); ------------------------------------------ public override void CreateWeight(IDictionary context, IndexSearcher searcher) { Weight w = searcher.CreateNormalizedWeight(q); context[this] = w; } 02.04.2016 ИСП РАН 47
  • 48. Как организовать межпроцедурный анализ? • Стандартный подход: при вызове функции начинать её символьное выполнение с текущим символьным состоянием. • Плюс: точно • Минус: очень медленно • Альтернативный подход: заранее построить «резюме» для всех вызванных функций и использовать их вместо повторного анализа: • Плюс: достаточно быстро • Минус: неточно 02.04.2016 ИСП РАН 48
  • 49. Какую информацию содержит резюме? string Foo(IList<int> list, out string str, TextWriter wr) • К объекту wr будет обращение, если он не null • К объекту list будет обращение, если wr != null • После выполнения вызова, str гарантированно не null. • Функция может вернуть null • Функция может бросить IOException 02.04.2016 ИСП РАН 49
  • 50. Что такое граф вызовов? public void Baz() { } public void Main() { Foo(); Bar(); } public void Bar() { Baz(); } public void Foo() { Bar(); Baz(); } 02.04.2016 ИСП РАН 50 Main Foo Bar Baz
  • 51. Обратный топологический порядок public void Baz() { } public void Main() { Foo(); Bar(); } public void Bar() { Baz(); } public void Foo() { Bar(); Baz(); } 02.04.2016 ИСП РАН 51 Main Foo Bar Baz
  • 52. Порядок анализа public void Baz() { } public void Main() { Foo(); Bar(); } public void Bar() { Baz(); } public void Foo() { Bar(); Baz(); } 02.04.2016 ИСП РАН 52 Main Foo Bar Baz Резюме
  • 53. Порядок анализа public void Baz() { } public void Main() { Foo(); Bar(); } public void Bar() { Baz(); } public void Foo() { Bar(); Baz(); } 02.04.2016 ИСП РАН 53 Main Foo Bar Baz Резюме Резюме
  • 54. Порядок анализа public void Baz() { } public void Main() { Foo(); Bar(); } public void Bar() { Baz(); } public void Foo() { Bar(); Baz(); } 02.04.2016 ИСП РАН 54 Main Foo Bar Baz Резюме Резюме Резюме
  • 55. Порядок анализа public void Baz() { } public void Main() { Foo(); Bar(); } public void Bar() { Baz(); } public void Foo() { Bar(); Baz(); } 02.04.2016 ИСП РАН 55 Main Foo Bar Baz Резюме Резюме Резюме Резюме
  • 56. Проблемы при построении графа вызовов • Виртуальные вызовы • Вызовы делегатов • Вызовы внешних функций • Рекурсия 02.04.2016 ИСП РАН 56
  • 57. Схема работы анализатора 02.04.2016 ИСП РАН 57 Построение графа вызовов Граф вызовов Анализ функций в обратном топологическом порядке Ошибки Фильтрация и выдача ошибок
  • 58. Пример: Won’t fix public string Foo(object obj) { return (obj as Bar).Baz(); } 02.04.2016 ИСП РАН 58
  • 59. При анализе неизвестен контракт public string Foo(IList<string> list) { int max = -1; string maxString = null; foreach (var elem in list) { if (elem.Length > max) { max = elem.Length; maxString = elem; } } return maxString.ToUpper(); } 02.04.2016 ИСП РАН 59
  • 60. При анализе неизвестен контракт public string Foo(IList<string> list) { int max = -1; string maxString = null; foreach (var elem in list) { if (elem.Length > max) { max = elem.Length; maxString = elem; } } return maxString.ToUpper(); } 02.04.2016 ИСП РАН 60
  • 61. При анализе неизвестен контракт public string Foo(IList<string> list) { Debug.Assert(list.Any()) int max = -1; string maxString = null; foreach (var elem in list) { if (elem.Length > max) { max = elem.Length; maxString = elem; } } return maxString.ToUpper(); } 02.04.2016 ИСП РАН 61
  • 62. Причины ложных срабатываний • Неточности в резюме функций; • Наличие неизвестных вызовов; • Наличие неявных контрактов функций; • Наличие инвариантов классов. 02.04.2016 ИСП РАН 62