c++: -fsanitize=vptr and -fstrong-eval-order. [PR95221]
authorJason Merrill <jason@redhat.com>
Thu, 21 May 2020 04:22:10 +0000 (00:22 -0400)
committerJason Merrill <jason@redhat.com>
Fri, 22 May 2020 21:02:03 +0000 (17:02 -0400)
With -fstrong-eval-order=all we evaluate the function address before the
arguments.  But this caused trouble with virtual functions and
-fsanitize=vptr; we would do vptr sanitization as part of calculating the
'this' argument, and separately look at the vptr in order to find the
function address.  Without -fstrong-eval-order=all 'this' is evaluated
first, but with that flag the function address is evaluated first, so we
would access the null vptr before sanitizing it.

Fixed by instrumenting the OBJ_TYPE_REF of a virtual function call instead
of the 'this' argument.

This issue suggests that we should be running the ubsan tests in multiple
standard modes like the rest of the G++ testsuite, so I've made that change
as well.

gcc/cp/ChangeLog:

* cp-ubsan.c (cp_ubsan_maybe_instrument_member_call): For a virtual
call, instrument the OBJ_TYPE_REF.

gcc/testsuite/ChangeLog:

* g++.dg/ubsan/ubsan.exp: Use g++-dg-runtest.
* c-c++-common/ubsan/bounds-13.c: Adjust.
* c-c++-common/ubsan/bounds-2.c: Adjust.
* c-c++-common/ubsan/div-by-zero-1.c: Adjust.
* c-c++-common/ubsan/div-by-zero-6.c: Adjust.
* c-c++-common/ubsan/div-by-zero-7.c: Adjust.
* c-c++-common/ubsan/overflow-add-1.c: Adjust.
* c-c++-common/ubsan/overflow-add-2.c: Adjust.
* c-c++-common/ubsan/overflow-int128.c: Adjust.
* c-c++-common/ubsan/overflow-sub-1.c: Adjust.
* c-c++-common/ubsan/overflow-sub-2.c: Adjust.
* g++.dg/ubsan/pr85029.C: Adjust.
* g++.dg/ubsan/vptr-14.C: Adjust.

14 files changed:
gcc/cp/cp-ubsan.c
gcc/testsuite/c-c++-common/ubsan/bounds-13.c
gcc/testsuite/c-c++-common/ubsan/bounds-2.c
gcc/testsuite/c-c++-common/ubsan/div-by-zero-1.c
gcc/testsuite/c-c++-common/ubsan/div-by-zero-6.c
gcc/testsuite/c-c++-common/ubsan/div-by-zero-7.c
gcc/testsuite/c-c++-common/ubsan/overflow-add-1.c
gcc/testsuite/c-c++-common/ubsan/overflow-add-2.c
gcc/testsuite/c-c++-common/ubsan/overflow-int128.c
gcc/testsuite/c-c++-common/ubsan/overflow-sub-1.c
gcc/testsuite/c-c++-common/ubsan/overflow-sub-2.c
gcc/testsuite/g++.dg/ubsan/pr85029.C
gcc/testsuite/g++.dg/ubsan/ubsan.exp
gcc/testsuite/g++.dg/ubsan/vptr-14.C

