5

-flto を指定して clang 3.5.0 を使用し、共有ライブラリとリンクする場合、共有ライブラリ内の への呼び出しは、メイン オブジェクトからのoperator deleteへの呼び出しと同じシンボル解決順序に従わないようです。operator new例:

共有.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== 

valgrind の を見つけていることがわかりますが、 fromoperator deleteを使用しています。対照的に、gcc を使用したまったく同じビルド (を に置き換えるだけ) は正常に動作します。理由、またはそれを回避する方法はありますか?operator newmain.cppclang++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*)
4

1 に答える 1

5

object-dumpを見ると、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*)バンドエイドとして強制的に保持およびエクスポートするにはどうすればよいでしょうか。
答えは可能な属性を見ることです。良いものがあります:

used
関数に付加されるこの属性は、関数が参照されていないように見える場合でも、関数のコードを発行する必要があることを意味します。これは、関数がインライン アセンブリでのみ参照される場合などに便利です。C++ クラス テンプレートのメンバー関数に適用された場合、この属性は、クラス自体がインスタンス化されている場合に関数がインスタンス化されることも意味します。

それをコードに入れる:

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

そしてほら、clang はもはやそれを不適切に剪定しません。

于 2014-09-18T22:49:50.857 に答える