Я пытаюсь добавить 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?
Это похоже на ошибку в 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
в твоем случае). Смотрите, например этот ответ для другого примера такого поведения и доступных обходных путей.
Других решений пока нет …