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
[email protected]
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits