Index: lib/CodeGen/CGExpr.cpp =================================================================== --- lib/CodeGen/CGExpr.cpp +++ lib/CodeGen/CGExpr.cpp @@ -544,44 +544,48 @@ llvm::raw_svector_ostream Out(MangledName); CGM.getCXXABI().getMangleContext().mangleCXXRTTI(Ty.getUnqualifiedType(), Out); - llvm::hash_code TypeHash = hash_value(Out.str()); - // Load the vptr, and compute hash_16_bytes(TypeHash, vptr). - llvm::Value *Low = llvm::ConstantInt::get(Int64Ty, TypeHash); - llvm::Type *VPtrTy = llvm::PointerType::get(IntPtrTy, 0); - llvm::Value *VPtrAddr = Builder.CreateBitCast(Address, VPtrTy); - llvm::Value *VPtrVal = Builder.CreateLoad(VPtrAddr); - llvm::Value *High = Builder.CreateZExt(VPtrVal, Int64Ty); - - llvm::Value *Hash = emitHash16Bytes(Builder, Low, High); - Hash = Builder.CreateTrunc(Hash, IntPtrTy); - - // Look the hash up in our cache. - const int CacheSize = 128; - llvm::Type *HashTable = llvm::ArrayType::get(IntPtrTy, CacheSize); - llvm::Value *Cache = CGM.CreateRuntimeVariable(HashTable, - "__ubsan_vptr_type_cache"); - llvm::Value *Slot = Builder.CreateAnd(Hash, - llvm::ConstantInt::get(IntPtrTy, - CacheSize-1)); - llvm::Value *Indices[] = { Builder.getInt32(0), Slot }; - llvm::Value *CacheVal = - Builder.CreateLoad(Builder.CreateInBoundsGEP(Cache, Indices)); - - // If the hash isn't in the cache, call a runtime handler to perform the - // hard work of checking whether the vptr is for an object of the right - // type. This will either fill in the cache and return, or produce a - // diagnostic. - llvm::Constant *StaticData[] = { - EmitCheckSourceLocation(Loc), - EmitCheckTypeDescriptor(Ty), - CGM.GetAddrOfRTTIDescriptor(Ty.getUnqualifiedType()), - llvm::ConstantInt::get(Int8Ty, TCK) - }; - llvm::Value *DynamicData[] = { Address, Hash }; - EmitCheck(Builder.CreateICmpEQ(CacheVal, Hash), - "dynamic_type_cache_miss", StaticData, DynamicData, - CRK_AlwaysRecoverable); + // Blacklist based on the mangled type. + if (!CGM.getSanitizerBlacklist().isBlacklistedType(Out.str())) { + llvm::hash_code TypeHash = hash_value(Out.str()); + + // Load the vptr, and compute hash_16_bytes(TypeHash, vptr). + llvm::Value *Low = llvm::ConstantInt::get(Int64Ty, TypeHash); + llvm::Type *VPtrTy = llvm::PointerType::get(IntPtrTy, 0); + llvm::Value *VPtrAddr = Builder.CreateBitCast(Address, VPtrTy); + llvm::Value *VPtrVal = Builder.CreateLoad(VPtrAddr); + llvm::Value *High = Builder.CreateZExt(VPtrVal, Int64Ty); + + llvm::Value *Hash = emitHash16Bytes(Builder, Low, High); + Hash = Builder.CreateTrunc(Hash, IntPtrTy); + + // Look the hash up in our cache. + const int CacheSize = 128; + llvm::Type *HashTable = llvm::ArrayType::get(IntPtrTy, CacheSize); + llvm::Value *Cache = CGM.CreateRuntimeVariable(HashTable, + "__ubsan_vptr_type_cache"); + llvm::Value *Slot = Builder.CreateAnd(Hash, + llvm::ConstantInt::get(IntPtrTy, + CacheSize-1)); + llvm::Value *Indices[] = { Builder.getInt32(0), Slot }; + llvm::Value *CacheVal = + Builder.CreateLoad(Builder.CreateInBoundsGEP(Cache, Indices)); + + // If the hash isn't in the cache, call a runtime handler to perform the + // hard work of checking whether the vptr is for an object of the right + // type. This will either fill in the cache and return, or produce a + // diagnostic. + llvm::Constant *StaticData[] = { + EmitCheckSourceLocation(Loc), + EmitCheckTypeDescriptor(Ty), + CGM.GetAddrOfRTTIDescriptor(Ty.getUnqualifiedType()), + llvm::ConstantInt::get(Int8Ty, TCK) + }; + llvm::Value *DynamicData[] = { Address, Hash }; + EmitCheck(Builder.CreateICmpEQ(CacheVal, Hash), + "dynamic_type_cache_miss", StaticData, DynamicData, + CRK_AlwaysRecoverable); + } } if (Done) { Index: lib/CodeGen/SanitizerBlacklist.h =================================================================== --- lib/CodeGen/SanitizerBlacklist.h +++ lib/CodeGen/SanitizerBlacklist.h @@ -38,6 +38,7 @@ bool isIn(const llvm::Function &F) const; bool isIn(const llvm::GlobalVariable &G, const StringRef Category = StringRef()) const; + bool isBlacklistedType(StringRef MangledTypeName) const; }; } // end namespace CodeGen } // end namespace clang Index: lib/CodeGen/SanitizerBlacklist.cpp =================================================================== --- lib/CodeGen/SanitizerBlacklist.cpp +++ lib/CodeGen/SanitizerBlacklist.cpp @@ -46,3 +46,7 @@ SCL->inSection("global", G.getName(), Category) || SCL->inSection("type", GetGlobalTypeString(G), Category); } + +bool SanitizerBlacklist::isBlacklistedType(StringRef MangledTypeName) const { + return SCL->inSection("type", MangledTypeName); +} Index: test/CodeGen/ubsan-type-blacklist.cpp =================================================================== --- test/CodeGen/ubsan-type-blacklist.cpp +++ test/CodeGen/ubsan-type-blacklist.cpp @@ -0,0 +1,23 @@ +// Verify ubsan vptr does not check down-casts on blacklisted types. +// RUN: echo "type:_ZTI3Foo" > %t-type.blacklist +// RUN: %clang_cc1 -fsanitize=vptr -emit-llvm %s -o - | FileCheck %s --check-prefix=DEFAULT +// RUN: %clang_cc1 -fsanitize=vptr -fsanitize-blacklist=%t-type.blacklist -emit-llvm %s -o - | FileCheck %s --check-prefix=TYPE + +// REQUIRES: shell + +class Bar { +public: + virtual ~Bar() {} +}; +class Foo : public Bar {}; + +Bar bar; + +// DEFAULT: @_Z7checkmev +// TYPE: @_Z7checkmev +void checkme() { +// DEFAULT: call void @__ubsan_handle_dynamic_type_cache_miss({{.*}} (%class.Bar* @bar to +// TYPE-NOT: call void @__ubsan_handle_dynamic_type_cache_miss({{.*}} (%class.Bar* @bar to + Foo* foo = static_cast(&bar); // down-casting + return; +}