Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.
Динамический анализпрограмм на C++Алексей Самсонов, GoogleЕкатеринбург, УрФУ, 29.04.2013
Команда (Google RU-MSK)Константин Серебряный (TL)Дмитрий ВьюковТимур ИсходжановСергей МатвеевАлександр ПотапенкоАлексей Са...
СодержаниеЧасть 1● Ошибки работы с памятью● AddressSanitizerЧасть 2● Гонки● ThreadSanitizer
В мире много кода на C и C++● Операционные системы● Браузеры (Chromium, Firefox, Safari)● Виртуальные машины (Java)● Базы ...
Ошибки работы с памятью в C/C++● Кодеки и рендереры (ffmpeg, pdf)● Использование освобождённой памяти(use-after-free)● Исп...
Ошибки работы с памятью в C/C++● Выход за границы буфера (out-of-boundaccess)● Использование освобождённой память(use-afte...
Выход за границы буфера (стек)void authorize() {...char username[128];gets(username); // 128 bytes should be// enough for ...
Использование освобожденнойпамяти~UserTable() {...delete all_users;LOG() << "Deleted " << all_users->size()<< " users!";}М...
Использование освобожденнойпамяти~UserTable() {...delete all_users;RunAction(all_users->action_on_delete);}
Всегда в моде: racy use-after-freeПоток 1void DeleteEntries() {have_entries = false;delete entries;}Поток 2Entry *GetEntry...
Инструменты для поиска ошибок● Valgrind/Memcheck● DynamoRIO/Dr. Memory● Purify● Insure++● Mudflap● Electric Fence / Page H...
Статический анализ программ● Формальная верификация?● Clang Static Analyzer?Проблемы:● Баланс между эффективностью иполезн...
Есть ли в программе ошибка?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];}...
Пример отчёта об ошибке (2)int main(int argc, char **argv) {int stack_array[100];stack_array[1] = 0;return stack_array[arg...
Пример отчёта об ошибке (3)int main(int argc, char **argv) {int *array = new int[100];int res = array[argc + 100];delete [...
Пример отчёта об ошибке (4)int main(int argc, char **argv) {int *array = new int[100];delete [] array;return array[argc];}...
Что такое AddressSanitizer?● Компиляторная инструментация○ Проверка всех обращений к памяти○ Добавление редзон("redzones")...
Теневой байт (shadow byte)Если адреса всех переменных кратны 8, то у любыхвыровненных восьми байт есть 9 состояний:0765432...
Тень адресного пространства (*)Приложение0xFFFFFFFF0x20000000Тень0x1FFFFFFF0x04000000Mprotect0x03FFFFF0x0000000
Инструментация доступа к памятиint *a = ...;*a = ...;char *shadow = a >> 3;if (*shadow != 0 &&*shadow < (a&7) + 4)ReportEr...
Инструментация стекаvoid foo() {char a[328];<------------- CODE ------------->}
Инструментация стекаvoid foo() {char redzone1[32]; // 32-byte alignedchar a[328];char redzone2[24];char redzone3[32];int *...
Инструментация глобальныхобъектовint global;struct {int original;char redzone[60];} global; // 32-byte aligned
LLVM спешит на помощь!
Интеграция в LLVM● Clang (или другой фронтенд) генерируетпромежуточное представлениепрограммы;● ASan добавляет инструмента...
Runtime-библиотека● Аллокатор○ Добавление редзон вокруг блоков динамическивыделенной памяти○ Карантин для освобождённой па...
Производительность● Замедление программы: 2x● Использование памяти: 1,5-3x● "Just works" для большинства тестов иреальных ...
Трофеи1000+ найденных ошибок повсюду:● Chromium, Firefox, Safari● Сервисы Google● Perl, PHP, MySQL, ffmpeg, webrtc, vim● L...
Что будет дальше?● Поиск других видов ошибок (в ближайшеевремя: поиск утечек памяти)● Поиск ошибок в системных ипрекомпили...
Попробуйте AddressSanitizer!● LLVM/Clang 3.1+clang++ -fsanitize=address a.cc● GCC 4.8+g++ -fsanitize=address a.cc● Платфор...
Гонки (data races)
Что такое гонка?Гонка происходит, когда два потока одновременнообращаются к одной и той же переменной, и хотя быодно из об...
Что напечатает этот код?Поток 1cout << x << "n";x = 1;cout << y << "n";Поток 2cout << y << "n";y = 1;cout << x << "n";int ...
"Безвредные" гонки● Синхронизация замедляет программу.● Может возникнуть желание допуститьгонки на "не очень важных" данны...
Пример "безвредной гонки"long longget_value() {return value;}void set_value(long long x) {value = x;}Является ли 64-битное...
Пример "безвредной гонки" (2)...int my_counter = counter; // read globalif (my_counter > my_old_counter) {my_action = prin...
Пример "безвредной гонки" (3)my_action = launch_nuclear_rocket;...int my_counter = counter; // read globalif (my_counter >...
А как же настоящие гонки?
Метод-лжец// Returns the user with a given IDUser& getUser(int id) {MutexLock(&mutex);CHECK(0 <= id && id < users.size());...
Метод-лжец// Returns the user with a given IDUser& getUser(int id) {MutexLock(&mutex);CHECK(0 <= id && id < users.size());...
Что не так с этим кодом?class AbstractAction {public:AbstractAction(Executor *executor) {executor->add(this);...}...}
Что не так с этим кодом?class AbstractAction {public:AbstractAction(Executor *executor) {executor->add(this);...}...virtua...
Гонка на vptrclass AbstractAction {public:AbstractAction(Executor *executor) {executor->add(this);// переключение контекст...
ThreadSanitizer спешит на помощьWARNING: ThreadSanitizer: data race on vptr (ctor/dtor vsvirtual call)Read of size 8 at 0x...
Что такое ThreadSanitizer?● Компиляторная инструментация○ Проверка всех обращений к памяти○ Отслеживание событий: вход/вых...
Инструментация (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::v...
Runtime-библиотека● Проверка всех доступов в память● Выделение/освобождение памяти● Поддержка синхронизации (мьютексы,атом...
Абстрактное время потокаУвеличивается после каждого события:void foo() { // time = 1Lock(&mutex); // time = 2x = 1; // tim...
Векторные часы (vector clock)VC[1..N], где VC[i] - время i-го потока.Векторные часы есть у каждого потока:VC[1..N], где VC...
Обновление векторных часовДоступ к памяти в потоке T:T->VC[T->id]++;
Обновление векторных часов (2)Взятие мьютекса M в потоке T:для всех i:T->VC[i] = max(T->VC[i], M->VC[i]);Освобождение мьют...
Как кодировать обращение кпамяти?Обращение к выровненным 8 байтамадресного пространства кодируется через:● ID потока (TID)...
Пример обращений к памятиПриложение Тень
Запись из потока T1Приложение ТеньT1TS1W0:2
Чтение из потока T2Приложение ТеньT1TS1W0:2T2TS24:4R
Чтение из потока T3Приложение ТеньT1TS1W0:2T2TS24:4RT3TS30:4R
Гонка?ТеньT1TS1W0:2T2TS24:4RT3TS30:4R● Доступыпересекаются?● Разные потоки?● Хотя бы одно изобращений -запись?● Есть лисин...
Как узнать стек вызовов длякаждого обращения к памяти?● Циклическая очередь всех событий вкаждом потоке:○ доступ к памяти○...
Результаты● Замедление программы: 4-10x (в 10 разбыстрее аналогов).● Использование памяти: 5-8x● 600+ найденных ошибок● Ра...
Что будет дальше?● Портирование на другие системы (сейчас- только 64-битный Linux).● Поиск ошибок в системных ипрекомпилир...
Попробуйте ThreadSanitizer!● LLVM/Clang 3.2+clang++ -fsanitize=thread a.cc● GCC 4.8+g++ -fsanitize=thread a.cc● Gogo build...
20130429 dynamic c_c++_program_analysis-alexey_samsonov
20130429 dynamic c_c++_program_analysis-alexey_samsonov
20130429 dynamic c_c++_program_analysis-alexey_samsonov
Upcoming SlideShare
Loading in …5
×

20130429 dynamic c_c++_program_analysis-alexey_samsonov

1,182 views

Published on

  • Be the first to comment

  • Be the first to like this

20130429 dynamic c_c++_program_analysis-alexey_samsonov

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

×