r244933 - Fix previous commit: poison only class members, simpler tests

Naomi Musgrave via cfe-commits cfe-commits at lists.llvm.org
Thu Aug 13 11:35:11 PDT 2015


Author: nmusgrave
Date: Thu Aug 13 13:35:11 2015
New Revision: 244933

URL: http://llvm.org/viewvc/llvm-project?rev=244933&view=rev
Log:
Fix previous commit: poison only class members, simpler tests

Summary: Poisoning applied to only class members, and before dtors for base class invoked

Implement poisoning of only class members in dtor, as opposed to also
poisoning fields inherited from base classes. Members are poisoned
only once, by the last dtor for a class. Skip poisoning if class has
no fields.
Verify emitted code for derived class with virtual destructor sanitizes
its members only once.
Removed patch file containing extraneous changes.

Reviewers: eugenis, kcc

Differential Revision: http://reviews.llvm.org/D11951


Simplified test cases for use-after-dtor

Summary: Simplified test cases to focus on one feature at time.
Tests updated to align with new emission order for sanitizing
callback.

Reviewers: eugenis, kcc

Differential Revision: http://reviews.llvm.org/D12003

Added:
    cfe/trunk/test/CodeGenCXX/sanitize-dtor-derived-class.cpp
Modified:
    cfe/trunk/lib/CodeGen/CGClass.cpp
    cfe/trunk/test/CodeGenCXX/sanitize-dtor-callback.cpp
    cfe/trunk/test/CodeGenCXX/sanitize-dtor-fn-attribute.cpp

Modified: cfe/trunk/lib/CodeGen/CGClass.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGClass.cpp?rev=244933&r1=244932&r2=244933&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGClass.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGClass.cpp Thu Aug 13 13:35:11 2015
@@ -1376,9 +1376,30 @@ static void EmitDtorSanitizerCallback(Co
   const ASTRecordLayout &Layout =
       CGF.getContext().getASTRecordLayout(Dtor->getParent());
 
+  // Nothing to poison
+  if(Layout.getFieldCount() == 0)
+    return;
+
+  // Construct pointer to region to begin poisoning, and calculate poison
+  // size, so that only members declared in this class are poisoned.
+  llvm::Value *OffsetPtr;
+  CharUnits::QuantityType PoisonSize;
+  ASTContext &Context = CGF.getContext();
+
+  llvm::ConstantInt *OffsetSizePtr = llvm::ConstantInt::get(
+      CGF.SizeTy, Context.toCharUnitsFromBits(Layout.getFieldOffset(0)).
+      getQuantity());
+
+  OffsetPtr = CGF.Builder.CreateGEP(CGF.Builder.CreateBitCast(
+      CGF.LoadCXXThis(), CGF.Int8PtrTy), OffsetSizePtr);
+
+  PoisonSize = Layout.getSize().getQuantity() -
+      Context.toCharUnitsFromBits(Layout.getFieldOffset(0)).getQuantity();
+
   llvm::Value *Args[] = {
-      CGF.Builder.CreateBitCast(CGF.LoadCXXThis(), CGF.VoidPtrTy),
-      llvm::ConstantInt::get(CGF.SizeTy, Layout.getSize().getQuantity())};
+    CGF.Builder.CreateBitCast(OffsetPtr, CGF.VoidPtrTy),
+    llvm::ConstantInt::get(CGF.SizeTy, PoisonSize)};
+
   llvm::Type *ArgTypes[] = {CGF.VoidPtrTy, CGF.SizeTy};
 
   llvm::FunctionType *FnType =
@@ -1386,6 +1407,8 @@ static void EmitDtorSanitizerCallback(Co
   llvm::Value *Fn =
       CGF.CGM.CreateRuntimeFunction(FnType, "__sanitizer_dtor_callback");
 
+  // Disables tail call elimination, to prevent the current stack frame from
+  // disappearing from the stack trace.
   CGF.CurFn->addFnAttr("disable-tail-calls", "true");
   CGF.EmitNounwindRuntimeCall(Fn, Args);
 }
@@ -1468,6 +1491,13 @@ void CodeGenFunction::EmitDestructorBody
     // the caller's body.
     if (getLangOpts().AppleKext)
       CurFn->addFnAttr(llvm::Attribute::AlwaysInline);
+
+    // Insert memory-poisoning instrumentation, before final clean ups,
+    // to ensure this class's members are protected from invalid access.
+    if (CGM.getCodeGenOpts().SanitizeMemoryUseAfterDtor
+        && SanOpts.has(SanitizerKind::Memory))
+      EmitDtorSanitizerCallback(*this, Dtor);
+
     break;
   }
 
@@ -1477,11 +1507,6 @@ void CodeGenFunction::EmitDestructorBody
   // Exit the try if applicable.
   if (isTryBody)
     ExitCXXTryStmt(*cast<CXXTryStmt>(Body), true);
-
-  // Insert memory-poisoning instrumentation.
-  if (CGM.getCodeGenOpts().SanitizeMemoryUseAfterDtor
-      && SanOpts.has(SanitizerKind::Memory))
-    EmitDtorSanitizerCallback(*this, Dtor);
 }
 
 void CodeGenFunction::emitImplicitAssignmentOperatorBody(FunctionArgList &Args) {

Modified: cfe/trunk/test/CodeGenCXX/sanitize-dtor-callback.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/sanitize-dtor-callback.cpp?rev=244933&r1=244932&r2=244933&view=diff
==============================================================================
--- cfe/trunk/test/CodeGenCXX/sanitize-dtor-callback.cpp (original)
+++ cfe/trunk/test/CodeGenCXX/sanitize-dtor-callback.cpp Thu Aug 13 13:35:11 2015
@@ -1,24 +1,26 @@
 // Test -fsanitize-memory-use-after-dtor
 // RUN: %clang_cc1 -fsanitize=memory -fsanitize-memory-use-after-dtor -std=c++11 -triple=x86_64-pc-linux -emit-llvm -o - %s | FileCheck %s
 
+// Sanitizing dtor is emitted in dtor for every class
+
 struct Simple {
+  int x;
   ~Simple() {}
 };
 Simple s;
 // Simple internal member is poisoned by compiler-generated dtor
 // CHECK-LABEL: define {{.*}}SimpleD1Ev
-// CHECK: call void @__sanitizer_dtor_callback
-// CHECK-NOT: call void @__sanitizer_dtor_callback
+// CHECK: call void {{.*}}SimpleD2Ev
 // CHECK: ret void
 
 struct Inlined {
+  int y;
   inline ~Inlined() {}
 };
 Inlined i;
 // Simple internal member is poisoned by compiler-generated dtor
 // CHECK-LABEL: define {{.*}}InlinedD1Ev
-// CHECK: call void @__sanitizer_dtor_callback
-// CHECK-NOT: call void @__sanitizer_dtor_callback
+// CHECK: call void {{.*}}InlinedD2Ev
 // CHECK: ret void
 
 struct Defaulted_Trivial {
@@ -32,7 +34,6 @@ void create_def_trivial() {
 // no destructor defined.
 // CHECK-LABEL: define {{.*}}create_def_trivial
 // CHECK-NOT: call {{.*}}Defaulted_Trivial
-// CHECK-NOT: call void @__sanitizer_dtor_callback
 // CHECK: ret void
 
 struct Defaulted_Non_Trivial {
@@ -44,8 +45,7 @@ Defaulted_Non_Trivial def_non_trivial;
 // By including a Simple member in the struct, the compiler is
 // forced to generate a non-trivial destructor.
 // CHECK-LABEL: define {{.*}}Defaulted_Non_TrivialD1Ev
-// CHECK: call void @__sanitizer_dtor_callback
-// CHECK-NOT: call void @__sanitizer_dtor_callback
+// CHECK: call void {{.*}}Defaulted_Non_TrivialD2
 // CHECK: ret void
 
 

Added: cfe/trunk/test/CodeGenCXX/sanitize-dtor-derived-class.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/sanitize-dtor-derived-class.cpp?rev=244933&view=auto
==============================================================================
--- cfe/trunk/test/CodeGenCXX/sanitize-dtor-derived-class.cpp (added)
+++ cfe/trunk/test/CodeGenCXX/sanitize-dtor-derived-class.cpp Thu Aug 13 13:35:11 2015
@@ -0,0 +1,65 @@
+// RUN: %clang_cc1 -fsanitize=memory -fsanitize-memory-use-after-dtor -disable-llvm-optzns -std=c++11 -triple=x86_64-pc-linux -emit-llvm -o - %s | FileCheck %s
+// RUN: %clang_cc1 -O1 -fsanitize=memory -fsanitize-memory-use-after-dtor -disable-llvm-optzns -std=c++11 -triple=x86_64-pc-linux -emit-llvm -o - %s | FileCheck %s
+
+// Only the last dtor of a class invokes the sanitizing callback
+// Sanitizing callback emited prior to base class dtor invocations
+
+class Base {
+ public:
+  int x;
+  Base() {
+    x = 5;
+  }
+  virtual ~Base() {
+    x += 1;
+  }
+};
+
+class Derived : public Base {
+ public:
+  int y;
+  Derived() {
+    y = 10;
+  }
+  ~Derived() {
+    y += 1;
+  }
+};
+
+Derived d;
+
+// CHECK-LABEL: define {{.*}}DerivedD1Ev
+// CHECK-NOT: call void @__sanitizer_dtor_callback
+// CHECK: call void {{.*}}DerivedD2Ev
+// CHECK-NOT: call void @__sanitizer_dtor_callback
+// CHECK: ret void
+
+// CHECK-LABEL: define {{.*}}DerivedD0Ev
+// CHECK-NOT: call void @__sanitizer_dtor_callback
+// CHECK: call void {{.*}}DerivedD1Ev
+// CHECK-NOT: call void @__sanitizer_dtor_callback
+// CHECK: ret void
+
+// CHECK-LABEL: define {{.*}}BaseD1Ev
+// CHECK-NOT: call void @__sanitizer_dtor_callback
+// CHECK: call void {{.*}}BaseD2Ev
+// CHECK-NOT: call void @__sanitizer_dtor_callback
+// CHECK: ret void
+
+// CHECK-LABEL: define {{.*}}BaseD0Ev
+// CHECK-NOT: call void @__sanitizer_dtor_callback
+// CHECK: call void {{.*}}BaseD1Ev
+// CHECK-NOT: call void @__sanitizer_dtor_callback
+// CHECK: ret void
+
+// CHECK-LABEL: define {{.*}}BaseD2Ev
+// CHECK: call void @__sanitizer_dtor_callback
+// CHECK-NOT: call void @__sanitizer_dtor_callback
+// CHECK: ret void
+
+// CHECK-LABEL: define {{.*}}DerivedD2Ev
+// CHECK: call void @__sanitizer_dtor_callback
+// CHECK-NOT: call void @__sanitizer_dtor_callback
+// CHECK: call void {{.*}}BaseD2Ev
+// CHECK-NOT: call void @__sanitizer_dtor_callback
+// CHECK: ret void

Modified: cfe/trunk/test/CodeGenCXX/sanitize-dtor-fn-attribute.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/sanitize-dtor-fn-attribute.cpp?rev=244933&r1=244932&r2=244933&view=diff
==============================================================================
--- cfe/trunk/test/CodeGenCXX/sanitize-dtor-fn-attribute.cpp (original)
+++ cfe/trunk/test/CodeGenCXX/sanitize-dtor-fn-attribute.cpp Thu Aug 13 13:35:11 2015
@@ -1,20 +1,20 @@
 // Test -fsanitize-memory-use-after-dtor
 // RUN: %clang_cc1 -fsanitize=memory -fsanitize-memory-use-after-dtor -std=c++11 -triple=x86_64-pc-linux -emit-llvm -o - %s | FileCheck %s
-// RUN: %clang_cc1 -DATTRIBUTE -fsanitize=memory -fsanitize-memory-use-after-dtor -std=c++11 -triple=x86_64-pc-linux -emit-llvm -o - %s | FileCheck %s --check-prefix=CHECK-ATTR
+
+// The no_sanitize_memory attribute, when applied to a destructor,
+// represses emission of sanitizing callback
 
 template <class T> class Vector {
  public:
+  int size;
   ~Vector() {}
 };
 
 struct No_San {
   Vector<int> v;
+  int x;
   No_San() { }
-#ifdef ATTRIBUTE
   __attribute__((no_sanitize_memory)) ~No_San() = default;
-#else
-  ~No_San() = default;
-#endif
 };
 
 int main() {
@@ -26,26 +26,18 @@ int main() {
 // Repressing the sanitization attribute results in no msan
 // instrumentation of the destructor
 // CHECK: define {{.*}}No_SanD1Ev{{.*}} [[ATTRIBUTE:#[0-9]+]]
-// CHECK: call void {{.*}}No_SanD2Ev
-// CHECK: call void @__sanitizer_dtor_callback
+// CHECK-NOT: call void {{.*}}sanitizer_dtor_callback
 // CHECK: ret void
 
-// CHECK-ATTR: define {{.*}}No_SanD1Ev{{.*}} [[ATTRIBUTE:#[0-9]+]]
-// CHECK-ATTR: call void {{.*}}No_SanD2Ev
-// CHECK-ATTR-NOT: call void @__sanitizer_dtor_callback
-// CHECK-ATTR: ret void
-
-
 // CHECK: define {{.*}}No_SanD2Ev{{.*}} [[ATTRIBUTE:#[0-9]+]]
-// CHECK: call void {{.*}}Vector
-// CHECK: call void @__sanitizer_dtor_callback
+// CHECK-NOT: call void {{.*}}sanitizer_dtor_callback
+// CHECK: call void {{.*}}VectorIiED2Ev
+// CHECK-NOT: call void {{.*}}sanitizer_dtor_callback
 // CHECK: ret void
 
-// CHECK-ATTR: define {{.*}}No_SanD2Ev{{.*}} [[ATTRIBUTE:#[0-9]+]]
-// CHECK-ATTR: call void {{.*}}Vector
-// CHECK-ATTR-NOT: call void @__sanitizer_dtor_callback
-// CHECK-ATTR: ret void
+// CHECK: define {{.*}}VectorIiED2Ev
+// CHECK: call void {{.*}}sanitizer_dtor_callback
+// CHECK: ret void
 
 // When attribute is repressed, the destructor does not emit any tail calls
-// CHECK: attributes [[ATTRIBUTE]] = {{.*}} sanitize_memory
-// CHECK-ATTR-NOT: attributes [[ATTRIBUTE]] = {{.*}} sanitize_memory
+// CHECK-NOT: attributes [[ATTRIBUTE]] = {{.*}} sanitize_memory




More information about the cfe-commits mailing list