Оптимизация времени соединения Clang с замененным оператором. Новые причины не совпадают free () / delete в valgrind.

При использовании clang 3.5.0 с -flto и связи с общей библиотекой кажется, что вызовы operator delete в общей библиотеке не следуйте тому же порядку разрешения символов, что и вызовы operator new от основных объектов. Пример:

shared.cpp:

void deleteIt(int* ptr) {
delete ptr;
}

main.cpp:

#include <cstdlib>
#include <new>

void* operator new(size_t size) {
void* result = std::malloc(size);
if (result == nullptr) {
throw std::bad_alloc();
}
return result;
}

void operator delete(void* ptr) noexcept {
std::free(ptr);
}

void deleteIt(int* ptr);

int main() {
deleteIt(new int);
return 0;
}

Вот что происходит, когда я собираю его и запускаю через valgrind:

$ clang++ -std=c++11 -g -O3 -flto -fuse-ld=gold -fPIC -shared shared.cpp -o libshared.so
$ clang++ -std=c++11 -g -O3 -flto -fuse-ld=gold main.cpp -L. -lshared -o main
$ LD_LIBRARY_PATH=. valgrind --quiet ./main
==20557== Mismatched free() / delete / delete []
==20557==    at 0x4C2B6D0: operator delete(void*) (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==20557==    by 0x4009F7: main (main.cpp:19)
==20557==  Address 0x5a03040 is 0 bytes inside a block of size 4 alloc'd
==20557==    at 0x4C29F90: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==20557==    by 0x4009EA: operator new (main.cpp:5)
==20557==    by 0x4009EA: main (main.cpp:19)
==20557==

Вы можете видеть, что он находит Вальгринда operator delete, но используя operator new от main.cpp, Напротив, точно такая же сборка с gcc (просто замени clang++ с g++) работает отлично. Есть идеи почему или как обойти это?

РЕДАКТИРОВАТЬ: импорт и экспорт символов в соответствии с запросом @Deduplicator.

$ objdump -T main | c++filt | grep operator
0000000000400990 g    DF .text  0000000000000033  Base        operator new(unsigned long)
0000000000000000      DF *UND*  0000000000000000  Base        operator delete(void*)
$ objdump -T libshared.so | c++filt | grep operator
0000000000000000      DF *UND*  0000000000000000  GLIBCXX_3.4 operator delete(void*)

5

Решение

Глядя на объектно-свалка, это очевидно operator delete(void*) не экспортируется main,

$ objdump -T main | c++filt | grep operator
0000000000400990 g    DF .text  0000000000000033  Base        operator new(unsigned long)
0000000000000000      DF *UND*  0000000000000000  Base        operator delete(void*)

Смотрите, что раздел, где operator delete(void*) хранится *UND*: Его там нет!

Теперь, это очевидный сбой со стороны clang, может сделать хороший отчет об ошибке, так как у нас уже есть минимальный тест-кейс.

Теперь, как заставить Clang сохранить и экспортировать operator delete(void*) как лейкопластырь?
Ответ глядя на возможные атрибуты, есть хороший

используемый
Этот атрибут, прикрепленный к функции, означает, что для функции должен быть выдан код, даже если кажется, что на функцию нет ссылки. Это полезно, например, когда на функцию ссылаются только во встроенной сборке.
При применении к функции-члену шаблона класса C ++ атрибут также означает, что создается экземпляр функции, если создается экземпляр самого класса.

Поместив это в код:

void operator delete(void* ptr) noexcept  __attribute__((used)) {

И вуаля, лязг больше не неправильно его подрезает.

5

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


По вопросам рекламы [email protected]