diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 75d8169dae2..a31e4391e21 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,10 @@ +2019-03-29 Jakub Jelinek + + PR sanitizer/89869 + * typeck.c: Include gimplify.h. + (cp_build_modify_expr) : Unshare rhs before using it + for second time. Formatting fixes. + 2019-03-29 Marek Polacek PR c++/89876 - ICE with deprecated conversion. diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c index e2c5fc22ce4..a00b0f48b69 100644 --- a/gcc/cp/typeck.c +++ b/gcc/cp/typeck.c @@ -40,6 +40,7 @@ along with GCC; see the file COPYING3. If not see #include "stringpool.h" #include "attribs.h" #include "asan.h" +#include "gimplify.h" static tree cp_build_addr_expr_strict (tree, tsubst_flags_t); static tree cp_build_function_call (tree, tree, tsubst_flags_t); @@ -8129,8 +8130,6 @@ cp_build_modify_expr (location_t loc, tree lhs, enum tree_code modifycode, /* Produce (a ? (b = rhs) : (c = rhs)) except that the RHS goes through a save-expr so the code to compute it is only emitted once. */ - tree cond; - if (VOID_TYPE_P (TREE_TYPE (rhs))) { if (complain & tf_error) @@ -8145,13 +8144,21 @@ cp_build_modify_expr (location_t loc, tree lhs, enum tree_code modifycode, if (!lvalue_or_else (lhs, lv_assign, complain)) return error_mark_node; - cond = build_conditional_expr - (input_location, TREE_OPERAND (lhs, 0), - cp_build_modify_expr (loc, TREE_OPERAND (lhs, 1), - modifycode, rhs, complain), - cp_build_modify_expr (loc, TREE_OPERAND (lhs, 2), - modifycode, rhs, complain), - complain); + tree op1 = cp_build_modify_expr (loc, TREE_OPERAND (lhs, 1), + modifycode, rhs, complain); + /* When sanitizing undefined behavior, even when rhs doesn't need + stabilization at this point, the sanitization might add extra + SAVE_EXPRs in there and so make sure there is no tree sharing + in the rhs, otherwise those SAVE_EXPRs will have initialization + only in one of the two branches. */ + if (sanitize_flags_p (SANITIZE_UNDEFINED + | SANITIZE_UNDEFINED_NONDEFAULT)) + rhs = unshare_expr (rhs); + tree op2 = cp_build_modify_expr (loc, TREE_OPERAND (lhs, 2), + modifycode, rhs, complain); + tree cond = build_conditional_expr (input_location, + TREE_OPERAND (lhs, 0), op1, op2, + complain); if (cond == error_mark_node) return cond; diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 1398b23424c..aee30789495 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,5 +1,8 @@ 2019-03-29 Jakub Jelinek + PR sanitizer/89869 + * g++.dg/ubsan/vptr-14.C: New test. + PR c/89872 * gcc.dg/tree-ssa/pr89872.c: New test. diff --git a/gcc/testsuite/g++.dg/ubsan/vptr-14.C b/gcc/testsuite/g++.dg/ubsan/vptr-14.C new file mode 100644 index 00000000000..2247ad99fcc --- /dev/null +++ b/gcc/testsuite/g++.dg/ubsan/vptr-14.C @@ -0,0 +1,18 @@ +// PR sanitizer/89869 +// { dg-do run } +// { dg-options "-fsanitize=vptr -fno-sanitize-recover=vptr" } + +struct S { S *s = 0; virtual ~S () {} }; + +void +foo (S *x, S *y) +{ + (x->s ? y : x) = x->s; +} + +int +main () +{ + S a; + foo (&a, 0); +}