diff options
author | Jason Merrill <jason@redhat.com> | 2020-05-21 00:22:10 -0400 |
---|---|---|
committer | Jason Merrill <jason@redhat.com> | 2020-05-22 17:02:03 -0400 |
commit | 72af65b91cc2a2eb726afe56af6b44d6c57bb10f (patch) | |
tree | 8d6d212d01adba64d540a4be66e7d5befedcf4ee /gcc/cp/cp-ubsan.c | |
parent | 2221fb6f668a7edc8b8aad69772907aeabbbb0be (diff) | |
download | gcc-72af65b91cc2a2eb726afe56af6b44d6c57bb10f.tar.gz |
c++: -fsanitize=vptr and -fstrong-eval-order. [PR95221]
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.
Diffstat (limited to 'gcc/cp/cp-ubsan.c')
-rw-r--r-- | gcc/cp/cp-ubsan.c | 33 |
1 files changed, 26 insertions, 7 deletions
diff --git a/gcc/cp/cp-ubsan.c b/gcc/cp/cp-ubsan.c index b064a98202a..c40dac72b42 100644 --- a/gcc/cp/cp-ubsan.c +++ b/gcc/cp/cp-ubsan.c @@ -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, |