SlideShare une entreprise Scribd logo
1  sur  67
Télécharger pour lire hors ligne
Динамический анализ
программ на C++
Алексей Самсонов, Google
Екатеринбург, УрФУ, 29.04.2013
Команда (Google RU-MSK)
Константин Серебряный (TL)
Дмитрий Вьюков
Тимур Исходжанов
Сергей Матвеев
Александр Потапенко
Алексей Самсонов
Евгений Степанов
Содержание
Часть 1
● Ошибки работы с памятью
● AddressSanitizer
Часть 2
● Гонки
● ThreadSanitizer
В мире много кода на C и C++
● Операционные системы
● Браузеры (Chromium, Firefox, Safari)
● Виртуальные машины (Java)
● Базы данных (MySQL)
● Backend веб-сервисов (поиск)
● Веб-серверы (Apache, nginx)
Ошибки работы с памятью в C/C++
● Кодеки и рендереры (ffmpeg, pdf)
● Использование освобождённой памяти
(use-after-free)
● Использование неинициализированной
памяти (uninitialized-memory-read)
● Утечки памяти (memory leaks)
● Неверный порядок
инициализации/уничтожения глобальных
объектов
Ошибки работы с памятью в C/C++
● Выход за границы буфера (out-of-bound
access)
● Использование освобождённой память
(use-after-free)
● Использование неинициализированной
памяти (uninitialized-memory-read)
● Утечки памяти (memory leaks)
● Неверный порядок
инициализации/уничтожения глобальных
объектов
Выход за границы буфера (стек)
void authorize() {
...
char username[128];
gets(username); // 128 bytes should be
// enough for everyone.
...
}
Использование освобожденной
памяти
~UserTable() {
...
delete all_users;
LOG() << "Deleted " << all_users->size()
<< " users!";
}
Можно ли сделать этот код ещё хуже?
Использование освобожденной
памяти
~UserTable() {
...
delete all_users;
RunAction(all_users->action_on_delete);
}
Всегда в моде: racy use-after-free
Поток 1
void DeleteEntries() {
have_entries = false;
delete entries;
}
Поток 2
Entry *GetEntry(int i) {
if (have_entries)
return entries[i];
return 0;
}
Инструменты для поиска ошибок
● Valgrind/Memcheck
● DynamoRIO/Dr. Memory
● Purify
● Insure++
● Mudflap
● Electric Fence / Page Heap / Guard Malloc
Проблемы:
● Замедление программы (в 10 и более раз)
● Поиск ошибок только для динамически
выделенной памяти (heap)
Статический анализ программ
● Формальная верификация?
● Clang Static Analyzer?
Проблемы:
● Баланс между эффективностью и
полезностью
● Баланс между false negative и false
positive
Есть ли в программе ошибка?
int array[10] = {...};
int main(int argc, char *argv[]) {
return array[2 + argc];
}
Пример отчёта об ошибке (1)
int global_array[100] = {-1};
int main(int argc, char **argv) {
return global_array[argc + 100];
}
==10538== ERROR: AddressSanitizer global-buffer-overflow
READ of size 4 at 0x000000415354 thread T0
#0 0x402481 in main a.cc:3
<...>
0x000000415354 is located 4 bytes to the right of global
variable 'global_array' (0x4151c0) of size 400
Пример отчёта об ошибке (2)
int main(int argc, char **argv) {
int stack_array[100];
stack_array[1] = 0;
return stack_array[argc + 100];
}
==10589== ERROR: AddressSanitizer stack-buffer-overflow
READ of size 4 at 0x7f5620d981b4 thread T0
#0 0x4024e8 in main a.cc:4
Address 0x7f5620d981b4 is located at offset 436 in frame
<main> of T0's stack:
This frame has 1 object(s):
[32, 432) 'stack_array'
Пример отчёта об ошибке (3)
int main(int argc, char **argv) {
int *array = new int[100];
int res = array[argc + 100];
delete [] array;
return res;
}
==10565== ERROR: AddressSanitizer heap-buffer-overflow
READ of size 4 at 0x7fe4b0c76214 thread T0
#0 0x40246f in main a.cc:3
0x7fe4b0c76214 is located 4 bytes to the right of 400-
byte region [0x7fe..., 0x7fe...)
allocated by thread T0 here:
#0 0x402c36 in operator new[](unsigned long)
#1 0x402422 in main a.cc:2
Пример отчёта об ошибке (4)
int main(int argc, char **argv) {
int *array = new int[100];
delete [] array;
return array[argc];
}
==30226== ERROR: AddressSanitizer heap-use-after-free
READ of size 4 at 0x7faa07fce084 thread T0
#0 0x40433c in main a.cc:4
0x7faa07fce084 is located 4 bytes inside of 400-byte
region
freed by thread T0 here:
#0 0x4058fd in operator delete[](void*)
#1 0x404303 in main a.cc:3
previously allocated by thread T0 here:
#0 0x405579 in operator new[](unsigned long)
#1 0x4042f3 in main a.cc:2
Что такое AddressSanitizer?
● Компиляторная инструментация
○ Проверка всех обращений к памяти
○ Добавление редзон("redzones") вокруг
глобальных и локальных переменных
● Runtime-библиотека
○ Аллокатор (выделение/освобождение памяти)
○ Отслеживание всех потоков
○ Печать отчётов об ошибках
○ Обёртки функций из стандартной библиотеки
Теневой байт (shadow byte)
Если адреса всех переменных кратны 8, то у любых
выровненных восьми байт есть 9 состояний:
0
7
6
5
4
3
2
1
-1
Тень адресного пространства (*)
Приложение
0xFFFFFFFF
0x20000000
Тень
0x1FFFFFFF
0x04000000
Mprotect
0x03FFFFF
0x0000000
Инструментация доступа к памяти
int *a = ...;
*a = ...;
char *shadow = a >> 3;
if (*shadow != 0 &&
*shadow < (a&7) + 4)
ReportError(a);
*a = ...;
Инструментация стека
void foo() {
char a[328];
<------------- CODE ------------->
}
Инструментация стека
void foo() {
char redzone1[32]; // 32-byte aligned
char a[328];
char redzone2[24];
char redzone3[32];
int *shadow = (&rz1 >> 3);
shadow[0] = 0xffffffff; // poison rz1
shadow[11] = 0xffffff00; // poison rz2
shadow[12] = 0xffffffff; // poison rz3
<------------- CODE ------------->
shadow[0] = shadow[11] = shadow[12] = 0;
}
Инструментация глобальных
объектов
int global;
struct {
int original;
char redzone[60];
} global; // 32-byte aligned
LLVM спешит на помощь!
Интеграция в LLVM
● Clang (или другой фронтенд) генерирует
промежуточное представление
программы;
● ASan добавляет инструментацию;
● Бэкенд оптимизирует код и генерирует
объектный файл;
● Исполняемый файл линкуется с runtime-
библиотекой.
Runtime-библиотека
● Аллокатор
○ Добавление редзон вокруг блоков динамически
выделенной памяти
○ Карантин для освобождённой памяти
○ Хранение стека вызовов для каждой аллокации
● Печать отчётов об ошибках
● Перехват библиотечных функций
char bad_string[2] = {'h', 'i'};
int len = strlen(bad_string);
Производительность
● Замедление программы: 2x
● Использование памяти: 1,5-3x
● "Just works" для большинства тестов и
реальных программ
● Незначительное замедление для GUI-
программ (Chromium+ASan работает без
проблем)
Трофеи
1000+ найденных ошибок повсюду:
● Chromium, Firefox, Safari
● Сервисы Google
● Perl, PHP, MySQL, ffmpeg, webrtc, vim
● LLVM, GCC
Google заплатил $130000+ внешним
исследователям за security-ошибки,
найденные с помощью AddressSanitizer.
Что будет дальше?
● Поиск других видов ошибок (в ближайшее
время: поиск утечек памяти)
● Поиск ошибок в системных и
прекомпилированных библиотеках
● AddressSanitizer для ядра Linux
● AddressSanitizer для Windows (нужен
компилятор).
Попробуйте AddressSanitizer!
● LLVM/Clang 3.1+
clang++ -fsanitize=address a.cc
● GCC 4.8+
g++ -fsanitize=address a.cc
● Платформы:
Linux, Mac OS X, Android
code.google.com/p/address-sanitizer
Гонки (data races)
Что такое гонка?
Гонка происходит, когда два потока одновременно
обращаются к одной и той же переменной, и хотя бы
одно из обращений является записью.
Если в программе на C++ могут возникнуть гонки, её
поведение не определено.
Компилятор имеет право считать, что в программе нет
гонок.
Что напечатает этот код?
Поток 1
cout << x << "n";
x = 1;
cout << y << "n";
Поток 2
cout << y << "n";
y = 1;
cout << x << "n";
int x = 0, y = 0;
"Безвредные" гонки
● Синхронизация замедляет программу.
● Может возникнуть желание допустить
гонки на "не очень важных" данных.
● Не нужно этого делать. В C++ не может
быть "безвредных" (benign) гонок.
H-J. Boehm "How to miscompile programs with "benign"
data races"
D. Vyukov "Benign data races: what could possibly go
wrong?"
Пример "безвредной гонки"
long long
get_value() {
return value;
}
void set_value(
long long x) {
value = x;
}
Является ли 64-битное чтение / запись атомарной
операцией?
Пример "безвредной гонки" (2)
...
int my_counter = counter; // read global
if (my_counter > my_old_counter) {
my_action = print_stats;
}
...
if (my_counter > my_old_counter) {
run_action(my_action);
}
Пример "безвредной гонки" (3)
my_action = launch_nuclear_rocket;
...
int my_counter = counter; // read global
if (my_counter > my_old_counter) {
my_action = print_stats;
}
...
my_counter = counter;
if (my_counter > my_old_counter) {
run_action(my_action);
}
А как же настоящие гонки?
Метод-лжец
// Returns the user with a given ID
User& getUser(int id) {
MutexLock(&mutex);
CHECK(0 <= id && id < users.size());
return users[id];
}
Метод-лжец
// Returns the user with a given ID
User& getUser(int id) {
MutexLock(&mutex);
CHECK(0 <= id && id < users.size());
return users[id];
}
Что не так с этим кодом?
class AbstractAction {
public:
AbstractAction(Executor *executor) {
executor->add(this);
...
}
...
}
Что не так с этим кодом?
class AbstractAction {
public:
AbstractAction(Executor *executor) {
executor->add(this);
...
}
...
virtual void Run() = 0;
}
Гонка на vptr
class AbstractAction {
public:
AbstractAction(Executor *executor) {
executor->add(this);
// переключение контекста
}
...
virtual void Run() = 0;
}
Pure virtual call!
ThreadSanitizer спешит на помощь
WARNING: ThreadSanitizer: data race on vptr (ctor/dtor vs
virtual call)
Read of size 8 at 0x7fff103327f0 by thread T3:
#0 ExecutorThread::RunAction() executor.cc:1112
#1 ExecutorThread::Start() executor.cc:1283
Previous write of size 8 at 0x7fff103327f0 by main
thread:
#0 MyAction::MyAction()vptr_race.cc:48
#1 main vptr_race.cc:59
Location is stack of main thread.
Что такое ThreadSanitizer?
● Компиляторная инструментация
○ Проверка всех обращений к памяти
○ Отслеживание событий: вход/выход в функцию,
обновление vptr, атомарные операции
● Runtime-библиотека
○ Аллокатор (выделение/освобождение памяти)
○ Отслеживание всех потоков
○ Печать отчётов об ошибках
○ Обёртки функций из стандартной библиотеки
○ Поддержка синхронизационных примитивов
Инструментация (1)
int *p = ...;
*p = 42;
int *p = ...;
__tsan_write4(p);
*p = 42;
Инструментация (2)
void foo() {
...
}
void foo() {
__tsan_func_entry(
__builtin_return_address(0));
...
__tsan_func_exit();
}
Инструментация (3)
A::~A() {
// this->vptr = A::vptr;
}
A::~A() {
__tsan_vptr_update(&this->vptr, A::vptr);
// this->vptr = A::vptr;
}
Runtime-библиотека
● Проверка всех доступов в память
● Выделение/освобождение памяти
● Поддержка синхронизации (мьютексы,
атомарные операции)
● Перехват функций работы с потоками
(libpthread)
● Перехват функций из стандартной
библиотеки
● Печать отчётов об ошибках
Абстрактное время потока
Увеличивается после каждого события:
void foo() { // time = 1
Lock(&mutex); // time = 2
x = 1; // time = 3
Unlock(&mutex); // time = 4
} // time = 5
Векторные часы (vector clock)
VC[1..N], где VC[i] - время i-го потока.
Векторные часы есть у каждого потока:
VC[1..N], где VC[i] - время i-го потока в
момент последней синхронизации с ним.
Векторные часы есть у каждого мьютекса:
VC[1..N], VC[i] - время i-го потока, когда
он в последний раз отпустил мьютекс.
Обновление векторных часов
Доступ к памяти в потоке T:
T->VC[T->id]++;
Обновление векторных часов (2)
Взятие мьютекса M в потоке T:
для всех i:
T->VC[i] = max(T->VC[i], M->VC[i]);
Освобождение мьютекса M в потоке T:
для всех i:
M->VC[i] = max(M->VC[i], T->VC[i]);
Как кодировать обращение к
памяти?
Обращение к выровненным 8 байтам
адресного пространства кодируется через:
● ID потока (TID)
● Время этого потока (TS)
● позиция (0..7) и размер (1,2,4,8)
обращения
● является ли доступ чтением или
записью?
Вся эта информация помещается в 8 байт.
Пример обращений к памяти
Приложение Тень
Запись из потока T1
Приложение Тень
T1
TS1
W
0:2
Чтение из потока T2
Приложение Тень
T1
TS1
W
0:2
T2
TS2
4:4
R
Чтение из потока T3
Приложение Тень
T1
TS1
W
0:2
T2
TS2
4:4
R
T3
TS3
0:4
R
Гонка?
Тень
T1
TS1
W
0:2
T2
TS2
4:4
R
T3
TS3
0:4
R
● Доступы
пересекаются?
● Разные потоки?
● Хотя бы одно из
обращений -
запись?
● Есть ли
синхронизация?
Гонка, если T3->VC[T1] < TS1
Как узнать стек вызовов для
каждого обращения к памяти?
● Циклическая очередь всех событий в
каждом потоке:
○ доступ к памяти
○ вход/выход из функции
○ взятие/освобождение мьютекса
● "Повторение" событий перед печатью
отчёта:
○ Через некоторое время события "забываются"
○ Неограниченный размер стека вызовов в отчёте
○ Отчёт содержит множество мьютексов, взятых в
каждом потоке.
Результаты
● Замедление программы: 4-10x (в 10 раз
быстрее аналогов).
● Использование памяти: 5-8x
● 600+ найденных ошибок
● Работает для больших серверных
приложений
Что будет дальше?
● Портирование на другие системы (сейчас
- только 64-битный Linux).
● Поиск ошибок в системных и
прекомпилированных библиотеках
● Больше оптимизаций, больше
пользователей
● Поиск гонок в коде на Java
Попробуйте ThreadSanitizer!
● LLVM/Clang 3.2+
clang++ -fsanitize=thread a.cc
● GCC 4.8+
g++ -fsanitize=thread a.cc
● Go
go build -race
code.google.com/p/thread-sanitizer

