clang и clang ++ с ASAN генерируют различный вывод

Я пытаюсь добавить ASAN (адрес Google / Clang для очистки) в наш проект и застрял в этой проблеме.

Например, у нас есть этот простой код C ++

#include <iostream>
int main() {
std::cout << "Started Program\n";
int* i = new int();
*i = 42;
std::cout << "Expected i: " << *i << std::endl;
}

Затем я создаю его с помощью Clang ++

clang++-3.8 -o memory-leak++ memory_leak.cpp -fsanitize=address -fno-omit-frame-pointer -g

Программа выдает этот вывод

Started Program
Expected i: 42

=================================================================
==14891==ERROR: LeakSanitizer: detected memory leaks

Direct leak of 4 byte(s) in 1 object(s) allocated from:
#0 0x4f2040 in operator new(unsigned long) (memory-leak+++0x4f2040)
#1 0x4f4f00 in main memory_leak.cpp:4:11
#2 0x7fae13ce6f44 in __libc_start_main /build/eglibc-SvCtMH/eglibc-2.19/csu/libc-start.c:287

SUMMARY: AddressSanitizer: 4 byte(s) leaked in 1 allocation(s).

Круто, это работает, и символизатор также дает значимую информацию.

Теперь я строю это с лязг

clang-3.8 -o memory-leak memory_leak.cpp -std=c++11 -fsanitize=address -fno-omit-frame-pointer -g -lstdc++

И программа выдает этот вывод

Started Program
Expected i: 42

=================================================================
==14922==ERROR: LeakSanitizer: detected memory leaks

Direct leak of 4 byte(s) in 1 object(s) allocated from:
#0 0x4c3bc8 in malloc (memory-leak+0x4c3bc8)
#1 0x7f024a8e4dac in operator new(unsigned long) (/usr/lib/x86_64-linux-gnu/libstdc++.so.6+0x5edac)
#2 0x7f0249998f44 in __libc_start_main /build/eglibc-SvCtMH/eglibc-2.19/csu/libc-start.c:287

SUMMARY: AddressSanitizer: 4 byte(s) leaked in 1 allocation(s).

Хорошо, он обнаруживает утечку памяти, но трассировка стека выглядит странно и не содержит строки memory_leak.cpp: 4: 11.

Я потратил довольно много времени, пытаясь сузить эту проблему в нашей кодовой базе, и, в конце концов, единственное отличие — это clang vs clang ++.

Почему это событие, проблема, мы не можем использовать Clang ++?
Мы используем bazel, который использует компилятор CC вместо CXX по некоторым причинам. Мы не можем слепо заставить его использовать CXX, потому что у нас есть зависимости CC, которые не могут быть созданы CXX. Так…

Любая идея, как получить тот же вывод ASAN при использовании с Clang и Clang ++? Или как заставить Bazel использовать clang ++ для целей C ++ и clang для целей C?

2

Решение

Это похоже на ошибку в Clang, не могли бы вы подать отчет об ошибке в их трекер? (РЕДАКТИРОВАТЬ: это было [решено как не-ошибка] (разработчики Asan https://github.com/google/sanitizers/issues/872) так что, скорее всего, это должно быть исправлено разработчиками Bazel).

Некоторые детали: когда вы используете обычный clang, он решает не связывать C ++ часть времени выполнения Asan, как это можно увидеть в Tools.cpp:

if (SanArgs.linkCXXRuntimes())
StaticRuntimes.push_back("asan_cxx");

а также SanitizerArgs.cpp:

LinkCXXRuntimes =
Args.hasArg(options::OPT_fsanitize_link_cxx_runtime) || D.CCCIsCXX();

(Обратите внимание D.CCCIsCXX часть, это проверяет clang против clang++ тогда как вместо этого им нужно проверить тип файла).

C ++ часть времени выполнения содержит перехватчик для operator new так что это объясняет, почему он отсутствует, когда вы связываете с clang вместо clang++, С положительной стороны, вы должны быть в состоянии обойти это, добавив -fsanitize-link-c++-runtime на ваши флаги.

Что касается растопленного стека, по умолчанию Asan раскручивает стек с разматывателем, основанным на указателе фрейма, который имеет проблемы с размоткой кода, который не был создан с -fno-omit-frame-pointer (лайк libstdc++.so в твоем случае). Смотрите, например этот ответ для другого примера такого поведения и доступных обходных путей.

0

Другие решения

Других решений пока нет …