# Санитайзеры

**Санитайзеры** – инструменты отладки, позволяющие проводить более продвинутые анализы во время исполнения программного обеспечения. Компилятор Clang (фронтенд LLVM) поддерживает шесть видов санитайзеров:

* [AddressSanitizer](https://clang.llvm.org/docs/AddressSanitizer.html) – детектор ошибок при работе с адресацией (выход за границы выделенной области памяти, стека, двойное высвобождение памяти и другое).
* [ThreadSanitizer](https://clang.llvm.org/docs/ThreadSanitizer.html) – детектор ошибок при взаимодействиями между потоками (data race).
* [UndefinedBehaviorSanitizer](https://clang.llvm.org/docs/UndefinedBehaviorSanitizer.html) – детектор специфических ошибок, чаще всего регламентированных в стандарте как [*Undefined Behavior*](https://en.cppreference.com/w/c/language/behavior).
* [MemorySanitizer](https://clang.llvm.org/docs/MemorySanitizer.html) – детектор чтения из неинициализированной области памяти.
* [LeakSanitizer](https://clang.llvm.org/docs/LeakSanitizer.html) – детектор утечки (не освобождаемой) памяти.
* [DataFlowSanitizer](https://clang.llvm.org/docs/DataFlowSanitizer.html) – обобщенный анализ потока данных.

Все виды детекторов [совместить нельзя](https://clang.llvm.org/docs/UsersManual.html#controlling-code-generation). Можете попробовать проанализировать код всеми видами санитайзеров, однако нас будет интересовать только: ASan, UBSan и LSan – почти всегда достаточный набор для диагностики кода.

Чтобы собрать программу с таким набором санитайзеров, необходимо установить флаг `-fsanitize` с желаемыми детекторами, и, обязательно, выбрать сборку под отладчиком:

{% code overflow="wrap" %}

```powershell
clang -O0 -g -fno-sanitize-recover=all -fsanitize=address,undefined,leak main.c -o main.exe
```

{% endcode %}

Примечание: на MacOS без leak – по документации, address уже включает обнаружение утечки памяти

<figure><img src="/files/Q09fG1O0gWWgJnTjKuHK" alt=""><figcaption><p>Обнаружение утечки памяти в простейшей программе</p></figcaption></figure>

При запуске программы автоматически запускаются следящие за ресурсами подпрограммы отладки, которые, в случае обнаружения ошибки в работе программы (например, выход за границы) или утечки памяти после завершения программы, выдают подробный лог ошибки.

## Настройка окружения

Ниже приведены (почти наверняка) рабочие инструкции для разных операционных систем.

### Windows

Возможности даже при большом желании использования интересных нам санитайзеров через легальные схемы на операционной системе Windows через нативный (то есть тот, который ожидается) `MSVC` или `clang-cl` **не получится**. Для решения этой проблемы предлагается два варианта: использование [*подсистемы Linux для Windows*](https://learn.microsoft.com/ru-ru/windows/wsl/about) (WSL, должна быть поддержка Hyper-V) и использование [*виртуальной машины VirtualBox*](https://www.virtualbox.org/) (медленнее, но никаких требований от вашего железа не требуется).

#### Нативный метод

Как уже сказано, на `MSVC` и `clang-cl` поддерживают только **AddressSanitizer**. Тем не менее, это может быть полезно, если у вас внезапная поломка программы на ровном месте. Для компиляции необходимо подать соответствующий флаг и [отладочную информацию](https://learn.microsoft.com/en-us/cpp/build/reference/z7-zi-zi-debug-information-format): рекомендуется использовать полную статистику, то есть, `/Z7`.

{% code overflow="wrap" %}

```cmd
cl.exe /Od /Z7 /fsanitize=address main.c
```

{% endcode %}

Более информации [здесь](https://learn.microsoft.com/en-us/cpp/sanitizers/asan?view=msvc-170).

#### WSL

В качестве дистрибутива рассмотрим самый простой и рекомендуемый для всех новичков в Линукс – [Ubuntu](https://ubuntu.com/).

1. Активируйте компоненты Windows.
   * Откройте *Панель управления* – *Все элементы панели управления* – *Программы и компоненты* – ***Включение и отключение компонентов Windows***.
   * В списке найдите пункт ***Подсистема Windows для Linux*** и убедитесь, что перед пунктом стоит галочка. В ином случае: поставьте, сохраните изменения и перезагрузите компьютер.
2. В Microsoft Store установите приложение [***Подсистема Windows для Linux***](https://learn.microsoft.com/ru-ru/windows/wsl/about).
3. Запустите терминал/командную строку (далее – терминал), введите следующее ниже и перезагрузите компьютер:

   ```powershell
   wsl.exe --update
   wsl.exe --set-default-version 2
   ```

   По пути домашнего каталога текущего пользователя должен появиться файл `.wslconfig`, в котором лежат основные глобальные настройки для WSL2. Содержимое `.wslconfig` предлагается установить следующим:

   ```config
   [wsl2]
   nestedVirtualization=true
   memory=2048MB
   processors=2
   ```

   Первые две строки должны быть по умолчанию после установки версии WSL на 2. Значение `memory` ограничивает подсистеме использование оперативной памяти, `processors`, соответственно, на количество процессоров.
4. Запустите терминал и установите ***Ubuntu 22.04.3 LTS*** с помощью следующей команды:

   ```cmd
   wsl.exe --install Ubuntu-22.04
   ```

   Альтернативный вариант: установить [приложение с Microsoft Store](https://apps.microsoft.com/detail/9pn20msr04dw).
5. Запустите дистрибутив (это можно сделать, введя в терминал `wsl`), проследуйте инструкциям установки. Введите в терминал WSL:

{% code overflow="wrap" lineNumbers="true" fullWidth="false" %}

```bash
   sudo apt-get update && sudo apt-get upgrade -y # обновление пакетов  
   sudo apt-get install build-essential libc++-dev libc++abi-dev binutils binutils-dev clang gdb pkg-config    
```

{% endcode %}

Альтернатива – программа [`valgrind`](https://valgrind.org/). Введите в терминал WSL:

Установка `valgrind`:

```bash
sudo apt-get install -y valgrind
```

Компиляция с `valgrind`:

```bash
clang -O0 -gdwarf-4 main.c -o main.exe      
```

Обратите внимание, здесь специально убираем санитайзеры, чтобы не смешать работу детекторов, и [поменяли флаг добавления отладочной информации](https://github.com/llvm/llvm-project/issues/56550).

Запуск с `valgrind`:

{% code overflow="wrap" %}

```bash
valgrind --tool=memcheck --gen-suppressions=all --leak-check=full --show-leak-kinds=all --track-origins=yes -s ./main.exe      
```

{% endcode %}

#### VirtualBox

Данная часть ничем не отличается от главы [про WSL](#wsl), кроме установки и настройки системы.

1. Скачайте и установите [VirtualBox](https://www.virtualbox.org/wiki/Download_Old_Builds_6_1) и образ диска [Ubuntu Server](https://ubuntu.com/download/server). Если хватает ресурсов, можно скачать пользовательскую версию [Ubuntu Desktop](https://ubuntu.com/desktop).
2. Установите операционную систему Ubuntu Server.

   1. Создайте новую машину, **`New`**.
      * В поле **Name** введите имя машины, например, *SanitizerRunner*.
      * В поле **Type** выберите тип `Linux`.
      * В поле **Version** выставите `Ubuntu (64-bit)` или `Ubuntu (32-bit)`.
   2. Далее нажимаете всё время `Next`. Из интересного стоит отметить количество места для операционной системы – хватает и 10 ГБ (утверждается, что можно поставить чуть поменьше). Также, по умолчанию, на ОС будет приходиться 2 ГБ оперативной памяти.
   3. Настройте виртуальную машину, **`Settings`**. В разделе *Storage*, в *Empty* нажмите на значок *диска* – *Choose a disk file* – выберите скачанный `.iso`.
   4. Запустите виртуальную машину, **`Start`**. В разделе *Guided storage configuration* рекомендуется убрать пункт `Set up this disk as an LVM group`.
   5. Во всех оставшихся разделах нажимаете всё время `Next`, создайте пользователя и ничего лишнего не выбирайте для экономия места и времени.

   В случае с Ubuntu Desktop потребуется 20 ГБ и 4 ГБ оперативной памяти (рекомендация), установка более очевидная из-за графического интерфейса. Рекомендуется в разделе *Updates and other software*:

   * Выбрать `Minimal installation`.
   * В пункте *Other options*: выбрать `Download updates while installing Ubuntu` и `Install third-party software for graphics and Wi-Fi hardware and additional media formats`.

   В дальнейшем все действия на серверной версии не будут отличаться от пользовательской.
3. Дальнейшие шаги ничем не отличаются от шага **5** из пункта про [WSL](#wsl).

Для более удобной работы с виртуальной машиной рекомендуется прочитать в Интернете про SSH подключения в локальной сети.

### Linux

Данная инструкция целиком и полностью копирует последовательность действий рассмотренных выше [WSL](#wsl) и [VirtualBox](#virtualbox). Обратите внимание, что в разных дистрибутивах названия тех или иных пакетов могут *отличаться*.

### MacOS

С MacOS как и в случае с Windows с санитайзерами всё довольно грустно и печально, если хочется компилировать с терминала. В качестве решений данной проблемы могут послужить:

[*Использование виртуальной машины*](https://mac.getutm.app/). В случае платформы ARM, в UTM выбираете пункт **emulate**. Если ваш Mac поддерживает VirtualBox и имеет возможность запустить виртуальную машину с образом Ubuntu, тогда вам следует обратиться к [этому пункту](#virtualbox).

*Нативные компиляторы и приложения*. В этом случае устанавливаете все необходимые для работы компилятора Clang через [пакетный менеджер `brew`](https://brew.sh/) компилируетесь через терминал (clang из Homebrew):

{% code overflow="wrap" %}

```bash
/path/to/homebrew/clang -O0 -g -fno-sanitize-recover=all -fsanitize=address,undefined main.c -o main.exe
```

{% endcode %}

и запускаетесь с:

```bash
ASAN_OPTIONS=verbosity=1:detect_leaks=1 ./main.exe
```

либо используйте [Xcode](https://developer.apple.com/xcode/) в качестве средства разработки и [запуска санитайзеров](https://developer.apple.com/documentation/xcode/diagnosing-memory-thread-and-crash-issues-early).


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://skkv-itmo.gitbook.io/c-cpp-cookies/code-analysis/sanitizer.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