Contenu connexe

Tendances

Юрий Ефимочев, Компилируемые в реальном времени DSL для С++
Юрий Ефимочев, Компилируемые в реальном времени DSL для С++ Юрий Ефимочев, Компилируемые в реальном времени DSL для С++
Юрий Ефимочев, Компилируемые в реальном времени DSL для С++ Sergey Platonov
 
ПВТ - осень 2014 - Лекция 4 - Стандарт POSIX Threads. Реентерабельность. Сигн...
ПВТ - осень 2014 - Лекция 4 - Стандарт POSIX Threads. Реентерабельность. Сигн...ПВТ - осень 2014 - Лекция 4 - Стандарт POSIX Threads. Реентерабельность. Сигн...
ПВТ - осень 2014 - Лекция 4 - Стандарт POSIX Threads. Реентерабельность. Сигн...Alexey Paznikov
 
Григорий Демченко, Универсальный адаптер
Григорий Демченко, Универсальный адаптерГригорий Демченко, Универсальный адаптер
Григорий Демченко, Универсальный адаптерSergey Platonov
 
ПВТ - осень 2014 - Лекция 5 - Многопоточное программирование в языке С++. Р...
ПВТ - осень 2014 - Лекция 5 - Многопоточное программирование в языке С++.   Р...ПВТ - осень 2014 - Лекция 5 - Многопоточное программирование в языке С++.   Р...
ПВТ - осень 2014 - Лекция 5 - Многопоточное программирование в языке С++. Р...Alexey Paznikov
 
