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

Updated patch

Now the information, if the pointer produced by 'new' operator is checked,
is stored in objects used for pointer representation (`Address` and
`AggValueSlot`) rather than globally.

Also the tests were cleaned up a bit.


Repository:
  rC Clang

https://reviews.llvm.org/D49589

Files:
  lib/CodeGen/Address.h
  lib/CodeGen/CGClass.cpp
  lib/CodeGen/CGExprCXX.cpp
  lib/CodeGen/CGValue.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,146 @@
+// 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]);
+};
+
+struct S4 : public S3 {
+  S4() : S3() {}
+};
+
+typedef __attribute__((ext_vector_type(2), aligned(32))) float float32x2_t;
+
+struct S5 {
+  float32x2_t x;
+};
+
+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
+  // CHECK:       ret %struct.S1*
+  return new S1[20];
+}
+
+S2 *func_02() {
+  // CHECK-LABEL: define {{.*}} @_Z7func_02v
+  // CHECK:       and i64 %{{.*}}, 31, !nosanitize
+  // CHECK:       icmp eq i64 %{{.*}}, 0, !nosanitize
+  // CHECK:       ret %struct.S2*
+  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
+  // CHECK:       ret %struct.S2*
+  return new S2[20];
+}
+
+float32x2_t *func_04() {
+  // CHECK-LABEL: define {{.*}} @_Z7func_04v
+  // CHECK:       and i64 %{{.*}}, 31, !nosanitize
+  // CHECK:       icmp eq i64 %{{.*}}, 0, !nosanitize
+  // CHECK:       ret <2 x float>*
+  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
+  // CHECK:       ret <2 x float>*
+  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
+  // CHECK:       ret %struct.S3*
+  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
+  // CHECK:       ret %struct.S3*
+  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
+  // CHECK:       ret %struct.S2*
+  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
+  // CHECK:       ret %struct.S2*
+  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
+  // CHECK:       ret <2 x float>*
+  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
+  // CHECK:       ret <2 x float>*
+  return new float32x2_t[20];
+}
+
+S4 *func_14() {
+  // CHECK-LABEL: define {{.*}} @_Z7func_14v
+  // CHECK:       and i64 %{{.*}}, 31, !nosanitize
+  // CHECK:       icmp eq i64 %{{.*}}, 0, !nosanitize
+  // CHECK-NOT:   and i64 %{{.*}}, 31
+  // CHECK:       ret %struct.S4*
+  return new S4;
+}
+
+S5 *func_15(const S5 *ptr) {
+  // CHECK-LABEL: define {{.*}} @_Z7func_15PK2S5
+  // CHECK:       and i64 %{{.*}}, 31, !nosanitize
+  // CHECK:       icmp eq i64 %{{.*}}, 0, !nosanitize
+  // CHECK-NOT:   and i64
+  // CHECK:       ret %struct.S5*
+  return new S5(*ptr);
+}
Index: lib/CodeGen/CGValue.h
===================================================================
--- lib/CodeGen/CGValue.h
+++ lib/CodeGen/CGValue.h
@@ -479,12 +479,20 @@
   /// the size of the type.
   bool OverlapFlag : 1;
 
+  /// If is set to true, sanitizer checks are already generated for this address
+  /// or not required. For instance, if this address represents an object
+  /// created in 'new' expression, sanitizer checks for memory is made as a part
+  /// of 'operator new' emission and object constructor should not generate
+  /// them.
+  bool CheckedFlag : 1;
+
 public:
   enum IsAliased_t { IsNotAliased, IsAliased };
   enum IsDestructed_t { IsNotDestructed, IsDestructed };
   enum IsZeroed_t { IsNotZeroed, IsZeroed };
   enum Overlap_t { DoesNotOverlap, MayOverlap };
   enum NeedsGCBarriers_t { DoesNotNeedGCBarriers, NeedsGCBarriers };
+  enum IsChecked_t { IsNotChecked, IsChecked };
 
   /// ignored - Returns an aggregate value slot indicating that the
   /// aggregate value is being ignored.
@@ -524,6 +532,7 @@
     AV.ZeroedFlag = isZeroed;
     AV.AliasedFlag = isAliased;
     AV.OverlapFlag = mayOverlap;
+    AV.CheckedFlag = addr.isChecked();
     return AV;
   }
 
@@ -567,7 +576,7 @@
   }
 
   Address getAddress() const {
-    return Address(Addr, getAlignment());
+    return Address(Addr, getAlignment(), isChecked());
   }
 
   bool isIgnored() const {
@@ -586,6 +595,14 @@
     return Overlap_t(OverlapFlag);
   }
 
+  bool isChecked() const {
+    return CheckedFlag;
+  }
+
+  static IsChecked_t getCheckedFlag(bool x) {
+    return static_cast<AggValueSlot::IsChecked_t>(x);
+  }
+
   RValue asRValue() const {
     if (isIgnored()) {
       return RValue::getIgnored();
Index: lib/CodeGen/CGExprCXX.cpp
===================================================================
--- lib/CodeGen/CGExprCXX.cpp
+++ lib/CodeGen/CGExprCXX.cpp
@@ -1705,6 +1705,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.
+  EmitTypeCheck(CodeGenFunction::TCK_ConstructorCall,
+      E->getAllocatedTypeSourceInfo()->getTypeLoc().getBeginLoc(),
+      result.getPointer(), allocType);
+  result = Address(result.getPointer(), result.getAlignment(), true);
+
   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 (!This.isChecked())
+    EmitTypeCheck(CodeGenFunction::TCK_ConstructorCall, Loc, This.getPointer(),
+                  getContext().getRecordType(ClassDecl));
 
   if (D->isTrivial() && D->isDefaultConstructor()) {
     assert(Args.size() == 1 && "trivial default ctor with args");
Index: lib/CodeGen/Address.h
===================================================================
--- lib/CodeGen/Address.h
+++ lib/CodeGen/Address.h
@@ -25,21 +25,26 @@
 class Address {
   llvm::Value *Pointer;
   CharUnits Alignment;
+  bool IsChecked;
 public:
-  Address(llvm::Value *pointer, CharUnits alignment)
-      : Pointer(pointer), Alignment(alignment) {
+  Address(llvm::Value *pointer, CharUnits alignment, bool Checked = false)
+      : Pointer(pointer), Alignment(alignment), IsChecked(Checked) {
     assert((!alignment.isZero() || pointer == nullptr) &&
            "creating valid address with invalid alignment");
   }
 
-  static Address invalid() { return Address(nullptr, CharUnits()); }
+  static Address invalid() { return Address(nullptr, CharUnits(), false); }
   bool isValid() const { return Pointer != nullptr; }
 
   llvm::Value *getPointer() const {
     assert(isValid());
     return Pointer;
   }
 
+  bool isChecked() const {
+    return IsChecked;
+  }
+
   /// Return the type of the pointer value.
   llvm::PointerType *getType() const {
     return llvm::cast<llvm::PointerType>(getPointer()->getType());
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to