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
This commit is contained in:
parent
8bdbeed1d0
commit
830421fcd3
@ -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
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
15
gcc/testsuite/g++.dg/opt/pr83555.C
Normal file
15
gcc/testsuite/g++.dg/opt/pr83555.C
Normal file
@ -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" } }
|
40
gcc/testsuite/g++.dg/ubsan/pr83555.C
Normal file
40
gcc/testsuite/g++.dg/ubsan/pr83555.C
Normal file
@ -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;
|
||||
}
|
Loading…
Reference in New Issue
Block a user