[PATCH] D29530: [ubsan] Reduce null checking of C++ object pointers (PR27581)

2017-02-16 Thread Phabricator via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
Closed by commit rL295391: [ubsan] Reduce null checking of C++ object pointers 
(PR27581) (authored by vedantk).

Changed prior to commit:
  https://reviews.llvm.org/D29530?vs=88259=88808#toc

Repository:
  rL LLVM

https://reviews.llvm.org/D29530

Files:
  cfe/trunk/lib/CodeGen/CGExpr.cpp
  cfe/trunk/lib/CodeGen/CGExprCXX.cpp
  cfe/trunk/lib/CodeGen/CodeGenFunction.cpp
  cfe/trunk/lib/CodeGen/CodeGenFunction.h
  cfe/trunk/test/CodeGen/catch-undef-behavior.c
  cfe/trunk/test/CodeGen/sanitize-recover.c
  cfe/trunk/test/CodeGenCXX/ubsan-suppress-null-checks.cpp

Index: cfe/trunk/test/CodeGenCXX/ubsan-suppress-null-checks.cpp
===
--- cfe/trunk/test/CodeGenCXX/ubsan-suppress-null-checks.cpp
+++ cfe/trunk/test/CodeGenCXX/ubsan-suppress-null-checks.cpp
@@ -0,0 +1,187 @@
+// RUN: %clang_cc1 -std=c++11 -triple x86_64-apple-darwin10 -emit-llvm -o - %s -fsanitize=null | FileCheck %s
+// RUN: %clang_cc1 -std=c++11 -triple x86_64-apple-darwin10 -emit-llvm -o - %s -fsanitize=null -DCHECK_LAMBDA | FileCheck %s --check-prefix=LAMBDA
+
+struct A {
+  int foo;
+
+  // CHECK-LABEL: define linkonce_odr void @_ZN1A10do_nothingEv
+  void do_nothing() {
+// CHECK: icmp ne %struct.A* %[[THIS1:[a-z0-9]+]], null, !nosanitize
+// CHECK: ptrtoint %struct.A* %[[THIS1]] to i64, !nosanitize
+// CHECK-NEXT: call void @__ubsan_handle_type_mismatch
+// CHECK-NOT: call void @__ubsan_handle_type_mismatch
+// CHECK: ret void
+  }
+
+#ifdef CHECK_LAMBDA
+  // LAMBDA-LABEL: define linkonce_odr void @_ZN1A22do_nothing_with_lambdaEv
+  void do_nothing_with_lambda() {
+// LAMBDA: icmp ne %struct.A* %[[THIS2:[a-z0-9]+]], null, !nosanitize
+// LAMBDA: ptrtoint %struct.A* %[[THIS2]] to i64, !nosanitize
+// LAMBDA-NEXT: call void @__ubsan_handle_type_mismatch
+
+auto f = [&] {
+  foo = 0;
+};
+f();
+
+// LAMBDA: ret void
+  }
+
+// Check the IR for the lambda:
+//
+// LAMBDA-LABEL: define linkonce_odr void @_ZZN1A22do_nothing_with_lambdaEvENKUlvE_clEv
+// LAMBDA: call void @__ubsan_handle_type_mismatch
+// LAMBDA-NOT: call void @__ubsan_handle_type_mismatch
+// LAMBDA: ret void
+#endif
+
+  // CHECK-LABEL: define linkonce_odr i32 @_ZN1A11load_memberEv
+  int load_member() {
+// CHECK: call void @__ubsan_handle_type_mismatch
+// CHECK: L1
+// CHECK-NOT: call void @__ubsan_handle_type_mismatch
+L1:
+return foo;
+// CHECK: ret i32
+  }
+
+  // CHECK-LABEL: define linkonce_odr i32 @_ZN1A11call_methodEv
+  int call_method() {
+// CHECK: call void @__ubsan_handle_type_mismatch
+// CHECK: L2
+// CHECK-NOT: call void @__ubsan_handle_type_mismatch
+L2:
+return load_member();
+// CHECK: ret i32
+  }
+
+  // CHECK-LABEL: define linkonce_odr void @_ZN1A15assign_member_1Ev
+  void assign_member_1() {
+// CHECK: call void @__ubsan_handle_type_mismatch
+// CHECK: L3
+// CHECK-NOT: call void @__ubsan_handle_type_mismatch
+L3:
+foo = 0;
+// CHECK: ret void
+  }
+
+  // CHECK-LABEL: define linkonce_odr void @_ZN1A15assign_member_2Ev
+  void assign_member_2() {
+// CHECK: call void @__ubsan_handle_type_mismatch
+// CHECK: L4
+// CHECK-NOT: call void @__ubsan_handle_type_mismatch
+L4:
+(__extension__ (this))->foo = 0;
+// CHECK: ret void
+  }
+
+  // CHECK-LABEL: define linkonce_odr void @_ZNK1A15assign_member_3Ev
+  void assign_member_3() const {
+// CHECK: call void @__ubsan_handle_type_mismatch
+// CHECK: L5
+// CHECK-NOT: call void @__ubsan_handle_type_mismatch
+L5:
+const_cast(this)->foo = 0;
+// CHECK: ret void
+  }
+
+  // CHECK-LABEL: define linkonce_odr i32 @_ZN1A22call_through_referenceERS_
+  static int call_through_reference(A ) {
+// CHECK-NOT: call void @__ubsan_handle_type_mismatch
+return a.load_member();
+// CHECK: ret i32
+  }
+
+  // CHECK-LABEL: define linkonce_odr i32 @_ZN1A20call_through_pointerEPS_
+  static int call_through_pointer(A *a) {
+// CHECK: call void @__ubsan_handle_type_mismatch
+return a->load_member();
+// CHECK: ret i32
+  }
+};
+
+struct B {
+  operator A*() const { return nullptr; }
+
+  // CHECK-LABEL: define linkonce_odr i32 @_ZN1B11load_memberEv
+  static int load_member() {
+// Null-check  before converting it to an A*.
+// CHECK: call void @__ubsan_handle_type_mismatch
+//
+// Null-check the result of the conversion before using it.
+// CHECK: call void @__ubsan_handle_type_mismatch
+//
+// CHECK-NOT: call void @__ubsan_handle_type_mismatch
+B b;
+return static_cast(b)->load_member();
+// CHECK: ret i32
+  }
+};
+
+struct Base {
+  int foo;
+
+  virtual int load_member_1() = 0;
+};
+
+struct Derived : public Base {
+  int bar;
+
+  // CHECK-LABEL: define linkonce_odr i32 @_ZN7Derived13load_member_2Ev
+  int load_member_2() {
+// CHECK: call void 

[PATCH] D29530: [ubsan] Reduce null checking of C++ object pointers (PR27581)

2017-02-16 Thread Alex Lorenz via Phabricator via cfe-commits
arphaman accepted this revision.
arphaman added a comment.
This revision is now accepted and ready to land.

LGTM


https://reviews.llvm.org/D29530



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D29530: [ubsan] Reduce null checking of C++ object pointers (PR27581)

2017-02-13 Thread Vedant Kumar via Phabricator via cfe-commits
vsk updated this revision to Diff 88259.
vsk marked an inline comment as done.
vsk added a comment.

- Tighten up the tests per Alex's suggestion.


https://reviews.llvm.org/D29530

Files:
  lib/CodeGen/CGExpr.cpp
  lib/CodeGen/CGExprCXX.cpp
  lib/CodeGen/CodeGenFunction.cpp
  lib/CodeGen/CodeGenFunction.h
  test/CodeGen/catch-undef-behavior.c
  test/CodeGen/sanitize-recover.c
  test/CodeGenCXX/ubsan-suppress-null-checks.cpp

Index: test/CodeGenCXX/ubsan-suppress-null-checks.cpp
===
--- /dev/null
+++ test/CodeGenCXX/ubsan-suppress-null-checks.cpp
@@ -0,0 +1,161 @@
+// RUN: %clang_cc1 -std=c++11 -triple x86_64-apple-darwin10 -emit-llvm -o - %s -fsanitize=null | FileCheck %s
+
+struct A {
+  int foo;
+
+  // CHECK-LABEL: define linkonce_odr void @_ZN1A10do_nothingEv
+  void do_nothing() {
+// CHECK: icmp ne %struct.A* %[[THIS1:[a-z0-9]+]], null, !nosanitize
+// CHECK: ptrtoint %struct.A* %[[THIS1]] to i64, !nosanitize
+// CHECK-NEXT: call void @__ubsan_handle_type_mismatch
+// CHECK-NOT: call void @__ubsan_handle_type_mismatch
+  }
+
+  // CHECK-LABEL: define linkonce_odr i32 @_ZN1A11load_memberEv
+  int load_member() {
+// CHECK: icmp ne %struct.A* %[[THIS2:[a-z0-9]+]], null, !nosanitize
+// CHECK: ptrtoint %struct.A* %[[THIS2]] to i64, !nosanitize
+// CHECK-NEXT: call void @__ubsan_handle_type_mismatch
+// CHECK: L1
+// CHECK-NOT: call void @__ubsan_handle_type_mismatch
+L1:
+return foo;
+// CHECK: ret i32
+  }
+
+  // CHECK-LABEL: define linkonce_odr i32 @_ZN1A11call_methodEv
+  int call_method() {
+// CHECK: call void @__ubsan_handle_type_mismatch
+// CHECK: L2
+// CHECK-NOT: call void @__ubsan_handle_type_mismatch
+L2:
+return load_member();
+// CHECK: ret i32
+  }
+
+  // CHECK-LABEL: define linkonce_odr void @_ZN1A15assign_member_1Ev
+  void assign_member_1() {
+// CHECK: call void @__ubsan_handle_type_mismatch
+// CHECK: L3
+// CHECK-NOT: call void @__ubsan_handle_type_mismatch
+L3:
+foo = 0;
+// CHECK: ret void
+  }
+
+  // CHECK-LABEL: define linkonce_odr void @_ZN1A15assign_member_2Ev
+  void assign_member_2() {
+// CHECK: call void @__ubsan_handle_type_mismatch
+// CHECK: L4
+// CHECK-NOT: call void @__ubsan_handle_type_mismatch
+L4:
+(__extension__ (this))->foo = 0;
+// CHECK: ret void
+  }
+
+  // CHECK-LABEL: define linkonce_odr void @_ZNK1A15assign_member_3Ev
+  void assign_member_3() const {
+// CHECK: call void @__ubsan_handle_type_mismatch
+// CHECK: L5
+// CHECK-NOT: call void @__ubsan_handle_type_mismatch
+L5:
+const_cast(this)->foo = 0;
+// CHECK: ret void
+  }
+
+  // CHECK-LABEL: define linkonce_odr i32 @_ZN1A22call_through_referenceERS_
+  static int call_through_reference(A ) {
+// CHECK-NOT: call void @__ubsan_handle_type_mismatch
+return a.load_member();
+// CHECK: ret i32
+  }
+
+  // CHECK-LABEL: define linkonce_odr i32 @_ZN1A20call_through_pointerEPS_
+  static int call_through_pointer(A *a) {
+// CHECK: call void @__ubsan_handle_type_mismatch
+return a->load_member();
+// CHECK: ret i32
+  }
+};
+
+struct B {
+  operator A*() const { return nullptr; }
+
+  // CHECK-LABEL: define linkonce_odr i32 @_ZN1B11load_memberEv
+  static int load_member() {
+// Null-check  before converting it to an A*.
+// CHECK: call void @__ubsan_handle_type_mismatch
+//
+// Null-check the result of the conversion before using it.
+// CHECK: call void @__ubsan_handle_type_mismatch
+//
+// CHECK-NOT: call void @__ubsan_handle_type_mismatch
+B b;
+return static_cast(b)->load_member();
+// CHECK: ret i32
+  }
+};
+
+struct Base {
+  int foo;
+
+  virtual int load_member_1() = 0;
+};
+
+struct Derived : public Base {
+  int bar;
+
+  // CHECK-LABEL: define linkonce_odr i32 @_ZN7Derived13load_member_2Ev
+  int load_member_2() {
+// CHECK: call void @__ubsan_handle_type_mismatch
+// CHECK: L6
+L6:
+// Null-check the result of the cast before using it.
+// CHECK: call void @__ubsan_handle_type_mismatch
+//
+// CHECK-NOT: call void @__ubsan_handle_type_mismatch
+return dynamic_cast(this)->load_member_1();
+// CHECK: ret i32
+  }
+
+  // CHECK-LABEL: define linkonce_odr i32 @_ZN7Derived13load_member_3Ev
+  int load_member_3() {
+// CHECK: call void @__ubsan_handle_type_mismatch
+// CHECK: L7
+// CHECK-NOT: call void @__ubsan_handle_type_mismatch
+L7:
+return reinterpret_cast(static_cast(this))->foo;
+// CHECK: ret i32
+  }
+
+  // CHECK-LABEL: define linkonce_odr i32 @_ZN7Derived13load_member_1Ev
+  int load_member_1() override {
+// CHECK: call void @__ubsan_handle_type_mismatch
+// CHECK: L8
+// CHECK-NOT: call void @__ubsan_handle_type_mismatch
+L8:
+return foo + bar;
+// CHECK: ret i32
+  }
+};
+
+void force_irgen() {
+  A *a;
+  a->do_nothing();
+  a->load_member();
+  a->call_method();

[PATCH] D29530: [ubsan] Reduce null checking of C++ object pointers (PR27581)

2017-02-13 Thread Vedant Kumar via Phabricator via cfe-commits
vsk marked 2 inline comments as done.
vsk added inline comments.



Comment at: test/CodeGenCXX/ubsan-suppress-null-checks.cpp:8
+  int load_member() {
+// CHECK: call void @__ubsan_handle_type_mismatch
+// CHECK-NOT: call void @__ubsan_handle_type_mismatch

arphaman wrote:
> I think this kind of check would've passed even when this patch is not 
> applied. I understand that you need the first check for the single 'this' 
> check, but it should be rewritten to ensure that it couldn't be the check for 
> the `return foo`. Maybe you could use a C label before return and then check 
> that the 'this' check is performed before the label?
Yes, this check should be tighter. This just checks that the number of checks 
in the method goes from 2 to 1. The label idea is great.


https://reviews.llvm.org/D29530



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D29530: [ubsan] Reduce null checking of C++ object pointers (PR27581)

2017-02-13 Thread Alex Lorenz via Phabricator via cfe-commits
arphaman added inline comments.



Comment at: test/CodeGenCXX/ubsan-suppress-null-checks.cpp:8
+  int load_member() {
+// CHECK: call void @__ubsan_handle_type_mismatch
+// CHECK-NOT: call void @__ubsan_handle_type_mismatch

I think this kind of check would've passed even when this patch is not applied. 
I understand that you need the first check for the single 'this' check, but it 
should be rewritten to ensure that it couldn't be the check for the `return 
foo`. Maybe you could use a C label before return and then check that the 
'this' check is performed before the label?


https://reviews.llvm.org/D29530



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D29530: [ubsan] Reduce null checking of C++ object pointers (PR27581)

2017-02-10 Thread Vedant Kumar via Phabricator via cfe-commits
vsk updated this revision to Diff 88075.
vsk edited the summary of this revision.
vsk added a reviewer: arphaman.
vsk added a comment.

- Check 'this' once per method. This supports the partial sanitization use-case.
- Flesh out the predicate for avoiding null checks on object pointers. I 
couldn't use isImplicitCXXThis like I'd wanted, because we'd like to catch 
explicit this exprs as well.


https://reviews.llvm.org/D29530

Files:
  lib/CodeGen/CGExpr.cpp
  lib/CodeGen/CGExprCXX.cpp
  lib/CodeGen/CodeGenFunction.cpp
  lib/CodeGen/CodeGenFunction.h
  test/CodeGen/catch-undef-behavior.c
  test/CodeGen/sanitize-recover.c
  test/CodeGenCXX/ubsan-suppress-null-checks.cpp

Index: test/CodeGenCXX/ubsan-suppress-null-checks.cpp
===
--- /dev/null
+++ test/CodeGenCXX/ubsan-suppress-null-checks.cpp
@@ -0,0 +1,135 @@
+// RUN: %clang_cc1 -std=c++11 -triple x86_64-apple-darwin10 -emit-llvm -o - %s -fsanitize=null | FileCheck %s
+
+struct A {
+  int foo;
+
+  // CHECK-LABEL: define linkonce_odr i32 @_ZN1A11load_memberEv
+  int load_member() {
+// CHECK: call void @__ubsan_handle_type_mismatch
+// CHECK-NOT: call void @__ubsan_handle_type_mismatch
+return foo;
+// CHECK: ret i32
+  }
+
+  // CHECK-LABEL: define linkonce_odr i32 @_ZN1A11call_methodEv
+  int call_method() {
+// CHECK: call void @__ubsan_handle_type_mismatch
+// CHECK-NOT: call void @__ubsan_handle_type_mismatch
+return load_member();
+// CHECK: ret i32
+  }
+
+  // CHECK-LABEL: define linkonce_odr void @_ZN1A15assign_member_1Ev
+  void assign_member_1() {
+// CHECK: call void @__ubsan_handle_type_mismatch
+// CHECK-NOT: call void @__ubsan_handle_type_mismatch
+foo = 0;
+// CHECK: ret void
+  }
+
+  // CHECK-LABEL: define linkonce_odr void @_ZN1A15assign_member_2Ev
+  void assign_member_2() {
+// CHECK: call void @__ubsan_handle_type_mismatch
+// CHECK-NOT: call void @__ubsan_handle_type_mismatch
+(__extension__ (this))->foo = 0;
+// CHECK: ret void
+  }
+
+  // CHECK-LABEL: define linkonce_odr void @_ZNK1A15assign_member_3Ev
+  void assign_member_3() const {
+// CHECK: call void @__ubsan_handle_type_mismatch
+// CHECK-NOT: call void @__ubsan_handle_type_mismatch
+const_cast(this)->foo = 0;
+// CHECK: ret void
+  }
+
+  // CHECK-LABEL: define linkonce_odr i32 @_ZN1A22call_through_referenceERS_
+  static int call_through_reference(A ) {
+// CHECK-NOT: call void @__ubsan_handle_type_mismatch
+return a.load_member();
+// CHECK: ret i32
+  }
+
+  // CHECK-LABEL: define linkonce_odr i32 @_ZN1A20call_through_pointerEPS_
+  static int call_through_pointer(A *a) {
+// CHECK: call void @__ubsan_handle_type_mismatch
+return a->load_member();
+// CHECK: ret i32
+  }
+};
+
+struct B {
+  operator A*() const { return nullptr; }
+
+  // CHECK-LABEL: define linkonce_odr i32 @_ZN1B11load_memberEv
+  static int load_member() {
+// Null-check  before converting it to an A*.
+// CHECK: call void @__ubsan_handle_type_mismatch
+//
+// Null-check the result of the conversion before using it.
+// CHECK: call void @__ubsan_handle_type_mismatch
+//
+// CHECK-NOT: call void @__ubsan_handle_type_mismatch
+B b;
+return static_cast(b)->load_member();
+// CHECK: ret i32
+  }
+};
+
+struct Base {
+  int foo;
+
+  virtual int load_member_1() = 0;
+};
+
+struct Derived : public Base {
+  int bar;
+
+  // CHECK-LABEL: define linkonce_odr i32 @_ZN7Derived13load_member_2Ev
+  int load_member_2() {
+// CHECK: call void @__ubsan_handle_type_mismatch
+//
+// Null-check the result of the cast before using it.
+// CHECK: call void @__ubsan_handle_type_mismatch
+//
+// CHECK-NOT: call void @__ubsan_handle_type_mismatch
+return dynamic_cast(this)->load_member_1();
+// CHECK: ret i32
+  }
+
+  // CHECK-LABEL: define linkonce_odr i32 @_ZN7Derived13load_member_3Ev
+  int load_member_3() {
+// CHECK: call void @__ubsan_handle_type_mismatch
+// CHECK-NOT: call void @__ubsan_handle_type_mismatch
+return reinterpret_cast(static_cast(this))->foo;
+// CHECK: ret i32
+  }
+
+  // CHECK-LABEL: define linkonce_odr i32 @_ZN7Derived13load_member_1Ev
+  int load_member_1() override {
+// CHECK: call void @__ubsan_handle_type_mismatch
+// CHECK-NOT: call void @__ubsan_handle_type_mismatch
+return foo + bar;
+// CHECK: ret i32
+  }
+};
+
+void force_irgen() {
+  A *a;
+  a->load_member();
+  a->call_method();
+  a->assign_member_1();
+  a->assign_member_2();
+  a->assign_member_3();
+  A::call_through_reference(*a);
+  A::call_through_pointer(a);
+
+  B::load_member();
+
+  Base *b = new Derived;
+  b->load_member_1();
+
+  Derived *d;
+  d->load_member_2();
+  d->load_member_3();
+}
Index: test/CodeGen/sanitize-recover.c
===
--- test/CodeGen/sanitize-recover.c
+++ 

[PATCH] D29530: [ubsan] Reduce null checking of C++ object pointers (PR27581)

2017-02-10 Thread Vedant Kumar via Phabricator via cfe-commits
vsk added a comment.

Ah, I did miss ParenExpr. Maybe it would be better to use 
Expr::isImplicitCXXThis, since it handles this case and some more. Later, we 
can go back and see if it's feasible to handle static/const casts in 
isImplicitCXXThis to catch more cases.

In https://reviews.llvm.org/D29530#671816, @arphaman wrote:

> Btw, you mentioned that 'this' must have been null-checked before the method 
> is called. But what if it's called from some part of code that was compiled 
> without `-fsanitize=null`? Wouldn't we still want at least one check to see 
> if 'this' is null in a method?


That's fair, I think that would address the concerns about the partial 
sanitization use case brought up in the original PR.


https://reviews.llvm.org/D29530



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D29530: [ubsan] Reduce null checking of C++ object pointers (PR27581)

2017-02-09 Thread Alex Lorenz via Phabricator via cfe-commits
arphaman added a comment.

Btw, you mentioned that 'this' must have been null-checked before the method is 
called. But what if it's called from some part of code that was compiled 
without `-fsanitize=null`? Wouldn't we still want at least one check to see if 
'this' is null in a method?


https://reviews.llvm.org/D29530



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D29530: [ubsan] Reduce null checking of C++ object pointers (PR27581)

2017-02-09 Thread Alex Lorenz via Phabricator via cfe-commits
arphaman added a comment.

Thanks!

I guess for the sake of completeness it might be useful for handle 'this' in 
parens as well, since it could up in macros:

  #define MEMBER(x) (x)->y
  ...
  MEMBER(this)
  ...

Btw, I was curious if we could do a similar optimization in Objective-C, but 
'self' can be set to null there inside the body of a method. I guess maybe it 
would be possible to avoid the null check on self if we can prove it wasn't 
modified, but that's out of scope of this patch.




Comment at: lib/CodeGen/CGExprCXX.cpp:294
+  bool SkipNullCheck = false;
+  if (const auto *CMCE = dyn_cast(CE)) {
+SkipNullCheck =

You can avoid the '{' '}' here.


https://reviews.llvm.org/D29530



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D29530: [ubsan] Reduce null checking of C++ object pointers (PR27581)

2017-02-06 Thread Vedant Kumar via Phabricator via cfe-commits
vsk updated this revision to Diff 87334.
vsk edited the summary of this revision.
vsk added a comment.

@arphaman thank you for the feedback!

Per Alex's comments:

- Add test for explicit use of the 'this' pointer.
- Handle cases where the 'this' pointer may be casted (implicitly, or 
otherwise).

We're able to eliminate more null checks with this version of the patch. See 
the updated patch summary for the X86FastISel.cpp numbers.


https://reviews.llvm.org/D29530

Files:
  lib/CodeGen/CGExpr.cpp
  lib/CodeGen/CGExprCXX.cpp
  lib/CodeGen/CodeGenFunction.h
  test/CodeGen/catch-undef-behavior.c
  test/CodeGen/sanitize-recover.c
  test/CodeGenCXX/ubsan-suppress-null-checks.cpp

Index: test/CodeGenCXX/ubsan-suppress-null-checks.cpp
===
--- /dev/null
+++ test/CodeGenCXX/ubsan-suppress-null-checks.cpp
@@ -0,0 +1,126 @@
+// RUN: %clang_cc1 -std=c++11 -triple x86_64-apple-darwin10 -emit-llvm -o - %s -fsanitize=null | FileCheck %s
+
+struct A {
+  int foo;
+
+  // CHECK-LABEL: define linkonce_odr i32 @_ZN1A11load_memberEv
+  int load_member() {
+// CHECK-NOT: call void @__ubsan_handle_type_mismatch
+return foo;
+// CHECK: ret i32
+  }
+
+  // CHECK-LABEL: define linkonce_odr i32 @_ZN1A11call_methodEv
+  int call_method() {
+// CHECK-NOT: call void @__ubsan_handle_type_mismatch
+return load_member();
+// CHECK: ret i32
+  }
+
+  // CHECK-LABEL: define linkonce_odr void @_ZN1A15assign_member_1Ev
+  void assign_member_1() {
+// CHECK-NOT: call void @__ubsan_handle_type_mismatch
+foo = 0;
+// CHECK: ret void
+  }
+
+  // CHECK-LABEL: define linkonce_odr void @_ZN1A15assign_member_2Ev
+  void assign_member_2() {
+// CHECK-NOT: call void @__ubsan_handle_type_mismatch
+this->foo = 0;
+// CHECK: ret void
+  }
+
+  // CHECK-LABEL: define linkonce_odr void @_ZNK1A15assign_member_3Ev
+  void assign_member_3() const {
+// CHECK-NOT: call void @__ubsan_handle_type_mismatch
+const_cast(this)->foo = 0;
+// CHECK: ret void
+  }
+
+  // CHECK-LABEL: define linkonce_odr i32 @_ZN1A22call_through_referenceERS_
+  static int call_through_reference(A ) {
+// CHECK-NOT: call void @__ubsan_handle_type_mismatch
+return a.load_member();
+// CHECK: ret i32
+  }
+
+  // CHECK-LABEL: define linkonce_odr i32 @_ZN1A20call_through_pointerEPS_
+  static int call_through_pointer(A *a) {
+// CHECK: call void @__ubsan_handle_type_mismatch
+return a->load_member();
+// CHECK: ret i32
+  }
+};
+
+struct B {
+  operator A*() const { return nullptr; }
+
+  // CHECK-LABEL: define linkonce_odr i32 @_ZN1B11load_memberEv
+  static int load_member() {
+// Null-check  before converting it to an A*.
+// CHECK: call void @__ubsan_handle_type_mismatch
+//
+// Null-check the result of the conversion before using it.
+// CHECK: call void @__ubsan_handle_type_mismatch
+//
+// CHECK-NOT: call void @__ubsan_handle_type_mismatch
+B b;
+return static_cast(b)->load_member();
+// CHECK: ret i32
+  }
+};
+
+struct Base {
+  int foo;
+
+  virtual int load_member_1() = 0;
+};
+
+struct Derived : public Base {
+  int bar;
+
+  // CHECK-LABEL: define linkonce_odr i32 @_ZN7Derived13load_member_2Ev
+  int load_member_2() {
+// Null-check the result of the cast before using it.
+// CHECK: call void @__ubsan_handle_type_mismatch
+//
+// CHECK-NOT: call void @__ubsan_handle_type_mismatch
+return dynamic_cast(this)->load_member_1();
+// CHECK: ret i32
+  }
+
+  // CHECK-LABEL: define linkonce_odr i32 @_ZN7Derived13load_member_3Ev
+  int load_member_3() {
+// CHECK-NOT: call void @__ubsan_handle_type_mismatch
+return reinterpret_cast(static_cast(this))->foo;
+// CHECK: ret i32
+  }
+
+  // CHECK-LABEL: define linkonce_odr i32 @_ZN7Derived13load_member_1Ev
+  int load_member_1() override {
+// CHECK-NOT: call void @__ubsan_handle_type_mismatch
+return foo + bar;
+// CHECK: ret i32
+  }
+};
+
+void force_irgen() {
+  A *a;
+  a->load_member();
+  a->call_method();
+  a->assign_member_1();
+  a->assign_member_2();
+  a->assign_member_3();
+  A::call_through_reference(*a);
+  A::call_through_pointer(a);
+
+  B::load_member();
+
+  Base *b = new Derived;
+  b->load_member_1();
+
+  Derived *d;
+  d->load_member_2();
+  d->load_member_3();
+}
Index: test/CodeGen/sanitize-recover.c
===
--- test/CodeGen/sanitize-recover.c
+++ test/CodeGen/sanitize-recover.c
@@ -19,20 +19,17 @@
 void foo() {
   union { int i; } u;
   u.i=1;
-  // PARTIAL:  %[[CHECK0:.*]] = icmp ne {{.*}}* %[[PTR:.*]], null
-
   // PARTIAL:  %[[SIZE:.*]] = call i64 @llvm.objectsize.i64.p0i8(i8* {{.*}}, i1 false)
-  // PARTIAL-NEXT: %[[CHECK1:.*]] = icmp uge i64 %[[SIZE]], 4
+  // PARTIAL-NEXT: %[[CHECK0:.*]] = icmp uge i64 %[[SIZE]], 4
 
   // PARTIAL:  %[[MISALIGN:.*]] = and i64 {{.*}}, 3
-  // PARTIAL-NEXT: 

[PATCH] D29530: [ubsan] Reduce null checking of C++ object pointers (PR27581)

2017-02-06 Thread Alex Lorenz via Phabricator via cfe-commits
arphaman added a comment.

I feel like you should have at least one statement in the test that uses 
explicit 'this' to access a field/method.

Does your patch handle fields/methods in base classes as well? I think 'this' 
might be implicitly converted in the base of the member expression.

Also, what about cases like this one:

  struct A {
int x;
  
void methodNotConst() const {
  const_cast(this)->x = 0;
}
  };




https://reviews.llvm.org/D29530



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D29530: [ubsan] Reduce null checking of C++ object pointers (PR27581)

2017-02-03 Thread Vedant Kumar via Phabricator via cfe-commits
vsk created this revision.

Given a load of a member variable from an instance method ('this->x'),
ubsan inserts a null check for 'this', and another null check for
'>x', before allowing the load to occur. Both of these checks are
redundant, because 'this' must have been null-checked before the method
is called.

Similarly, given a call to a method from another method bound to the
same instance ('this->foo()'), ubsan inserts a redundant null check for
'this'. There is also a redundant null check in the case where the
object pointer is a reference ('Ref.foo()').

This patch teaches ubsan to remove the redundant null checks identified
above. I'm not sure I've gone about this in the way suggested in PR27581,
and would appreciate any advice/corrections.

Testing: check-clang and check-ubsan. I also compiled X86FastISel.cpp
with -fsanitize=null using patched/unpatched clangs based on r293572.
Here are the number of null checks emitted in various setups:

| Setup  | # of null checks |
| unpatched, -O0 | 21767|
| unpatched, -O3 | 11862|
| patched, -O0   | 13178|
| patched, -O3   | 5547 |


https://reviews.llvm.org/D29530

Files:
  lib/CodeGen/CGExpr.cpp
  lib/CodeGen/CGExprCXX.cpp
  test/CodeGenCXX/ubsan-suppress-null-checks.cpp


Index: test/CodeGenCXX/ubsan-suppress-null-checks.cpp
===
--- /dev/null
+++ test/CodeGenCXX/ubsan-suppress-null-checks.cpp
@@ -0,0 +1,38 @@
+// RUN: %clang_cc1 -std=c++11 -triple x86_64-apple-darwin10 -emit-llvm -o - %s 
-fsanitize=null | FileCheck %s
+
+struct A {
+  int foo;
+
+  // CHECK-LABEL: define linkonce_odr i32 @_ZN1A5func1Ev
+  int func1() {
+// CHECK-NOT: ubsan_handler_type_mismatch
+return foo;
+  }
+
+  // CHECK-LABEL: define linkonce_odr i32 @_ZN1A5func2Ev
+  int func2() {
+// CHECK-NOT: ubsan_handler_type_mismatch
+return func1();
+  }
+
+  // CHECK-LABEL: define linkonce_odr void @_ZN1A5func3Ev
+  void func3() {
+// CHECK-NOT: ubsan_handler_type_mismatch
+foo = 0;
+  }
+
+  // CHECK-LABEL: define linkonce_odr i32 @_ZN1A5func4ERS_
+  static int func4(A ) {
+// CHECK-NOT: ubsan_handler_type_mismatch
+return a.func1();
+  }
+};
+
+// Force clang to emit IR for A's methods.
+void bar() {
+  A *a;
+  a->func1();
+  a->func2();
+  a->func3();
+  A::func4(*a);
+}
Index: lib/CodeGen/CGExprCXX.cpp
===
--- lib/CodeGen/CGExprCXX.cpp
+++ lib/CodeGen/CGExprCXX.cpp
@@ -290,10 +290,16 @@
   if (CE)
 CallLoc = CE->getExprLoc();
 
-  EmitTypeCheck(isa(CalleeDecl)
-? CodeGenFunction::TCK_ConstructorCall
-: CodeGenFunction::TCK_MemberCall,
-CallLoc, This.getPointer(), 
C.getRecordType(CalleeDecl->getParent()));
+  bool SkipNullCheck = false;
+  if (const auto *CMCE = dyn_cast(CE)) {
+Expr *IOA = CMCE->getImplicitObjectArgument();
+SkipNullCheck = isa(IOA) || isa(IOA);
+  }
+  EmitTypeCheck(
+  isa(CalleeDecl) ? 
CodeGenFunction::TCK_ConstructorCall
+  : CodeGenFunction::TCK_MemberCall,
+  CallLoc, This.getPointer(), C.getRecordType(CalleeDecl->getParent()),
+  /*Alignment=*/CharUnits::Zero(), SkipNullCheck);
 
   // FIXME: Uses of 'MD' past this point need to be audited. We may need to use
   // 'CalleeDecl' instead.
Index: lib/CodeGen/CGExpr.cpp
===
--- lib/CodeGen/CGExpr.cpp
+++ lib/CodeGen/CGExpr.cpp
@@ -953,9 +953,13 @@
 LV = EmitArraySubscriptExpr(cast(E), /*Accessed*/true);
   else
 LV = EmitLValue(E);
-  if (!isa(E) && !LV.isBitField() && LV.isSimple())
+  if (!isa(E) && !LV.isBitField() && LV.isSimple()) {
+bool SkipNullCheck = false;
+if (const auto *ME = dyn_cast(E))
+  SkipNullCheck = isa(ME->getBase());
 EmitTypeCheck(TCK, E->getExprLoc(), LV.getPointer(),
-  E->getType(), LV.getAlignment());
+  E->getType(), LV.getAlignment(), SkipNullCheck);
+  }
   return LV;
 }
 
@@ -3335,7 +3339,9 @@
 AlignmentSource AlignSource;
 Address Addr = EmitPointerWithAlignment(BaseExpr, );
 QualType PtrTy = BaseExpr->getType()->getPointeeType();
-EmitTypeCheck(TCK_MemberAccess, E->getExprLoc(), Addr.getPointer(), PtrTy);
+bool SkipNullCheck = isa(BaseExpr);
+EmitTypeCheck(TCK_MemberAccess, E->getExprLoc(), Addr.getPointer(), PtrTy,
+  /*Alignment=*/CharUnits::Zero(), SkipNullCheck);
 BaseLV = MakeAddrLValue(Addr, PtrTy, AlignSource);
   } else
 BaseLV = EmitCheckedLValue(BaseExpr, TCK_MemberAccess);


Index: test/CodeGenCXX/ubsan-suppress-null-checks.cpp
===
--- /dev/null
+++ test/CodeGenCXX/ubsan-suppress-null-checks.cpp
@@ -0,0 +1,38 @@
+// RUN: %clang_cc1 -std=c++11 -triple x86_64-apple-darwin10 -emit-llvm -o - %s -fsanitize=null | FileCheck