ПВТ - весна 2015 - Лекция 6. Разработка параллельных структур данных на основ...
ПВТ - весна 2015 - Лекция 6. Разработка параллельных структур данных на основ...ПВТ - весна 2015 - Лекция 6. Разработка параллельных структур данных на основ...
ПВТ - весна 2015 - Лекция 6. Разработка параллельных структур данных на основ...Alexey Paznikov
 
Павел Сушин «Асинхронное программирование на С++: callbacks, futures, fibers»
Павел Сушин «Асинхронное программирование на С++: callbacks, futures, fibers»Павел Сушин «Асинхронное программирование на С++: callbacks, futures, fibers»
Павел Сушин «Асинхронное программирование на С++: callbacks, futures, fibers»Platonov Sergey
 
Григорий Демченко, “Асинхронность и сопрограммы: обработка данных“
Григорий Демченко, “Асинхронность и сопрограммы: обработка данных“Григорий Демченко, “Асинхронность и сопрограммы: обработка данных“
Григорий Демченко, “Асинхронность и сопрограммы: обработка данных“Platonov Sergey
 
WinDbg в руках .NET разработчика
WinDbg в руках .NET разработчикаWinDbg в руках .NET разработчика
WinDbg в руках .NET разработчикаMikhail Shcherbakov
 
Полухин Антон, Как делать не надо: C++ велосипедостроение для профессионалов
Полухин Антон, Как делать не надо: C++ велосипедостроение для профессионаловПолухин Антон, Как делать не надо: C++ велосипедостроение для профессионалов
Полухин Антон, Как делать не надо: C++ велосипедостроение для профессионаловSergey Platonov
 
Михаил Щербаков "WinDbg сотоварищи"
Михаил Щербаков "WinDbg сотоварищи"Михаил Щербаков "WinDbg сотоварищи"
Михаил Щербаков "WinDbg сотоварищи"Mikhail Shcherbakov
 
Антон Полухин, Немного о Boost
Антон Полухин, Немного о BoostАнтон Полухин, Немного о Boost
Антон Полухин, Немного о BoostSergey Platonov
 
Максим Хижинский Lock-free maps
Максим Хижинский Lock-free mapsМаксим Хижинский Lock-free maps
Максим Хижинский Lock-free mapsPlatonov Sergey
 
Поговорим о микрооптимизациях .NET-приложений
Поговорим о микрооптимизациях .NET-приложенийПоговорим о микрооптимизациях .NET-приложений
Поговорим о микрооптимизациях .NET-приложенийAndrey Akinshin
 
Игорь Кудрин, «Используем неизменяемые данные и создаем качественный код»
Игорь Кудрин, «Используем неизменяемые данные и создаем качественный код»Игорь Кудрин, «Используем неизменяемые данные и создаем качественный код»
Игорь Кудрин, «Используем неизменяемые данные и создаем качественный код»Platonov Sergey
 
WinDbg со товарищи
WinDbg со товарищиWinDbg со товарищи
WinDbg со товарищиCUSTIS
 
ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инстр...
ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инстр...ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инстр...
ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инстр...Alexey Paznikov
 
Продолжаем говорить о микрооптимизациях .NET-приложений
Продолжаем говорить о микрооптимизациях .NET-приложенийПродолжаем говорить о микрооптимизациях .NET-приложений
Продолжаем говорить о микрооптимизациях .NET-приложенийAndrey Akinshin
 
Лекция 6. Стандарт OpenMP
Лекция 6. Стандарт OpenMPЛекция 6. Стандарт OpenMP
Лекция 6. Стандарт OpenMPMikhail Kurnosov
 
Распространённые ошибки оценки производительности .NET-приложений
Распространённые ошибки оценки производительности .NET-приложенийРаспространённые ошибки оценки производительности .NET-приложений
Распространённые ошибки оценки производительности .NET-приложенийMikhail Shcherbakov
 
200 open source проектов спустя: опыт статического анализа исходного кода
200 open source проектов спустя: опыт статического анализа исходного кода200 open source проектов спустя: опыт статического анализа исходного кода
200 open source проектов спустя: опыт статического анализа исходного кодаAndrey Karpov
 

Tendances (20)

Юрий Ефимочев, Компилируемые в реальном времени DSL для С++
Юрий Ефимочев, Компилируемые в реальном времени DSL для С++ Юрий Ефимочев, Компилируемые в реальном времени DSL для С++
Юрий Ефимочев, Компилируемые в реальном времени DSL для С++
 
ПВТ - осень 2014 - Лекция 4 - Стандарт POSIX Threads. Реентерабельность. Сигн...
ПВТ - осень 2014 - Лекция 4 - Стандарт POSIX Threads. Реентерабельность. Сигн...ПВТ - осень 2014 - Лекция 4 - Стандарт POSIX Threads. Реентерабельность. Сигн...
ПВТ - осень 2014 - Лекция 4 - Стандарт POSIX Threads. Реентерабельность. Сигн...
 
Григорий Демченко, Универсальный адаптер
Григорий Демченко, Универсальный адаптерГригорий Демченко, Универсальный адаптер
Григорий Демченко, Универсальный адаптер
 
ПВТ - осень 2014 - Лекция 5 - Многопоточное программирование в языке С++. Р...
ПВТ - осень 2014 - Лекция 5 - Многопоточное программирование в языке С++.   Р...ПВТ - осень 2014 - Лекция 5 - Многопоточное программирование в языке С++.   Р...
ПВТ - осень 2014 - Лекция 5 - Многопоточное программирование в языке С++. Р...
 
ПВТ - весна 2015 - Лекция 6. Разработка параллельных структур данных на основ...
ПВТ - весна 2015 - Лекция 6. Разработка параллельных структур данных на основ...ПВТ - весна 2015 - Лекция 6. Разработка параллельных структур данных на основ...
ПВТ - весна 2015 - Лекция 6. Разработка параллельных структур данных на основ...
 
Павел Сушин «Асинхронное программирование на С++: callbacks, futures, fibers»
Павел Сушин «Асинхронное программирование на С++: callbacks, futures, fibers»Павел Сушин «Асинхронное программирование на С++: callbacks, futures, fibers»
Павел Сушин «Асинхронное программирование на С++: callbacks, futures, fibers»
 
Григорий Демченко, “Асинхронность и сопрограммы: обработка данных“
Григорий Демченко, “Асинхронность и сопрограммы: обработка данных“Григорий Демченко, “Асинхронность и сопрограммы: обработка данных“
Григорий Демченко, “Асинхронность и сопрограммы: обработка данных“
 
WinDbg в руках .NET разработчика
WinDbg в руках .NET разработчикаWinDbg в руках .NET разработчика
WinDbg в руках .NET разработчика
 
Полухин Антон, Как делать не надо: C++ велосипедостроение для профессионалов
Полухин Антон, Как делать не надо: C++ велосипедостроение для профессионаловПолухин Антон, Как делать не надо: C++ велосипедостроение для профессионалов
Полухин Антон, Как делать не надо: C++ велосипедостроение для профессионалов
 
Михаил Щербаков "WinDbg сотоварищи"
Михаил Щербаков "WinDbg сотоварищи"Михаил Щербаков "WinDbg сотоварищи"
Михаил Щербаков "WinDbg сотоварищи"
 
Антон Полухин, Немного о Boost
Антон Полухин, Немного о BoostАнтон Полухин, Немного о Boost
Антон Полухин, Немного о Boost
 
Максим Хижинский Lock-free maps
Максим Хижинский Lock-free mapsМаксим Хижинский Lock-free maps
Максим Хижинский Lock-free maps
 
Поговорим о микрооптимизациях .NET-приложений
Поговорим о микрооптимизациях .NET-приложенийПоговорим о микрооптимизациях .NET-приложений
Поговорим о микрооптимизациях .NET-приложений
 
Игорь Кудрин, «Используем неизменяемые данные и создаем качественный код»
Игорь Кудрин, «Используем неизменяемые данные и создаем качественный код»Игорь Кудрин, «Используем неизменяемые данные и создаем качественный код»
Игорь Кудрин, «Используем неизменяемые данные и создаем качественный код»
 
WinDbg со товарищи
WinDbg со товарищиWinDbg со товарищи
WinDbg со товарищи
 
ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инстр...
ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инстр...ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инстр...
ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инстр...
 
Продолжаем говорить о микрооптимизациях .NET-приложений
Продолжаем говорить о микрооптимизациях .NET-приложенийПродолжаем говорить о микрооптимизациях .NET-приложений
Продолжаем говорить о микрооптимизациях .NET-приложений
 
Лекция 6. Стандарт OpenMP
Лекция 6. Стандарт OpenMPЛекция 6. Стандарт OpenMP
Лекция 6. Стандарт OpenMP
 
Распространённые ошибки оценки производительности .NET-приложений
Распространённые ошибки оценки производительности .NET-приложенийРаспространённые ошибки оценки производительности .NET-приложений
Распространённые ошибки оценки производительности .NET-приложений
 
200 open source проектов спустя: опыт статического анализа исходного кода
200 open source проектов спустя: опыт статического анализа исходного кода200 open source проектов спустя: опыт статического анализа исходного кода
200 open source проектов спустя: опыт статического анализа исходного кода
 

Similaire à 20130429 dynamic c_c++_program_analysis-alexey_samsonov

Семинар 5. Многопоточное программирование на OpenMP (часть 5)
Семинар 5. Многопоточное программирование на OpenMP (часть 5)Семинар 5. Многопоточное программирование на OpenMP (часть 5)
Семинар 5. Многопоточное программирование на OpenMP (часть 5)Mikhail Kurnosov
 
