Управление ведением журнала для Address Sanitizer PLUS Undefined Behavior Sanitizer?

Несколько дезинфицирующих средств (из GCC или Clang) нельзя комбинировать — т. е. использовать одновременно в одной сборке, но Asan и Ubsan можно комбинировать — т. е. я могу собрать с «-fsanitize=address,undefined -fsanitize-recover=all…» и иметь исполняемый файл, который выполняет проверки обоих дезинфицирующих средств. Пока все хорошо.

Однако LOGGING из полученного исполняемого файла кажется проблематичным.

Во всех случаях, если в параметрах не задан «log_path», обо всех дефектах сообщается на stderr. ОК пока. Однако попробуйте использовать log_path, и все станет странно:

  • Для исполняемого файла, созданного только с помощью Asan, и для параметра ASAN_OPTIONS, включающего «log_path=./ASAN», дефекты Address Saniitizer попадут в файл с именем ASAN.
  • Для исполняемого файла, созданного только с помощью Ubsan, и для параметра UBSAN_OPTIONS, включающего «log_path=./UBSAN», дефекты неопределенного поведения будут помещены в файл с именем UBSAN.
  • Для исполняемого файла, созданного как с Asan, так и с Ubsan o Выходные данные Asan идут в указанный файл журнала, но выходные данные ubsan идут только в stderr o Вышеприведенное применимо, даже если log_path установлен только через UBSAN_OPTIONS, а ASAN_OPTIONS не установлен o Если log_path установлен установлен как в ASAN_OPTIONS, так и в UBSAN_OPTIONS, используемый log_path является UBSAN, но содержит только результаты ASAN

Есть ли какая-то скрытая магия, позволяющая обоим дезинфицирующим средствам записывать в один и тот же журнал дефектов?


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

char *hello = "hello";

int main (int argc, char *argv[])
{
   int x = 1;
   x <<= 32; // Error: (1 << 32) can't be represented in a (32-bit) int
   char some_char = hello [argc *10];
}

построить и запустить: (здесь используется g++ 7.3.0, но другие версии GCC, а также clang 7.1.0 показали такое же базовое поведение)

Только асан - работает как положено

g++ foo.C -fsanitize=address -fsanitize-recover=all -g
setenv ASAN_OPTIONS "log_path=./ASAN:halt_on_error=0:handle_abort=1:exitcode=0"
a.out 

Файл АСАН. 29648 содержит дефект, начинающийся с

== 29648 == ОШИБКА: AddressSanitizer: глобальное переполнение буфера по адресу 0x000000400aca на ПК 0x0000004009a5 bp 0x7fffffffe090 sp 0x7fffffffe088

ЧТЕНИЕ размера 1 в 0x000000400aca thread T0 0x4009a4 в main /tmp/foo.C:7

Только Убсан - работает как положено

g++ foo.C -fsanitize=undefined -fsanitize-recover=all -g
setenv UBSAN_OPTIONS "log_path=./UBSAN:halt_on_error=0:handle_abort=1:exitcode=0”
a.out

Файл UBSAN.29675 содержит

foo.C:6:6: ошибка выполнения: экспонента сдвига 32 слишком велика для 32-битного типа 'int'

Asan PLUS Ubsan - странное поведение при регистрации

g++ foo.C -fsanitize=address,undefined -fsanitize-recover=all -g

setenv ASAN_OPTIONS "log_path=./ASAN:halt_on_error=0:handle_abort=1:exitcode=0"
a.out 

ASAN_OPTIONS игнорируется, обо всех дефектах сообщается в stderr. Теперь попробуйте установить UBSAN_OPTIONS:

setenv UBSAN_OPTIONS "log_path=./UBSAN:halt_on_error=0:handle_abort=1:exitcode=0”
a.out

Файл UBSAN.30352 содержит ТОЛЬКО дефект Asan:

==30352==ОШИБКА: AddressSanitizer: глобальное переполнение буфера по адресу 0x000000400aca на компьютере 0x0000004009a5 bp 0x7fffffffe090 sp 0x7fffffffe088 ЧТЕНИЕ размера 1 по адресу 0x000000400aca thread T0 0x4009a4 в main /tmp7foo.C:tmp7foo.C:tmp7foo.C:tmp7foo.C:

а дефект Ubsan записывается только в stderr:

foo.C:6:6: ошибка выполнения: экспонента сдвига 32 слишком велика для 32-битного типа 'int'


person Gordon Mc    schedule 20.03.2020    source источник


Ответы (3)


а дефект Ubsan записывается только в stderr:

Это звучит как ошибка (или, по крайней мере, непроверенная комбинация настроек).

Тем не менее, в целом, разработчики ASan не считают halt_on_error=0 полезной функцией - вы должны просто исправлять ошибки по мере их обнаружения, так как бессмысленно искать UB после< /em> вы уже переполнили буфер или использовали зависшую память. Что угодно может произойти после этого момента.

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

person Employed Russian    schedule 21.03.2020
comment
Я не верю, что это имеет какое-либо отношение к тому, следует ли продолжать после ошибки. Как вы можете видеть в примере, UB происходит ДО переполнения буфера, поэтому в этом случае первая ошибка даже не регистрируется в журнале — она теряется для stderr, в то время как в журнал фиксируется только ПОСЛЕДНЕЕ переполнение буфера. - person Gordon Mc; 25.03.2020

Подтвердили, что это действительно ошибка. https://gcc.gnu.org/bugzilla/show_bug.cgi?id=94328 применяется

person Gordon Mc    schedule 25.03.2020

Я искал способ использовать AddressSantizer с avr-gcc, где нет консоли, чтобы обнаружить сбой кода среды выполнения. Мне все еще нужно поэкспериментировать с этим, но я считаю, что этот вариант использования является контрпримером того, что эта функция бесполезна.

person mds    schedule 17.10.2020