re PR sanitizer/89869 (-fsanitize=undefined miscompilation)
authorJakub Jelinek <jakub@redhat.com>
Fri, 29 Mar 2019 20:10:19 +0000 (21:10 +0100)
committerJakub Jelinek <jakub@gcc.gnu.org>
Fri, 29 Mar 2019 20:10:19 +0000 (21:10 +0100)
PR sanitizer/89869
* typeck.c: Include gimplify.h.
(cp_build_modify_expr) <case COND_EXPR>: Unshare rhs before using it
for second time.  Formatting fixes.

* g++.dg/ubsan/vptr-14.C: New test.

From-SVN: r270024

gcc/cp/ChangeLog
gcc/cp/typeck.c
gcc/testsuite/ChangeLog
gcc/testsuite/g++.dg/ubsan/vptr-14.C [new file with mode: 0644]

index 75d8169dae2366f3b5a11ce6d6b0fa1b6ee179df..a31e4391e211f2c74b74b4858849d190eee9d51a 100644 (file)
@@ -1,3 +1,10 @@
+2019-03-29  Jakub Jelinek  <jakub@redhat.com>
+
+       PR sanitizer/89869
+       * typeck.c: Include gimplify.h.
+       (cp_build_modify_expr) <case COND_EXPR>: Unshare rhs before using it
+       for second time.  Formatting fixes.
+
 2019-03-29  Marek Polacek  <polacek@redhat.com>
 
        PR c++/89876 - ICE with deprecated conversion.
index e2c5fc22ce4275754baff9eeb18bdded061191d1..a00b0f48b69c670577486525e1c05332fe0d87dd 100644 (file)
@@ -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;
index 1398b23424c0d3e0eac6f8b21c8e015a71cdbbcf..aee307894953b208ab6bf5dbeffb829494cb5f70 100644 (file)
@@ -1,5 +1,8 @@
 2019-03-29  Jakub Jelinek  <jakub@redhat.com>
 
+       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 (file)
index 0000000..2247ad9
--- /dev/null
@@ -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);
+}