]> granicus.if.org Git - clang/commitdiff
[UBSan] Introduce type-based blacklisting.
authorAlexey Samsonov <vonosmas@gmail.com>
Thu, 10 Jul 2014 22:34:19 +0000 (22:34 +0000)
committerAlexey Samsonov <vonosmas@gmail.com>
Thu, 10 Jul 2014 22:34:19 +0000 (22:34 +0000)
Teach UBSan vptr checker to ignore technically invalud down-casts on
blacklisted types.

Based on http://reviews.llvm.org/D4407 by Byoungyoung Lee!

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@212770 91177308-0d34-0410-b5e6-96231b3b80d8

lib/CodeGen/CGExpr.cpp
lib/CodeGen/SanitizerBlacklist.cpp
lib/CodeGen/SanitizerBlacklist.h
test/CodeGen/ubsan-type-blacklist.cpp [new file with mode: 0644]

index c99e669f6ff8fdec6a88ca078bc77d947a37c7aa..a43cf30da736873c57d92274e35d692dd249b17c 100644 (file)
@@ -544,44 +544,48 @@ void CodeGenFunction::EmitTypeCheck(TypeCheckKind TCK, SourceLocation Loc,
     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 60bdbe1d92e4fd76d8706979fbe47414c4bd2f89..9f1ddc8e7d7b9e8b87e2e0b4494d846a9cc20153 100644 (file)
@@ -46,3 +46,7 @@ bool SanitizerBlacklist::isIn(const llvm::GlobalVariable &G,
          SCL->inSection("global", G.getName(), Category) ||
          SCL->inSection("type", GetGlobalTypeString(G), Category);
 }
+
+bool SanitizerBlacklist::isBlacklistedType(StringRef MangledTypeName) const {
+  return SCL->inSection("type", MangledTypeName);
+}
index b8c283ccf4f4cd7168474296a5a650f21eecaabc..659441dfe346f0850ab7bb16b2b99d2bbaf2bcc0 100644 (file)
@@ -38,6 +38,7 @@ public:
   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
diff --git a/test/CodeGen/ubsan-type-blacklist.cpp b/test/CodeGen/ubsan-type-blacklist.cpp
new file mode 100644 (file)
index 0000000..7dc6fe1
--- /dev/null
@@ -0,0 +1,25 @@
+// Verify ubsan vptr does not check down-casts on blacklisted types.
+// RUN: echo "type:_ZTI3Foo" > %t-type.blacklist
+// RUN: %clang_cc1 -triple x86_64-linux-gnu -fsanitize=vptr -emit-llvm %s -o - | FileCheck %s --check-prefix=DEFAULT
+// RUN: %clang_cc1 -triple x86_64-linux-gnu -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: @__ubsan_handle_dynamic_type_cache_miss
+  Foo* foo = static_cast<Foo*>(&bar); // down-casting
+// DEFAULT: ret void
+// TYPE: ret void
+  return;
+}