diff --git a/clang/lib/CodeGen/CGVTables.h b/clang/lib/CodeGen/CGVTables.h --- a/clang/lib/CodeGen/CGVTables.h +++ b/clang/lib/CodeGen/CGVTables.h @@ -155,8 +155,8 @@ void GenerateRelativeVTableAlias(llvm::GlobalVariable *VTable, llvm::StringRef AliasNameRef); - /// Specify a vtable should not be instrumented with hwasan. - void RemoveHwasanMetadata(llvm::GlobalValue *VTable); + /// Specify a global should not be instrumented with hwasan. + void RemoveHwasanMetadata(llvm::GlobalValue *GV) const; }; } // end namespace CodeGen diff --git a/clang/lib/CodeGen/CGVTables.cpp b/clang/lib/CodeGen/CGVTables.cpp --- a/clang/lib/CodeGen/CGVTables.cpp +++ b/clang/lib/CodeGen/CGVTables.cpp @@ -664,6 +664,12 @@ proxy->setVisibility(llvm::GlobalValue::HiddenVisibility); proxy->setComdat(module.getOrInsertComdat(rttiProxyName)); } + // Do not instrument the rtti proxies with hwasan to avoid a duplicate + // symbol error. Aliases generated by hwasan will retain the same namebut + // the addresses they are set to may have different tags from different + // compilation units. We don't run into this without hwasan because the + // proxies are in comdat groups, but those aren't propagated to the alias. + RemoveHwasanMetadata(proxy); } target = proxy; } @@ -938,13 +944,13 @@ // relocations. A future alternative for this would be finding which usages of // the vtable can continue to use the untagged hwasan value without any loss of // value in hwasan. -void CodeGenVTables::RemoveHwasanMetadata(llvm::GlobalValue *VTable) { +void CodeGenVTables::RemoveHwasanMetadata(llvm::GlobalValue *GV) const { if (CGM.getLangOpts().Sanitize.has(SanitizerKind::HWAddress)) { llvm::GlobalValue::SanitizerMetadata Meta; - if (VTable->hasSanitizerMetadata()) - Meta = VTable->getSanitizerMetadata(); + if (GV->hasSanitizerMetadata()) + Meta = GV->getSanitizerMetadata(); Meta.NoHWAddress = true; - VTable->setSanitizerMetadata(Meta); + GV->setSanitizerMetadata(Meta); } } diff --git a/clang/test/CodeGenCXX/RelativeVTablesABI/relative-vtables-hwasan.cpp b/clang/test/CodeGenCXX/RelativeVTablesABI/relative-vtables-hwasan.cpp --- a/clang/test/CodeGenCXX/RelativeVTablesABI/relative-vtables-hwasan.cpp +++ b/clang/test/CodeGenCXX/RelativeVTablesABI/relative-vtables-hwasan.cpp @@ -6,6 +6,7 @@ /// hwasan-instrumented. // CHECK-DAG: @_ZTV1A.local = private unnamed_addr constant { [3 x i32] } { [3 x i32] [i32 0, i32 trunc (i64 sub (i64 ptrtoint (ptr @_ZTI1A.rtti_proxy to i64), i64 ptrtoint (ptr getelementptr inbounds ({ [3 x i32] }, ptr @_ZTV1A.local, i32 0, i32 0, i32 2) to i64)) to i32), i32 trunc (i64 sub (i64 ptrtoint (ptr dso_local_equivalent @_ZN1A3fooEv to i64), i64 ptrtoint (ptr getelementptr inbounds ({ [3 x i32] }, ptr @_ZTV1A.local, i32 0, i32 0, i32 2) to i64)) to i32)] }, no_sanitize_hwaddress, align 4 // CHECK-DAG: @_ZTV1A = unnamed_addr alias { [3 x i32] }, ptr @_ZTV1A.local +// CHECK-DAG: @_ZTI1A.rtti_proxy = hidden unnamed_addr constant ptr @_ZTI1A, no_sanitize_hwaddress, comdat class A { public: @@ -21,6 +22,7 @@ /// If the vtable happens to be hidden, then the alias is not needed. In this /// case, the original vtable struct itself should be unsanitized. // CHECK-DAG: @_ZTV1B = hidden unnamed_addr constant { [3 x i32] } { [3 x i32] [i32 0, i32 trunc (i64 sub (i64 ptrtoint (ptr @_ZTI1B.rtti_proxy to i64), i64 ptrtoint (ptr getelementptr inbounds ({ [3 x i32] }, ptr @_ZTV1B, i32 0, i32 0, i32 2) to i64)) to i32), i32 trunc (i64 sub (i64 ptrtoint (ptr dso_local_equivalent @_ZN1B3fooEv to i64), i64 ptrtoint (ptr getelementptr inbounds ({ [3 x i32] }, ptr @_ZTV1B, i32 0, i32 0, i32 2) to i64)) to i32)] }, no_sanitize_hwaddress, align 4 +// CHECK-DAG: @_ZTI1B.rtti_proxy = hidden unnamed_addr constant ptr @_ZTI1B, no_sanitize_hwaddress, comdat class __attribute__((visibility("hidden"))) B { public: