Как я должен использовать дезинфицирующее средство в clang?

Прошу прощения, если это концепция uber-easy, но мне трудно найти правильное мышление, чтобы правильно использовать дезинфицирующее средство, предоставленное clang.

float foo(float f) { return (f / 0); }

Я компилирую этот небольшой фрагмент с помощью

clang++ -fsanitize=float-divide-by-zero -std=c++11 -stdlib=libc++ -c source.cpp -o osan

и я также компилирую "нормальную" версию моего объекта без использования дезинфицирующего средства

clang++ -std=c++11 -stdlib=libc++ -c source.cpp -o onorm

Я ожидал некоторого подробного вывода или некоторой ошибки с консоли, но при проверке файла с помощью nm я нашел только 1 разницу

nm o* --demangle

onorm:
0000000000000000 T foo(float)

osan:
                 U __ubsan_handle_divrem_overflow
0000000000000000 T foo(float)

Таким образом, в санированной версии есть символ undefined с именем, которое напоминает дезинфицирующее средство, которое я использовал при компиляции; но все на самом деле "безмолвно" без вывода из интерфейса clang.

Как я должен использовать дезинфицирующее средство и какой правильный рабочий процесс? Какова точка этого символа undefined?

Ответ 1

Символ undefined - это функция, которая реализует проверку sanitizer. Если вы посмотрите на сгенерированный код:

Нет дезинфицирующего средства:

_Z3foof:                                # @_Z3foof
    .cfi_startproc
# BB#0:
    xorps   %xmm1, %xmm1
    divss   %xmm1, %xmm0
    ret

С дезинфицирующим средством:

_Z3foof:                                # @_Z3foof
    .cfi_startproc
    .long   1413876459              # 0x54460aeb
    .quad   _ZTIFffE
# BB#0:
    pushq   %rax
.Ltmp1:
    .cfi_def_cfa_offset 16
    movss   %xmm0, 4(%rsp)          # 4-byte Spill
    movd    %xmm0, %esi
    movl    $__unnamed_1, %edi
    xorl    %edx, %edx
    callq   __ubsan_handle_divrem_overflow
    xorps   %xmm1, %xmm1
    movss   4(%rsp), %xmm0          # 4-byte Reload
    divss   %xmm1, %xmm0
    popq    %rax
    ret

Вы видите, что он добавил код для проверки с помощью этой функции.

Компилятор должен автоматически ссылаться в соответствующей библиотеке sanitizer, а затем для меня следующая полная программа:

float foo(float f) { return (f / 0); }
int main() {
    foo(1.0f);
}

Производит следующий вывод при выполнении:

main.cpp:1:32: runtime error: division by zero

Я построил и выполнил команду clang++ -fsanitize=undefined main.cpp && ./a.out


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

Здесь программа, которая создает отчет анализатора:

#include <malloc.h>

int main() {
    int *i = (int*) malloc(sizeof(int));
}

Скомпилированный с помощью clang++ -std=c++11 main.cpp он не производит диагностики, но скомпилирован с clang++ -std=c++11 --analyze main.cpp, он сообщает следующее:

main.cpp:4:10: warning: Value stored to 'i' during its initialization is never read
    int *i = (int*) malloc(sizeof(int));
         ^   ~~~~~~~~~~~~~~~~~~~~~~~~~~
main.cpp:5:1: warning: Potential leak of memory pointed to by 'i'
}
^

Мертвое хранилище также может быть обнаружено с помощью "Все" [-Унимое значение], но утечка обнаруживается только анализатором.

По умолчанию результаты полного анализа записываются в файл plist. Вы также можете запустить анализатор с помощью команд:

clang++ --analyze -Xanalyzer -analyzer-output=text main.cpp
clang++ --analyze -Xanalyzer -analyzer-output=html -o html-dir main.cpp

Чтобы получить подробные проходы обнаруженных проблем на стандартном выходе или через html-отображение аннотированного исходного кода, а не в plist.

Проверки анализатора перечислены здесь.

Обратите внимание, что для лучшей работы анализатору необходимо анализировать целые программы, а это значит, что он должен привязываться к системе сборки. Обычный интерфейс - через инструмент IDE (Xcode) или scan-build с make. У CMake есть некоторые функции clang, такие как создание clang файлов базы данных компиляции JSON, но я не уверен, если у CMake есть встроенная поддержка clang анализатор.

Ответ 2

Итак, если мы посмотрим на документацию в Control Code Generation, она говорит (внимание мое):

Включите проверку выполнения для различных форм undefined или подозрительного поведения.

Этот параметр определяет, добавляет ли Clang проверки времени выполнения для различных форм undefined или подозрительного поведения, и по умолчанию отключен. Если сбой проверки, во время выполнения появляется сообщение диагностическое сообщение, объясняющее проблему.

поэтому эти проверки времени выполнения не компилируются. Поэтому, если вы использовали foo в своем коде, вы увидите следующий вывод:

ошибка времени выполнения: деление на ноль

В этом примере live с помощью -fsanitize=undefined:

float foo(float f) { return (f / 0); }

int main()
{
    int x = 1 << 100 ;
    foo( 2.0f ) ;
}

он генерирует два сообщения во время выполнения:

main.cpp: 6: 19: ошибка времени выполнения: показатель экспоненты 100 слишком велик для 32-разрядного типа 'int'

main.cpp: 2: 36: ошибка времени выполнения: деление на ноль

Обновить

Что касается статических шашек, в ответе на С++-реализацию, которая обнаруживает поведение undefined? Я упоминаю несколько инструментов: STACK, kcc и, конечно, Frama-C.

По-видимому, clang позволяет вам использовать - анализировать, чтобы запустить статическую проверку, но похоже, что он может быть отключен в конце концов, и правильный способ запустить его будет через scan-build.

Также в моем ответе на вопрос Почему константные выражения имеют исключение для поведения undefined? Я показываю, как constexprs можно использовать для catch undefined во время компиляции.