aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorJakub Jelinek <jakub@redhat.com>2018-01-03 21:37:41 +0100
committerJakub Jelinek <jakub@gcc.gnu.org>2018-01-03 21:37:41 +0100
commit830421fcd37719426fa8eb7f0d545c744db497b4 (patch)
tree4caa4cc0a2b0794c69cc3be5c592273f1dbcc26b /gcc
parent8bdbeed1d0b00bc21a105712b1b672ebec37358e (diff)
downloadgcc-830421fcd37719426fa8eb7f0d545c744db497b4.zip
gcc-830421fcd37719426fa8eb7f0d545c744db497b4.tar.gz
gcc-830421fcd37719426fa8eb7f0d545c744db497b4.tar.bz2
re PR c++/83555 (Unnecessary null check when static_cast is used with references.)
PR c++/83555 * typeck.c (build_static_cast_1): For static casts to reference types, call build_base_path with flag_delete_null_pointer_checks as nonnull instead of always false. When -fsanitize=null, call ubsan_maybe_instrument_reference on the NULL reference INTEGER_CST. * cp-gimplify.c (cp_genericize_r): Don't walk subtrees of UBSAN_NULL call if the first argument is INTEGER_CST with REFERENCE_TYPE. * g++.dg/opt/pr83555.C: New test. * g++.dg/ubsan/pr83555.C: New test. From-SVN: r256186
Diffstat (limited to 'gcc')
-rw-r--r--gcc/cp/ChangeLog10
-rw-r--r--gcc/cp/cp-gimplify.c6
-rw-r--r--gcc/cp/typeck.c20
-rw-r--r--gcc/testsuite/ChangeLog6
-rw-r--r--gcc/testsuite/g++.dg/opt/pr83555.C15
-rw-r--r--gcc/testsuite/g++.dg/ubsan/pr83555.C40
6 files changed, 94 insertions, 3 deletions
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index 4f8f839..959f412 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -1,3 +1,13 @@
+2018-01-03 Jakub Jelinek <jakub@redhat.com>
+
+ PR c++/83555
+ * typeck.c (build_static_cast_1): For static casts to reference types,
+ call build_base_path with flag_delete_null_pointer_checks as nonnull
+ instead of always false. When -fsanitize=null, call
+ ubsan_maybe_instrument_reference on the NULL reference INTEGER_CST.
+ * cp-gimplify.c (cp_genericize_r): Don't walk subtrees of UBSAN_NULL
+ call if the first argument is INTEGER_CST with REFERENCE_TYPE.
+
2018-01-03 Nathan Sidwell <nathan@acm.org>
PR c++/83667
diff --git a/gcc/cp/cp-gimplify.c b/gcc/cp/cp-gimplify.c
index c090ee7..eda493a 100644
--- a/gcc/cp/cp-gimplify.c
+++ b/gcc/cp/cp-gimplify.c
@@ -1506,6 +1506,12 @@ cp_genericize_r (tree *stmt_p, int *walk_subtrees, void *data)
if (sanitize_flags_p (SANITIZE_VPTR) && !is_ctor)
cp_ubsan_maybe_instrument_member_call (stmt);
}
+ else if (fn == NULL_TREE
+ && CALL_EXPR_IFN (stmt) == IFN_UBSAN_NULL
+ && TREE_CODE (CALL_EXPR_ARG (stmt, 0)) == INTEGER_CST
+ && (TREE_CODE (TREE_TYPE (CALL_EXPR_ARG (stmt, 0)))
+ == REFERENCE_TYPE))
+ *walk_subtrees = 0;
}
break;
diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c
index ccbef1d..76fd930 100644
--- a/gcc/cp/typeck.c
+++ b/gcc/cp/typeck.c
@@ -6943,8 +6943,11 @@ build_static_cast_1 (tree type, tree expr, bool c_cast_p,
}
/* Convert from "B*" to "D*". This function will check that "B"
- is not a virtual base of "D". */
- expr = build_base_path (MINUS_EXPR, expr, base, /*nonnull=*/false,
+ is not a virtual base of "D". Even if we don't have a guarantee
+ that expr is NULL, if the static_cast is to a reference type,
+ it is UB if it would be NULL, so omit the non-NULL check. */
+ expr = build_base_path (MINUS_EXPR, expr, base,
+ /*nonnull=*/flag_delete_null_pointer_checks,
complain);
/* Convert the pointer to a reference -- but then remember that
@@ -6955,7 +6958,18 @@ build_static_cast_1 (tree type, tree expr, bool c_cast_p,
is a variable with the same type, the conversion would get folded
away, leaving just the variable and causing lvalue_kind to give
the wrong answer. */
- return convert_from_reference (rvalue (cp_fold_convert (type, expr)));
+ expr = cp_fold_convert (type, expr);
+
+ /* When -fsanitize=null, make sure to diagnose reference binding to
+ NULL even when the reference is converted to pointer later on. */
+ if (sanitize_flags_p (SANITIZE_NULL)
+ && TREE_CODE (expr) == COND_EXPR
+ && TREE_OPERAND (expr, 2)
+ && TREE_CODE (TREE_OPERAND (expr, 2)) == INTEGER_CST
+ && TREE_TYPE (TREE_OPERAND (expr, 2)) == type)
+ ubsan_maybe_instrument_reference (&TREE_OPERAND (expr, 2));
+
+ return convert_from_reference (rvalue (expr));
}
/* "A glvalue of type cv1 T1 can be cast to type rvalue reference to
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index 503a839..7c4e6e9 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,9 @@
+2018-01-03 Jakub Jelinek <jakub@redhat.com>
+
+ PR c++/83555
+ * g++.dg/opt/pr83555.C: New test.
+ * g++.dg/ubsan/pr83555.C: New test.
+
2018-01-03 David Malcolm <dmalcolm@redhat.com>
PR c/82050
diff --git a/gcc/testsuite/g++.dg/opt/pr83555.C b/gcc/testsuite/g++.dg/opt/pr83555.C
new file mode 100644
index 0000000..c6f810d
--- /dev/null
+++ b/gcc/testsuite/g++.dg/opt/pr83555.C
@@ -0,0 +1,15 @@
+// PR c++/83555
+// { dg-do compile }
+// { dg-options "-O2 -fdump-tree-optimized -fdelete-null-pointer-checks" }
+
+struct A { int a; };
+struct B { int b; };
+struct C : A, B { int c; };
+
+C *
+foo (B *b)
+{
+ return &static_cast<C &>(*b);
+}
+
+// { dg-final { scan-tree-dump-not "if \\(b_\[0-9]*\\(D\\) .= 0" "optimized" } }
diff --git a/gcc/testsuite/g++.dg/ubsan/pr83555.C b/gcc/testsuite/g++.dg/ubsan/pr83555.C
new file mode 100644
index 0000000..6574923
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ubsan/pr83555.C
@@ -0,0 +1,40 @@
+// PR c++/83555
+// { dg-do run }
+// { dg-options "-fsanitize=null" }
+// { dg-output ":25:\[^\n\r]*reference binding to null pointer of type 'struct C'" }
+
+struct A { int a; };
+struct B { int b; };
+struct C : A, B { int c; };
+
+__attribute__((noipa)) C *
+foo (B *b)
+{
+ return static_cast<C *>(b);
+}
+
+__attribute__((noipa)) C *
+bar (B *b)
+{
+ return &static_cast<C &>(*b);
+}
+
+__attribute__((noipa)) C *
+baz (B *b)
+{
+ return &static_cast<C &>(*b);
+}
+
+int
+main ()
+{
+ C c;
+ if (foo (static_cast<B *> (&c)) != &c)
+ __builtin_abort ();
+ if (foo (0))
+ __builtin_abort ();
+ if (bar (static_cast<B *> (&c)) != &c)
+ __builtin_abort ();
+ baz (0);
+ return 0;
+}