sepavloff updated this revision to Diff 157102.
sepavloff added a comment.

Updated patch

- Modified check generation. Now for each 'new' expression compiler tries to

generate the checks. It solves problem of 'nested' new expressions, which
appear when 'new' is used in default arguments.

- Field and RAII class names are made more specific.
- Added new tests including that with inplace new operator.


Repository:
  rC Clang

https://reviews.llvm.org/D49589

Files:
  lib/CodeGen/CGClass.cpp
  lib/CodeGen/CGExprCXX.cpp
  lib/CodeGen/CodeGenFunction.h
  test/CodeGenCXX/ubsan-new-checks.cpp

Index: test/CodeGenCXX/ubsan-new-checks.cpp
===================================================================
--- /dev/null
+++ test/CodeGenCXX/ubsan-new-checks.cpp
@@ -0,0 +1,114 @@
+// RUN: %clang_cc1 -triple x86_64-linux-gnu -std=c++11 -S -emit-llvm -fsanitize=alignment %s -o - | FileCheck %s
+
+struct alignas(32) S1 {
+  int x;
+  S1();
+};
+
+struct alignas(32) S2 {
+  int x;
+};
+
+struct alignas(32) S3 {
+  int x;
+  S3(int *p = new int[4]);
+};
+
+typedef __attribute__((ext_vector_type(2), aligned(32))) float float32x2_t;
+
+
+void *operator new (unsigned long, void *p) { return p; }
+void *operator new[] (unsigned long, void *p) { return p; }
+
+S1 *func_01() {
+  // CHECK-LABEL: define {{.*}} @_Z7func_01v
+  // CHECK:       and i64 %{{.*}}, 31, !nosanitize
+  // CHECK:       icmp eq i64 %{{.*}}, 0, !nosanitize
+  // CHECK:       call void @_ZN2S1C1Ev(
+  // CHECK-NOT:   and i64 %{{.*}}, 31, !nosanitize
+  // CHECK-NOT:   icmp eq i64 %{{.*}}, 0, !nosanitize
+  return new S1[20];
+}
+
+S2 *func_02() {
+  // CHECK-LABEL: define {{.*}} @_Z7func_02v
+  // CHECK:       and i64 %{{.*}}, 31, !nosanitize
+  // CHECK:       icmp eq i64 %{{.*}}, 0, !nosanitize
+  return new S2;
+}
+
+S2 *func_03() {
+  // CHECK-LABEL: define {{.*}} @_Z7func_03v
+  // CHECK:       and i64 %{{.*}}, 31, !nosanitize
+  // CHECK:       icmp eq i64 %{{.*}}, 0, !nosanitize
+  // CHECK-NOT:   and i64 %{{.*}}, 31, !nosanitize
+  // CHECK-NOT:   icmp eq i64 %{{.*}}, 0, !nosanitize
+  return new S2[20];
+}
+
+float32x2_t *func_04() {
+  // CHECK-LABEL: define {{.*}} @_Z7func_04v
+  // CHECK:       and i64 %{{.*}}, 31, !nosanitize
+  // CHECK:       icmp eq i64 %{{.*}}, 0, !nosanitize
+  return new float32x2_t;
+}
+
+float32x2_t *func_05() {
+  // CHECK-LABEL: define {{.*}} @_Z7func_05v
+  // CHECK:       and i64 %{{.*}}, 31, !nosanitize
+  // CHECK:       icmp eq i64 %{{.*}}, 0, !nosanitize
+  // CHECK-NOT:   and i64 %{{.*}}, 31, !nosanitize
+  // CHECK-NOT:   icmp eq i64 %{{.*}}, 0, !nosanitize
+  return new float32x2_t[20];
+}
+
+S3 *func_07() {
+  // CHECK-LABEL: define {{.*}} @_Z7func_07v
+  // CHECK:       and i64 %{{.*}}, 31, !nosanitize
+  // CHECK:       icmp eq i64 %{{.*}}, 0, !nosanitize
+  // CHECK:       and i64 %{{.*}}, 3, !nosanitize
+  // CHECK:       icmp eq i64 %{{.*}}, 0, !nosanitize
+  return new S3;
+}
+
+S3 *func_08() {
+  // CHECK-LABEL: define {{.*}} @_Z7func_08v
+  // CHECK:       and i64 %{{.*}}, 31, !nosanitize
+  // CHECK:       icmp eq i64 %{{.*}}, 0, !nosanitize
+  // CHECK:       and i64 %{{.*}}, 3, !nosanitize
+  // CHECK:       icmp eq i64 %{{.*}}, 0, !nosanitize
+  return new S3[10];
+}
+
+
+S2 *func_10(void *p) {
+  // CHECK-LABEL: define {{.*}} @_Z7func_10Pv
+  // CHECK:       and i64 %{{.*}}, 31, !nosanitize
+  // CHECK:       icmp eq i64 %{{.*}}, 0, !nosanitize
+  return new(p) S2;
+}
+
+S2 *func_11(void *p) {
+  // CHECK-LABEL: define {{.*}} @_Z7func_11Pv
+  // CHECK:       and i64 %{{.*}}, 31, !nosanitize
+  // CHECK:       icmp eq i64 %{{.*}}, 0, !nosanitize
+  // CHECK-NOT:   and i64 %{{.*}}, 31, !nosanitize
+  // CHECK-NOT:   icmp eq i64 %{{.*}}, 0, !nosanitize
+  return new(p) S2[10];
+}
+
+float32x2_t *func_12() {
+  // CHECK-LABEL: define {{.*}} @_Z7func_12v
+  // CHECK:       and i64 %{{.*}}, 31, !nosanitize
+  // CHECK:       icmp eq i64 %{{.*}}, 0, !nosanitize
+  return new float32x2_t;
+}
+
+float32x2_t *func_13() {
+  // CHECK-LABEL: define {{.*}} @_Z7func_13v
+  // CHECK:       and i64 %{{.*}}, 31, !nosanitize
+  // CHECK:       icmp eq i64 %{{.*}}, 0, !nosanitize
+  // CHECK-NOT:   and i64 %{{.*}}, 31, !nosanitize
+  // CHECK-NOT:   icmp eq i64 %{{.*}}, 0, !nosanitize
+  return new float32x2_t[20];
+}
Index: lib/CodeGen/CodeGenFunction.h
===================================================================
--- lib/CodeGen/CodeGenFunction.h
+++ lib/CodeGen/CodeGenFunction.h
@@ -458,6 +458,23 @@
     ~SanitizerScope();
   };
 
+  /// True if sanitizer checks for the pointer returned by 'new' are generated.
+  bool NewPointerChecksAreEmitted = false;
+
+  /// RAII object to track generation of sanitizer checks for result of 'new'.
+  class NewPointerChecksRAII {
+    CodeGenFunction *CGF;
+    bool PrevValue;
+  public:
+    NewPointerChecksRAII(CodeGenFunction *CGF)
+        : CGF(CGF), PrevValue(CGF->NewPointerChecksAreEmitted) {
+      CGF->NewPointerChecksAreEmitted = true;
+    }
+    ~NewPointerChecksRAII() {
+      CGF->NewPointerChecksAreEmitted = PrevValue;
+    }
+  };
+
   /// In C++, whether we are code generating a thunk.  This controls whether we
   /// should emit cleanups.
   bool CurFuncIsThunk = false;
Index: lib/CodeGen/CGExprCXX.cpp
===================================================================
--- lib/CodeGen/CGExprCXX.cpp
+++ lib/CodeGen/CGExprCXX.cpp
@@ -1271,6 +1271,7 @@
                                Address NewPtr, llvm::Value *NumElements,
                                llvm::Value *AllocSizeWithoutCookie) {
   ApplyDebugLocation DL(CGF, E);
+
   if (E->isArray())
     CGF.EmitNewArrayInitializer(E, ElementType, ElementTy, NewPtr, NumElements,
                                 AllocSizeWithoutCookie);
@@ -1705,6 +1706,13 @@
     result = Address(Builder.CreateLaunderInvariantGroup(result.getPointer()),
                      result.getAlignment());
 
+  // Emit sanitizer checks for pointer value now, so that in the case of an
+  // array it was checked only once and not at each constructor call.
+  NewPointerChecksRAII PC(this);
+  EmitTypeCheck(CodeGenFunction::TCK_ConstructorCall,
+      E->getAllocatedTypeSourceInfo()->getTypeLoc().getBeginLoc(),
+      result.getPointer(), allocType);
+
   EmitNewInitializer(*this, E, allocType, elementTy, result, numElements,
                      allocSizeWithoutCookie);
   if (E->isArray()) {
Index: lib/CodeGen/CGClass.cpp
===================================================================
--- lib/CodeGen/CGClass.cpp
+++ lib/CodeGen/CGClass.cpp
@@ -2068,11 +2068,9 @@
                                              SourceLocation Loc) {
   const CXXRecordDecl *ClassDecl = D->getParent();
 
-  // C++11 [class.mfct.non-static]p2:
-  //   If a non-static member function of a class X is called for an object that
-  //   is not of type X, or of a type derived from X, the behavior is undefined.
-  EmitTypeCheck(CodeGenFunction::TCK_ConstructorCall, Loc,
-                This.getPointer(), getContext().getRecordType(ClassDecl));
+  if (!NewPointerChecksAreEmitted)
+    EmitTypeCheck(CodeGenFunction::TCK_ConstructorCall, Loc, This.getPointer(),
+                  getContext().getRecordType(ClassDecl));
 
   if (D->isTrivial() && D->isDefaultConstructor()) {
     assert(Args.size() == 1 && "trivial default ctor with args");
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to