index b064a98202ac6af70bb2054650ae9b451e0915a6..c40dac72b42b7fb071307d54694b2ce18d2403e7 100644 (file)
@@ -118,14 +118,33 @@ cp_ubsan_maybe_instrument_member_call (tree stmt)
 {
   if (call_expr_nargs (stmt) == 0)
     return;
-  tree *opp = &CALL_EXPR_ARG (stmt, 0);
-  tree op = *opp;
-  if (op == error_mark_node
-      || !INDIRECT_TYPE_P (TREE_TYPE (op)))
-    return;
-  while (TREE_CODE (op) == COMPOUND_EXPR)
+  tree op, *opp;
+
+  tree fn = CALL_EXPR_FN (stmt);
+  if (fn && TREE_CODE (fn) == OBJ_TYPE_REF)
+    {
+      /* Virtual function call: Sanitize the use of the object pointer in the
+        OBJ_TYPE_REF, since the vtable reference will SEGV otherwise (95221).
+        OBJ_TYPE_REF_EXPR is ptr->vptr[N] and OBJ_TYPE_REF_OBJECT is ptr.  */
+      opp = &OBJ_TYPE_REF_EXPR (fn);
+      op = OBJ_TYPE_REF_OBJECT (fn);
+      while (*opp != op)
+       {
+         if (TREE_CODE (*opp) == COMPOUND_EXPR)
+           opp = &TREE_OPERAND (*opp, 1);
+         else
+           opp = &TREE_OPERAND (*opp, 0);
+       }
+    }
+  else
     {
-      opp = &TREE_OPERAND (op, 1);
+      /* Non-virtual call: Sanitize the 'this' argument.  */
+      opp = &CALL_EXPR_ARG (stmt, 0);
+      if (*opp == error_mark_node
+         || !INDIRECT_TYPE_P (TREE_TYPE (*opp)))
+       return;
+      while (TREE_CODE (*opp) == COMPOUND_EXPR)
+       opp = &TREE_OPERAND (*opp, 1);
       op = *opp;
     }
   op = cp_ubsan_maybe_instrument_vptr (EXPR_LOCATION (stmt), op,
index 25b0467ec67be51d2b66bcc2bafee3831f793c86..a8bce370f8f60e7cdeef6d9084776ed90aa7a9f1 100644 (file)
@@ -1,6 +1,7 @@
 /* PR sanitizer/71498 */
 /* { dg-do run } */
 /* { dg-options "-fsanitize=bounds -Wno-array-bounds" } */
+/* { dg-options "-fsanitize=bounds -Wno-array-bounds -Wno-volatile" { target c++ } } */
 
 struct S { int a[100]; int b, c; } s;
 
index 56654486f65f9b0dafcaa11549991c312e697c0e..ec4ef7eed20a6b6fc120a01e1f0ca432c9bdbbff 100644 (file)
@@ -1,5 +1,6 @@
 /* { dg-do run } */
 /* { dg-options "-fsanitize=bounds -Wall -Wextra -Wno-unused -Wno-array-bounds -Wno-uninitialized" } */
+/* { dg-options "-fsanitize=bounds -Wall -Wextra -Wno-unused -Wno-array-bounds -Wno-uninitialized -Wno-volatile" { target c++ } } */
 
 /* Test runtime errors.  */
 
index 479ced038fb1db878766b93d288ea8bce36010ec..8b62ae743d815153f55b53c134f288706ad54b63 100644 (file)
@@ -1,5 +1,6 @@
 /* { dg-do run } */
 /* { dg-options "-fsanitize=integer-divide-by-zero -Wno-div-by-zero" } */
+/* { dg-options "-fsanitize=integer-divide-by-zero -Wno-div-by-zero -Wno-volatile" { target c++ } } */
 
 int
 main (void)
index 27a18bb096e56307b1965fbb77983c1a95a23fb9..be017ad8179e56183bccf5b5a1d33c1edee012e0 100644 (file)
@@ -1,5 +1,6 @@
 /* { dg-do run } */
 /* { dg-options "-fsanitize=integer-divide-by-zero -Wno-div-by-zero" } */
+/* { dg-options "-fsanitize=integer-divide-by-zero -Wno-div-by-zero -Wno-volatile" { target c++ } } */
 
 #include <stdio.h>
 
index 5f53bef74ea5f977852bfac2d47dadc5cda501c0..643b76af143c693402f9813080f4c841724ef903 100644 (file)
@@ -1,5 +1,6 @@
 /* { dg-do run } */
 /* { dg-options "-fsanitize=integer-divide-by-zero -Wno-div-by-zero -fno-sanitize-recover=integer-divide-by-zero" } */
+/* { dg-options "-fsanitize=integer-divide-by-zero -Wno-div-by-zero -fno-sanitize-recover=integer-divide-by-zero -Wno-volatile" { target c++ } } */
 /* { dg-shouldfail "ubsan" } */
 
 #include <stdio.h>
index 960f1b0afaf98eaa75acfca87de410c094b99c45..3c0a17edb8547bc4b9e6c0adf246ac7e1b2283b0 100644 (file)
@@ -1,5 +1,6 @@
 /* { dg-do run } */
 /* { dg-options "-fsanitize=signed-integer-overflow -Wno-unused-variable -fno-sanitize-recover=signed-integer-overflow" } */
+/* { dg-options "-fsanitize=signed-integer-overflow -Wno-unused-variable -fno-sanitize-recover=signed-integer-overflow -Wno-volatile" { target c++ } } */
 
 #define SCHAR_MAX __SCHAR_MAX__
 #define SHRT_MAX __SHRT_MAX__
index b104d6158fed8c062f141d219437e90542db481d..8fa9074647af2414310b4a3de67a99681d80767a 100644 (file)
@@ -1,5 +1,6 @@
 /* { dg-do run } */
 /* { dg-options "-fsanitize=signed-integer-overflow -Wno-unused-variable" } */
+/* { dg-options "-fsanitize=signed-integer-overflow -Wno-unused-variable -Wno-volatile" { target c++ } } */
 
 #define INT_MAX __INT_MAX__
 #define INT_MIN (-__INT_MAX__ - 1)
index 400f25b01e10532f91c8ea385042dd695158691d..10ccc79d0fea88e20a3a2615cbe5c771acddf02a 100644 (file)
@@ -1,6 +1,7 @@
 /* { dg-do run } */
 /* { dg-require-effective-target int128 } */
 /* { dg-options "-fsanitize=signed-integer-overflow" } */
+/* { dg-options "-fsanitize=signed-integer-overflow -Wno-volatile" { target c++ } } */
 
 /* 2^127 - 1 */
 #define INT128_MAX (__int128) (((unsigned __int128) 1 << ((__SIZEOF_INT128__ * __CHAR_BIT__) - 1)) - 1)
index e92aaf4ce33c4e5f98a45ed4088b5829a44aabff..7ceb4ec60a733ac14b8420c42710d219c19bc956 100644 (file)
@@ -1,5 +1,6 @@
 /* { dg-do run } */
 /* { dg-options "-fsanitize=signed-integer-overflow -Wno-unused-variable -fno-sanitize-recover=signed-integer-overflow" } */
+/* { dg-options "-fsanitize=signed-integer-overflow -Wno-unused-variable -fno-sanitize-recover=signed-integer-overflow -Wno-volatile" { target c++ } } */
 
 #define SCHAR_MAX __SCHAR_MAX__
 #define SCHAR_MIN (-__SCHAR_MAX__ - 1)
index cc94061634ecf824526922762b901d9a72c9f86b..92a2ea28af2598ab38db65c8c8122ac999084404 100644 (file)
@@ -1,5 +1,6 @@
 /* { dg-do run } */
 /* { dg-options "-fsanitize=signed-integer-overflow -Wno-unused-variable" } */
+/* { dg-options "-fsanitize=signed-integer-overflow -Wno-unused-variable -Wno-volatile" { target c++ } } */
 
 #define INT_MAX __INT_MAX__
 #define INT_MIN (-__INT_MAX__ - 1)
index 07472af16a5fd39d90c154752b1599d77dbe728d..836ce69cc15d4fac22265d4064e777ab04199ba3 100644 (file)
@@ -1,7 +1,7 @@
 // PR sanitizer/85029
 // { dg-do compile }
 // { dg-skip-if "" { *-*-* } { "-flto -fno-fat-lto-objects" } }
-// { dg-options "-fsanitize=undefined" }
+// { dg-options "-fsanitize=undefined -Wno-register" }
 
 struct B {
   virtual B bar ();
index 11b92bff980394ed73719e11b5196618cb24a163..2bc98831d2e296989bcb2941766806be43918e58 100644 (file)
@@ -26,7 +26,7 @@ ubsan_init
 
 # Main loop.
 if [check_effective_target_fsanitize_undefined] {
-  gcc-dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/*.C $srcdir/c-c++-common/ubsan/*.c]] "" ""
+  g++-dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/*.C $srcdir/c-c++-common/ubsan/*.c]] "" ""
 }
 
 # All done.
index 2247ad99fccff8b28ad080ec3efcfc766a4f061e..06cd66347d4d61b4d98e13aac295af9a770f48d7 100644 (file)
@@ -1,5 +1,5 @@
 // PR sanitizer/89869
-// { dg-do run }
+// { dg-do run { target c++11 } }
 // { dg-options "-fsanitize=vptr -fno-sanitize-recover=vptr" }
 
 struct S { S *s = 0; virtual ~S () {} };