Address Sanitizer или как сделать программы на c/с++ надежнее и безопаснее (К...
Address Sanitizer или как сделать программы на c/с++ надежнее и безопаснее (К...Address Sanitizer или как сделать программы на c/с++ надежнее и безопаснее (К...
Address Sanitizer или как сделать программы на c/с++ надежнее и безопаснее (К...Ontico
 
static - defcon russia 20
static  - defcon russia 20static  - defcon russia 20
static - defcon russia 20DefconRussia
 
200 open source проектов спустя: опыт статического анализа исходного кода
200 open source проектов спустя:опыт статического анализа исходного кода200 open source проектов спустя:опыт статического анализа исходного кода
200 open source проектов спустя: опыт статического анализа исходного кодаPositive Hack Days
 
Принципы работы статического анализатора кода PVS-Studio
Принципы работы статического анализатора кода PVS-StudioПринципы работы статического анализатора кода PVS-Studio
Принципы работы статического анализатора кода PVS-StudioAndrey Karpov
 
Статический анализ кода: Что? Как? Зачем?
Статический анализ кода: Что? Как? Зачем?Статический анализ кода: Что? Как? Зачем?
Статический анализ кода: Что? Как? Зачем?Andrey Karpov
 
Android: Как написать приложение, которое не тормозит
Android: Как  написать приложение, которое не тормозитAndroid: Как  написать приложение, которое не тормозит
Android: Как написать приложение, которое не тормозитElena Kotina
 
11 встреча — Введение в GPGPU (А. Свириденков)
11 встреча — Введение в GPGPU (А. Свириденков)11 встреча — Введение в GPGPU (А. Свириденков)
11 встреча — Введение в GPGPU (А. Свириденков)Smolensk Computer Science Club
 
Лекция 8. Intel Threading Building Blocks
Лекция 8. Intel Threading Building BlocksЛекция 8. Intel Threading Building Blocks
Лекция 8. Intel Threading Building BlocksMikhail Kurnosov
 
Tech Talks @NSU: Как приручить дракона: введение в LLVM
Tech Talks @NSU: Как приручить дракона: введение в LLVMTech Talks @NSU: Как приручить дракона: введение в LLVM
Tech Talks @NSU: Как приручить дракона: введение в LLVMTech Talks @NSU
 
Как приручить дракона: введение в LLVM
Как приручить дракона: введение в LLVMКак приручить дракона: введение в LLVM
Как приручить дракона: введение в LLVMTech Talks @NSU
 
статический анализ кода
статический анализ кодастатический анализ кода
статический анализ кодаAndrey Karpov
 
Статический анализ кода
Статический анализ кода Статический анализ кода
Статический анализ кода Pavel Tsukanov
 
Лекция 12 (часть 1): Языки программирования семейства PGAS: Cray Chapel
Лекция 12 (часть 1): Языки программирования семейства PGAS: Cray ChapelЛекция 12 (часть 1): Языки программирования семейства PGAS: Cray Chapel
Лекция 12 (часть 1): Языки программирования семейства PGAS: Cray ChapelMikhail Kurnosov
 
Распространённые ошибки оценки производительности .NET-приложений
Распространённые ошибки оценки производительности .NET-приложенийРаспространённые ошибки оценки производительности .NET-приложений
Распространённые ошибки оценки производительности .NET-приложенийAndrey Akinshin
 
Всё о статическом анализе кода для Java программиста
Всё о статическом анализе кода для Java программистаВсё о статическом анализе кода для Java программиста
Всё о статическом анализе кода для Java программистаAndrey Karpov
 
Статический анализ Си++ кода
Статический анализ Си++ кодаСтатический анализ Си++ кода
Статический анализ Си++ кодаTatyanazaxarova
 
ADD 2011: Статический анализ Си++ кода
ADD 2011: Статический анализ Си++ кодаADD 2011: Статический анализ Си++ кода
ADD 2011: Статический анализ Си++ кодаAndrey Karpov
 
Когда в C# не хватает C++ . Часть 3.
Когда в C# не хватает C++. Часть 3. Когда в C# не хватает C++. Часть 3.
Когда в C# не хватает C++ . Часть 3. Mikhail Shcherbakov
 
Статический анализ: ищем ошибки... и уязвимости?
Статический анализ: ищем ошибки... и уязвимости?Статический анализ: ищем ошибки... и уязвимости?
Статический анализ: ищем ошибки... и уязвимости?Andrey Karpov
 

Similaire à 20130429 dynamic c_c++_program_analysis-alexey_samsonov (20)

Семинар 5. Многопоточное программирование на OpenMP (часть 5)
Семинар 5. Многопоточное программирование на OpenMP (часть 5)Семинар 5. Многопоточное программирование на OpenMP (часть 5)
Семинар 5. Многопоточное программирование на OpenMP (часть 5)
 
Address Sanitizer или как сделать программы на c/с++ надежнее и безопаснее (К...
Address Sanitizer или как сделать программы на c/с++ надежнее и безопаснее (К...Address Sanitizer или как сделать программы на c/с++ надежнее и безопаснее (К...
Address Sanitizer или как сделать программы на c/с++ надежнее и безопаснее (К...
 
static - defcon russia 20
static  - defcon russia 20static  - defcon russia 20
static - defcon russia 20
 
200 open source проектов спустя: опыт статического анализа исходного кода
200 open source проектов спустя:опыт статического анализа исходного кода200 open source проектов спустя:опыт статического анализа исходного кода
200 open source проектов спустя: опыт статического анализа исходного кода
 
Принципы работы статического анализатора кода PVS-Studio
Принципы работы статического анализатора кода PVS-StudioПринципы работы статического анализатора кода PVS-Studio
Принципы работы статического анализатора кода PVS-Studio
 
Статический анализ кода: Что? Как? Зачем?
Статический анализ кода: Что? Как? Зачем?Статический анализ кода: Что? Как? Зачем?
Статический анализ кода: Что? Как? Зачем?
 
Android: Как написать приложение, которое не тормозит
Android: Как  написать приложение, которое не тормозитAndroid: Как  написать приложение, которое не тормозит
Android: Как написать приложение, которое не тормозит
 
11 встреча — Введение в GPGPU (А. Свириденков)
11 встреча — Введение в GPGPU (А. Свириденков)11 встреча — Введение в GPGPU (А. Свириденков)
11 встреча — Введение в GPGPU (А. Свириденков)
 
Лекция 8. Intel Threading Building Blocks
Лекция 8. Intel Threading Building BlocksЛекция 8. Intel Threading Building Blocks
Лекция 8. Intel Threading Building Blocks
 
Tech Talks @NSU: Как приручить дракона: введение в LLVM
Tech Talks @NSU: Как приручить дракона: введение в LLVMTech Talks @NSU: Как приручить дракона: введение в LLVM
Tech Talks @NSU: Как приручить дракона: введение в LLVM
 
Как приручить дракона: введение в LLVM
Как приручить дракона: введение в LLVMКак приручить дракона: введение в LLVM
Как приручить дракона: введение в LLVM
 
статический анализ кода
статический анализ кодастатический анализ кода
статический анализ кода
 
Статический анализ кода
Статический анализ кода Статический анализ кода
Статический анализ кода
 
Лекция 12 (часть 1): Языки программирования семейства PGAS: Cray Chapel
Лекция 12 (часть 1): Языки программирования семейства PGAS: Cray ChapelЛекция 12 (часть 1): Языки программирования семейства PGAS: Cray Chapel
Лекция 12 (часть 1): Языки программирования семейства PGAS: Cray Chapel
 
Распространённые ошибки оценки производительности .NET-приложений
Распространённые ошибки оценки производительности .NET-приложенийРаспространённые ошибки оценки производительности .NET-приложений
Распространённые ошибки оценки производительности .NET-приложений
 
Всё о статическом анализе кода для Java программиста
Всё о статическом анализе кода для Java программистаВсё о статическом анализе кода для Java программиста
Всё о статическом анализе кода для Java программиста
 
Статический анализ Си++ кода
Статический анализ Си++ кодаСтатический анализ Си++ кода
Статический анализ Си++ кода
 
ADD 2011: Статический анализ Си++ кода
ADD 2011: Статический анализ Си++ кодаADD 2011: Статический анализ Си++ кода
ADD 2011: Статический анализ Си++ кода
 
Когда в C# не хватает C++ . Часть 3.
Когда в C# не хватает C++. Часть 3. Когда в C# не хватает C++. Часть 3.
Когда в C# не хватает C++ . Часть 3.
 
Статический анализ: ищем ошибки... и уязвимости?
Статический анализ: ищем ошибки... и уязвимости?Статический анализ: ищем ошибки... и уязвимости?
Статический анализ: ищем ошибки... и уязвимости?
 

Plus de Computer Science Club

20140531 serebryany lecture01_fantastic_cpp_bugs
20140531 serebryany lecture01_fantastic_cpp_bugs20140531 serebryany lecture01_fantastic_cpp_bugs
20140531 serebryany lecture01_fantastic_cpp_bugsComputer Science Club
 
20140531 serebryany lecture02_find_scary_cpp_bugs
20140531 serebryany lecture02_find_scary_cpp_bugs20140531 serebryany lecture02_find_scary_cpp_bugs
20140531 serebryany lecture02_find_scary_cpp_bugsComputer Science Club
 
20140531 serebryany lecture01_fantastic_cpp_bugs
20140531 serebryany lecture01_fantastic_cpp_bugs20140531 serebryany lecture01_fantastic_cpp_bugs
20140531 serebryany lecture01_fantastic_cpp_bugsComputer Science Club
 
20140511 parallel programming_kalishenko_lecture12
20140511 parallel programming_kalishenko_lecture1220140511 parallel programming_kalishenko_lecture12
20140511 parallel programming_kalishenko_lecture12Computer Science Club
 
20140427 parallel programming_zlobin_lecture11
20140427 parallel programming_zlobin_lecture1120140427 parallel programming_zlobin_lecture11
20140427 parallel programming_zlobin_lecture11Computer Science Club
 
20140420 parallel programming_kalishenko_lecture10
20140420 parallel programming_kalishenko_lecture1020140420 parallel programming_kalishenko_lecture10
20140420 parallel programming_kalishenko_lecture10Computer Science Club
 
20140413 parallel programming_kalishenko_lecture09
20140413 parallel programming_kalishenko_lecture0920140413 parallel programming_kalishenko_lecture09
20140413 parallel programming_kalishenko_lecture09Computer Science Club
 
20140329 graph drawing_dainiak_lecture02
20140329 graph drawing_dainiak_lecture0220140329 graph drawing_dainiak_lecture02
20140329 graph drawing_dainiak_lecture02Computer Science Club
 
20140329 graph drawing_dainiak_lecture01
20140329 graph drawing_dainiak_lecture0120140329 graph drawing_dainiak_lecture01
20140329 graph drawing_dainiak_lecture01Computer Science Club
 
20140310 parallel programming_kalishenko_lecture03-04
20140310 parallel programming_kalishenko_lecture03-0420140310 parallel programming_kalishenko_lecture03-04
20140310 parallel programming_kalishenko_lecture03-04Computer Science Club
 
20140216 parallel programming_kalishenko_lecture01
20140216 parallel programming_kalishenko_lecture0120140216 parallel programming_kalishenko_lecture01
20140216 parallel programming_kalishenko_lecture01Computer Science Club
 

Plus de Computer Science Club (20)

20141223 kuznetsov distributed
20141223 kuznetsov distributed20141223 kuznetsov distributed
20141223 kuznetsov distributed
 
Computer Vision
Computer VisionComputer Vision
Computer Vision
 
20140531 serebryany lecture01_fantastic_cpp_bugs
20140531 serebryany lecture01_fantastic_cpp_bugs20140531 serebryany lecture01_fantastic_cpp_bugs
20140531 serebryany lecture01_fantastic_cpp_bugs
 
20140531 serebryany lecture02_find_scary_cpp_bugs
20140531 serebryany lecture02_find_scary_cpp_bugs20140531 serebryany lecture02_find_scary_cpp_bugs
20140531 serebryany lecture02_find_scary_cpp_bugs
 
20140531 serebryany lecture01_fantastic_cpp_bugs
20140531 serebryany lecture01_fantastic_cpp_bugs20140531 serebryany lecture01_fantastic_cpp_bugs
20140531 serebryany lecture01_fantastic_cpp_bugs
 
20140511 parallel programming_kalishenko_lecture12
20140511 parallel programming_kalishenko_lecture1220140511 parallel programming_kalishenko_lecture12
20140511 parallel programming_kalishenko_lecture12
 
20140427 parallel programming_zlobin_lecture11
20140427 parallel programming_zlobin_lecture1120140427 parallel programming_zlobin_lecture11
20140427 parallel programming_zlobin_lecture11
 
20140420 parallel programming_kalishenko_lecture10
20140420 parallel programming_kalishenko_lecture1020140420 parallel programming_kalishenko_lecture10
20140420 parallel programming_kalishenko_lecture10
 
20140413 parallel programming_kalishenko_lecture09
20140413 parallel programming_kalishenko_lecture0920140413 parallel programming_kalishenko_lecture09
20140413 parallel programming_kalishenko_lecture09
 
20140329 graph drawing_dainiak_lecture02
20140329 graph drawing_dainiak_lecture0220140329 graph drawing_dainiak_lecture02
20140329 graph drawing_dainiak_lecture02
 
20140329 graph drawing_dainiak_lecture01
20140329 graph drawing_dainiak_lecture0120140329 graph drawing_dainiak_lecture01
20140329 graph drawing_dainiak_lecture01
 
20140310 parallel programming_kalishenko_lecture03-04
20140310 parallel programming_kalishenko_lecture03-0420140310 parallel programming_kalishenko_lecture03-04
20140310 parallel programming_kalishenko_lecture03-04
 
20140223-SuffixTrees-lecture01-03
20140223-SuffixTrees-lecture01-0320140223-SuffixTrees-lecture01-03
20140223-SuffixTrees-lecture01-03
 
20140216 parallel programming_kalishenko_lecture01
20140216 parallel programming_kalishenko_lecture0120140216 parallel programming_kalishenko_lecture01
20140216 parallel programming_kalishenko_lecture01
 
20131106 h10 lecture6_matiyasevich
20131106 h10 lecture6_matiyasevich20131106 h10 lecture6_matiyasevich
20131106 h10 lecture6_matiyasevich
 
20131027 h10 lecture5_matiyasevich
20131027 h10 lecture5_matiyasevich20131027 h10 lecture5_matiyasevich
20131027 h10 lecture5_matiyasevich
 
20131027 h10 lecture5_matiyasevich
20131027 h10 lecture5_matiyasevich20131027 h10 lecture5_matiyasevich
20131027 h10 lecture5_matiyasevich
 
20131013 h10 lecture4_matiyasevich
20131013 h10 lecture4_matiyasevich20131013 h10 lecture4_matiyasevich
20131013 h10 lecture4_matiyasevich
 
20131006 h10 lecture3_matiyasevich
20131006 h10 lecture3_matiyasevich20131006 h10 lecture3_matiyasevich
20131006 h10 lecture3_matiyasevich
 
20131006 h10 lecture3_matiyasevich
20131006 h10 lecture3_matiyasevich20131006 h10 lecture3_matiyasevich
20131006 h10 lecture3_matiyasevich
 

20130429 dynamic c_c++_program_analysis-alexey_samsonov

  • 1. Динамический анализ программ на C++ Алексей Самсонов, Google Екатеринбург, УрФУ, 29.04.2013
  • 2. Команда (Google RU-MSK) Константин Серебряный (TL) Дмитрий Вьюков Тимур Исходжанов Сергей Матвеев Александр Потапенко Алексей Самсонов Евгений Степанов
  • 3. Содержание Часть 1 ● Ошибки работы с памятью ● AddressSanitizer Часть 2 ● Гонки ● ThreadSanitizer
  • 4. В мире много кода на C и C++ ● Операционные системы ● Браузеры (Chromium, Firefox, Safari) ● Виртуальные машины (Java) ● Базы данных (MySQL) ● Backend веб-сервисов (поиск) ● Веб-серверы (Apache, nginx)
  • 5. Ошибки работы с памятью в C/C++ ● Кодеки и рендереры (ffmpeg, pdf) ● Использование освобождённой памяти (use-after-free) ● Использование неинициализированной памяти (uninitialized-memory-read) ● Утечки памяти (memory leaks) ● Неверный порядок инициализации/уничтожения глобальных объектов
  • 6. Ошибки работы с памятью в C/C++ ● Выход за границы буфера (out-of-bound access) ● Использование освобождённой память (use-after-free) ● Использование неинициализированной памяти (uninitialized-memory-read) ● Утечки памяти (memory leaks) ● Неверный порядок инициализации/уничтожения глобальных объектов
  • 7. Выход за границы буфера (стек) void authorize() { ... char username[128]; gets(username); // 128 bytes should be // enough for everyone. ... }
  • 8. Использование освобожденной памяти ~UserTable() { ... delete all_users; LOG() << "Deleted " << all_users->size() << " users!"; } Можно ли сделать этот код ещё хуже?
  • 10. Всегда в моде: racy use-after-free Поток 1 void DeleteEntries() { have_entries = false; delete entries; } Поток 2 Entry *GetEntry(int i) { if (have_entries) return entries[i]; return 0; }
  • 11. Инструменты для поиска ошибок ● Valgrind/Memcheck ● DynamoRIO/Dr. Memory ● Purify ● Insure++ ● Mudflap ● Electric Fence / Page Heap / Guard Malloc Проблемы: ● Замедление программы (в 10 и более раз) ● Поиск ошибок только для динамически выделенной памяти (heap)
  • 12. Статический анализ программ ● Формальная верификация? ● Clang Static Analyzer? Проблемы: ● Баланс между эффективностью и полезностью ● Баланс между false negative и false positive
  • 13. Есть ли в программе ошибка? int array[10] = {...}; int main(int argc, char *argv[]) { return array[2 + argc]; }
  • 14.
  • 15. Пример отчёта об ошибке (1) int global_array[100] = {-1}; int main(int argc, char **argv) { return global_array[argc + 100]; } ==10538== ERROR: AddressSanitizer global-buffer-overflow READ of size 4 at 0x000000415354 thread T0 #0 0x402481 in main a.cc:3 <...> 0x000000415354 is located 4 bytes to the right of global variable 'global_array' (0x4151c0) of size 400
  • 16. Пример отчёта об ошибке (2) int main(int argc, char **argv) { int stack_array[100]; stack_array[1] = 0; return stack_array[argc + 100]; } ==10589== ERROR: AddressSanitizer stack-buffer-overflow READ of size 4 at 0x7f5620d981b4 thread T0 #0 0x4024e8 in main a.cc:4 Address 0x7f5620d981b4 is located at offset 436 in frame <main> of T0's stack: This frame has 1 object(s): [32, 432) 'stack_array'
  • 17. Пример отчёта об ошибке (3) int main(int argc, char **argv) { int *array = new int[100]; int res = array[argc + 100]; delete [] array; return res; } ==10565== ERROR: AddressSanitizer heap-buffer-overflow READ of size 4 at 0x7fe4b0c76214 thread T0 #0 0x40246f in main a.cc:3 0x7fe4b0c76214 is located 4 bytes to the right of 400- byte region [0x7fe..., 0x7fe...) allocated by thread T0 here: #0 0x402c36 in operator new[](unsigned long) #1 0x402422 in main a.cc:2
  • 18. Пример отчёта об ошибке (4) int main(int argc, char **argv) { int *array = new int[100]; delete [] array; return array[argc]; } ==30226== ERROR: AddressSanitizer heap-use-after-free READ of size 4 at 0x7faa07fce084 thread T0 #0 0x40433c in main a.cc:4 0x7faa07fce084 is located 4 bytes inside of 400-byte region freed by thread T0 here: #0 0x4058fd in operator delete[](void*) #1 0x404303 in main a.cc:3 previously allocated by thread T0 here: #0 0x405579 in operator new[](unsigned long) #1 0x4042f3 in main a.cc:2
  • 19.
  • 20. Что такое AddressSanitizer? ● Компиляторная инструментация ○ Проверка всех обращений к памяти ○ Добавление редзон("redzones") вокруг глобальных и локальных переменных ● Runtime-библиотека ○ Аллокатор (выделение/освобождение памяти) ○ Отслеживание всех потоков ○ Печать отчётов об ошибках ○ Обёртки функций из стандартной библиотеки
  • 21. Теневой байт (shadow byte) Если адреса всех переменных кратны 8, то у любых выровненных восьми байт есть 9 состояний: 0 7 6 5 4 3 2 1 -1
  • 22. Тень адресного пространства (*) Приложение 0xFFFFFFFF 0x20000000 Тень 0x1FFFFFFF 0x04000000 Mprotect 0x03FFFFF 0x0000000
  • 23. Инструментация доступа к памяти int *a = ...; *a = ...; char *shadow = a >> 3; if (*shadow != 0 && *shadow < (a&7) + 4) ReportError(a); *a = ...;
  • 24. Инструментация стека void foo() { char a[328]; <------------- CODE -------------> }
  • 25. Инструментация стека void foo() { char redzone1[32]; // 32-byte aligned char a[328]; char redzone2[24]; char redzone3[32]; int *shadow = (&rz1 >> 3); shadow[0] = 0xffffffff; // poison rz1 shadow[11] = 0xffffff00; // poison rz2 shadow[12] = 0xffffffff; // poison rz3 <------------- CODE -------------> shadow[0] = shadow[11] = shadow[12] = 0; }
  • 26. Инструментация глобальных объектов int global; struct { int original; char redzone[60]; } global; // 32-byte aligned
  • 27. LLVM спешит на помощь!
  • 28. Интеграция в LLVM ● Clang (или другой фронтенд) генерирует промежуточное представление программы; ● ASan добавляет инструментацию; ● Бэкенд оптимизирует код и генерирует объектный файл; ● Исполняемый файл линкуется с runtime- библиотекой.
  • 29. Runtime-библиотека ● Аллокатор ○ Добавление редзон вокруг блоков динамически выделенной памяти ○ Карантин для освобождённой памяти ○ Хранение стека вызовов для каждой аллокации ● Печать отчётов об ошибках ● Перехват библиотечных функций char bad_string[2] = {'h', 'i'}; int len = strlen(bad_string);
  • 30. Производительность ● Замедление программы: 2x ● Использование памяти: 1,5-3x ● "Just works" для большинства тестов и реальных программ ● Незначительное замедление для GUI- программ (Chromium+ASan работает без проблем)
  • 31. Трофеи 1000+ найденных ошибок повсюду: ● Chromium, Firefox, Safari ● Сервисы Google ● Perl, PHP, MySQL, ffmpeg, webrtc, vim ● LLVM, GCC Google заплатил $130000+ внешним исследователям за security-ошибки, найденные с помощью AddressSanitizer.
  • 32. Что будет дальше? ● Поиск других видов ошибок (в ближайшее время: поиск утечек памяти) ● Поиск ошибок в системных и прекомпилированных библиотеках ● AddressSanitizer для ядра Linux ● AddressSanitizer для Windows (нужен компилятор).
  • 33. Попробуйте AddressSanitizer! ● LLVM/Clang 3.1+ clang++ -fsanitize=address a.cc ● GCC 4.8+ g++ -fsanitize=address a.cc ● Платформы: Linux, Mac OS X, Android code.google.com/p/address-sanitizer
  • 35. Что такое гонка? Гонка происходит, когда два потока одновременно обращаются к одной и той же переменной, и хотя бы одно из обращений является записью. Если в программе на C++ могут возникнуть гонки, её поведение не определено. Компилятор имеет право считать, что в программе нет гонок.
  • 36. Что напечатает этот код? Поток 1 cout << x << "n"; x = 1; cout << y << "n"; Поток 2 cout << y << "n"; y = 1; cout << x << "n"; int x = 0, y = 0;
  • 37. "Безвредные" гонки ● Синхронизация замедляет программу. ● Может возникнуть желание допустить гонки на "не очень важных" данных. ● Не нужно этого делать. В C++ не может быть "безвредных" (benign) гонок. H-J. Boehm "How to miscompile programs with "benign" data races" D. Vyukov "Benign data races: what could possibly go wrong?"
  • 38.
  • 39. Пример "безвредной гонки" long long get_value() { return value; } void set_value( long long x) { value = x; } Является ли 64-битное чтение / запись атомарной операцией?
  • 40. Пример "безвредной гонки" (2) ... int my_counter = counter; // read global if (my_counter > my_old_counter) { my_action = print_stats; } ... if (my_counter > my_old_counter) { run_action(my_action); }
  • 41. Пример "безвредной гонки" (3) my_action = launch_nuclear_rocket; ... int my_counter = counter; // read global if (my_counter > my_old_counter) { my_action = print_stats; } ... my_counter = counter; if (my_counter > my_old_counter) { run_action(my_action); }
  • 42. А как же настоящие гонки?
  • 43. Метод-лжец // Returns the user with a given ID User& getUser(int id) { MutexLock(&mutex); CHECK(0 <= id && id < users.size()); return users[id]; }
  • 44. Метод-лжец // Returns the user with a given ID User& getUser(int id) { MutexLock(&mutex); CHECK(0 <= id && id < users.size()); return users[id]; }
  • 45. Что не так с этим кодом? class AbstractAction { public: AbstractAction(Executor *executor) { executor->add(this); ... } ... }
  • 46. Что не так с этим кодом? class AbstractAction { public: AbstractAction(Executor *executor) { executor->add(this); ... } ... virtual void Run() = 0; }
  • 47. Гонка на vptr class AbstractAction { public: AbstractAction(Executor *executor) { executor->add(this); // переключение контекста } ... virtual void Run() = 0; } Pure virtual call!
  • 48. ThreadSanitizer спешит на помощь WARNING: ThreadSanitizer: data race on vptr (ctor/dtor vs virtual call) Read of size 8 at 0x7fff103327f0 by thread T3: #0 ExecutorThread::RunAction() executor.cc:1112 #1 ExecutorThread::Start() executor.cc:1283 Previous write of size 8 at 0x7fff103327f0 by main thread: #0 MyAction::MyAction()vptr_race.cc:48 #1 main vptr_race.cc:59 Location is stack of main thread.
  • 49. Что такое ThreadSanitizer? ● Компиляторная инструментация ○ Проверка всех обращений к памяти ○ Отслеживание событий: вход/выход в функцию, обновление vptr, атомарные операции ● Runtime-библиотека ○ Аллокатор (выделение/освобождение памяти) ○ Отслеживание всех потоков ○ Печать отчётов об ошибках ○ Обёртки функций из стандартной библиотеки ○ Поддержка синхронизационных примитивов
  • 50. Инструментация (1) int *p = ...; *p = 42; int *p = ...; __tsan_write4(p); *p = 42;
  • 51. Инструментация (2) void foo() { ... } void foo() { __tsan_func_entry( __builtin_return_address(0)); ... __tsan_func_exit(); }
  • 52. Инструментация (3) A::~A() { // this->vptr = A::vptr; } A::~A() { __tsan_vptr_update(&this->vptr, A::vptr); // this->vptr = A::vptr; }
  • 53. Runtime-библиотека ● Проверка всех доступов в память ● Выделение/освобождение памяти ● Поддержка синхронизации (мьютексы, атомарные операции) ● Перехват функций работы с потоками (libpthread) ● Перехват функций из стандартной библиотеки ● Печать отчётов об ошибках
  • 54. Абстрактное время потока Увеличивается после каждого события: void foo() { // time = 1 Lock(&mutex); // time = 2 x = 1; // time = 3 Unlock(&mutex); // time = 4 } // time = 5
  • 55. Векторные часы (vector clock) VC[1..N], где VC[i] - время i-го потока. Векторные часы есть у каждого потока: VC[1..N], где VC[i] - время i-го потока в момент последней синхронизации с ним. Векторные часы есть у каждого мьютекса: VC[1..N], VC[i] - время i-го потока, когда он в последний раз отпустил мьютекс.
  • 56. Обновление векторных часов Доступ к памяти в потоке T: T->VC[T->id]++;
  • 57. Обновление векторных часов (2) Взятие мьютекса M в потоке T: для всех i: T->VC[i] = max(T->VC[i], M->VC[i]); Освобождение мьютекса M в потоке T: для всех i: M->VC[i] = max(M->VC[i], T->VC[i]);
  • 58. Как кодировать обращение к памяти? Обращение к выровненным 8 байтам адресного пространства кодируется через: ● ID потока (TID) ● Время этого потока (TS) ● позиция (0..7) и размер (1,2,4,8) обращения ● является ли доступ чтением или записью? Вся эта информация помещается в 8 байт.
  • 59. Пример обращений к памяти Приложение Тень
  • 60. Запись из потока T1 Приложение Тень T1 TS1 W 0:2
  • 61. Чтение из потока T2 Приложение Тень T1 TS1 W 0:2 T2 TS2 4:4 R
  • 62. Чтение из потока T3 Приложение Тень T1 TS1 W 0:2 T2 TS2 4:4 R T3 TS3 0:4 R
  • 63. Гонка? Тень T1 TS1 W 0:2 T2 TS2 4:4 R T3 TS3 0:4 R ● Доступы пересекаются? ● Разные потоки? ● Хотя бы одно из обращений - запись? ● Есть ли синхронизация? Гонка, если T3->VC[T1] < TS1
  • 64. Как узнать стек вызовов для каждого обращения к памяти? ● Циклическая очередь всех событий в каждом потоке: ○ доступ к памяти ○ вход/выход из функции ○ взятие/освобождение мьютекса ● "Повторение" событий перед печатью отчёта: ○ Через некоторое время события "забываются" ○ Неограниченный размер стека вызовов в отчёте ○ Отчёт содержит множество мьютексов, взятых в каждом потоке.
  • 65. Результаты ● Замедление программы: 4-10x (в 10 раз быстрее аналогов). ● Использование памяти: 5-8x ● 600+ найденных ошибок ● Работает для больших серверных приложений
  • 66. Что будет дальше? ● Портирование на другие системы (сейчас - только 64-битный Linux). ● Поиск ошибок в системных и прекомпилированных библиотеках ● Больше оптимизаций, больше пользователей ● Поиск гонок в коде на Java
  • 67. Попробуйте ThreadSanitizer! ● LLVM/Clang 3.2+ clang++ -fsanitize=thread a.cc ● GCC 4.8+ g++ -fsanitize=thread a.cc ● Go go build -race code.google.com/p/thread-sanitizer