diff options
author | Jakub Jelinek <jakub@redhat.com> | 2014-08-01 09:52:43 +0200 |
---|---|---|
committer | Jakub Jelinek <jakub@gcc.gnu.org> | 2014-08-01 09:52:43 +0200 |
commit | 944fa280bc92d197c443e369bb24405f007d46ab (patch) | |
tree | 893b88f145db7b629d24315901550a2b349d00ae /gcc/c-family | |
parent | bbe2542f728dbd46ffc9997537e62228173ffa24 (diff) | |
download | gcc-944fa280bc92d197c443e369bb24405f007d46ab.zip gcc-944fa280bc92d197c443e369bb24405f007d46ab.tar.gz gcc-944fa280bc92d197c443e369bb24405f007d46ab.tar.bz2 |
opts.c (common_handle_option): Handle -fsanitize=alignment.
* opts.c (common_handle_option): Handle -fsanitize=alignment.
* ubsan.h (enum ubsan_null_ckind): Add UBSAN_CTOR_CALL.
(ubsan_expand_bounds_ifn, ubsan_expand_null_ifn): Change return
type to bool.
* stor-layout.h (min_align_of_type): New prototype.
* asan.c (pass_sanopt::execute): Don't perform gsi_next if
ubsan_expand* told us not to do it. Remove the extra gsi_end_p
check.
* ubsan.c: Include builtins.h.
(ubsan_expand_bounds_ifn): Change return type to bool,
always return true.
(ubsan_expand_null_ifn): Change return type to bool, change
argument to gimple_stmt_iterator *. Handle both null and alignment
sanitization, take type from ckind argument's type rather than
first argument.
(instrument_member_call): Removed.
(instrument_mem_ref): Remove t argument, add mem and base arguments.
Handle both null and alignment sanitization, don't say whole
struct access is member access. Build 3 argument IFN_UBSAN_NULL
call instead of 2 argument.
(instrument_null): Adjust instrument_mem_ref caller. Don't
instrument calls here.
(pass_ubsan::gate, pass_ubsan::execute): Handle SANITIZE_ALIGNMENT
like SANITIZE_NULL.
* stor-layout.c (min_align_of_type): New function.
* flag-types.h (enum sanitize_code): Add SANITIZE_ALIGNMENT.
Or it into SANITIZE_UNDEFINED.
* doc/invoke.texi (-fsanitize=alignment): Document.
cp/
* cp-gimplify.c (cp_genericize_r): For -fsanitize=null and/or
-fsanitize=alignment call ubsan_maybe_instrument_reference
for casts to REFERENCE_TYPE and ubsan_maybe_instrument_member_call
for calls to member functions.
c-family/
* c-common.h (min_align_of_type): Removed prototype.
* c-common.c (min_align_of_type): Removed.
* c-ubsan.h (ubsan_maybe_instrument_reference,
ubsan_maybe_instrument_member_call): New prototypes.
* c-ubsan.c: Include stor-layout.h and builtins.h.
(ubsan_maybe_instrument_reference_or_call,
ubsan_maybe_instrument_reference, ubsan_maybe_instrument_call): New
functions.
testsuite/
* c-c++-common/ubsan/align-1.c: New test.
* c-c++-common/ubsan/align-2.c: New test.
* c-c++-common/ubsan/align-3.c: New test.
* c-c++-common/ubsan/align-4.c: New test.
* c-c++-common/ubsan/align-5.c: New test.
* c-c++-common/ubsan/attrib-4.c: New test.
* g++.dg/ubsan/align-1.C: New test.
* g++.dg/ubsan/align-2.C: New test.
* g++.dg/ubsan/align-3.C: New test.
* g++.dg/ubsan/attrib-1.C: New test.
* g++.dg/ubsan/null-1.C: New test.
* g++.dg/ubsan/null-2.C: New test.
From-SVN: r213406
Diffstat (limited to 'gcc/c-family')
-rw-r--r-- | gcc/c-family/ChangeLog | 11 | ||||
-rw-r--r-- | gcc/c-family/c-common.c | 20 | ||||
-rw-r--r-- | gcc/c-family/c-common.h | 1 | ||||
-rw-r--r-- | gcc/c-family/c-ubsan.c | 98 | ||||
-rw-r--r-- | gcc/c-family/c-ubsan.h | 2 |
5 files changed, 111 insertions, 21 deletions
diff --git a/gcc/c-family/ChangeLog b/gcc/c-family/ChangeLog index bf1ad5b..55e4a66 100644 --- a/gcc/c-family/ChangeLog +++ b/gcc/c-family/ChangeLog @@ -1,3 +1,14 @@ +2014-08-01 Jakub Jelinek <jakub@redhat.com> + + * c-common.h (min_align_of_type): Removed prototype. + * c-common.c (min_align_of_type): Removed. + * c-ubsan.h (ubsan_maybe_instrument_reference, + ubsan_maybe_instrument_member_call): New prototypes. + * c-ubsan.c: Include stor-layout.h and builtins.h. + (ubsan_maybe_instrument_reference_or_call, + ubsan_maybe_instrument_reference, ubsan_maybe_instrument_call): New + functions. + 2014-07-31 Marc Glisse <marc.glisse@inria.fr> PR c++/60517 diff --git a/gcc/c-family/c-common.c b/gcc/c-family/c-common.c index 79d0f2f..b2a053e 100644 --- a/gcc/c-family/c-common.c +++ b/gcc/c-family/c-common.c @@ -4965,26 +4965,6 @@ c_common_get_alias_set (tree t) return -1; } -/* Return the least alignment required for type TYPE. */ - -unsigned int -min_align_of_type (tree type) -{ - unsigned int align = TYPE_ALIGN (type); - align = MIN (align, BIGGEST_ALIGNMENT); -#ifdef BIGGEST_FIELD_ALIGNMENT - align = MIN (align, BIGGEST_FIELD_ALIGNMENT); -#endif - unsigned int field_align = align; -#ifdef ADJUST_FIELD_ALIGN - tree field = build_decl (UNKNOWN_LOCATION, FIELD_DECL, NULL_TREE, - type); - field_align = ADJUST_FIELD_ALIGN (field, field_align); -#endif - align = MIN (align, field_align); - return align / BITS_PER_UNIT; -} - /* Compute the value of 'sizeof (TYPE)' or '__alignof__ (TYPE)', where the IS_SIZEOF parameter indicates which operator is being applied. The COMPLAIN flag controls whether we should diagnose possibly diff --git a/gcc/c-family/c-common.h b/gcc/c-family/c-common.h index 3e8c8e7..26aaee2 100644 --- a/gcc/c-family/c-common.h +++ b/gcc/c-family/c-common.h @@ -762,7 +762,6 @@ extern tree c_wrap_maybe_const (tree, bool); extern tree c_save_expr (tree); extern tree c_common_truthvalue_conversion (location_t, tree); extern void c_apply_type_quals_to_decl (int, tree); -extern unsigned int min_align_of_type (tree); extern tree c_sizeof_or_alignof_type (location_t, tree, bool, bool, int); extern tree c_alignof_expr (location_t, tree); /* Print an error message for invalid operands to arith operation CODE. diff --git a/gcc/c-family/c-ubsan.c b/gcc/c-family/c-ubsan.c index ad5dd0b..e048c53 100644 --- a/gcc/c-family/c-ubsan.c +++ b/gcc/c-family/c-ubsan.c @@ -31,6 +31,8 @@ along with GCC; see the file COPYING3. If not see #include "c-family/c-ubsan.h" #include "asan.h" #include "internal-fn.h" +#include "stor-layout.h" +#include "builtins.h" /* Instrument division by zero and INT_MIN / -1. If not instrumenting, return NULL_TREE. */ @@ -350,3 +352,99 @@ ubsan_maybe_instrument_array_ref (tree *expr_p, bool ignore_off_by_one) } } } + +static tree +ubsan_maybe_instrument_reference_or_call (location_t loc, tree op, tree type, + enum ubsan_null_ckind ckind) +{ + tree orig_op = op; + bool instrument = false; + unsigned int mina = 0; + + if (current_function_decl == NULL_TREE + || lookup_attribute ("no_sanitize_undefined", + DECL_ATTRIBUTES (current_function_decl))) + return NULL_TREE; + + if (flag_sanitize & SANITIZE_ALIGNMENT) + { + mina = min_align_of_type (type); + if (mina <= 1) + mina = 0; + } + while ((TREE_CODE (op) == NOP_EXPR + || TREE_CODE (op) == NON_LVALUE_EXPR) + && TREE_CODE (TREE_TYPE (op)) == POINTER_TYPE) + op = TREE_OPERAND (op, 0); + if (TREE_CODE (op) == NOP_EXPR + && TREE_CODE (TREE_TYPE (op)) == REFERENCE_TYPE) + { + if (mina && mina > min_align_of_type (TREE_TYPE (TREE_TYPE (op)))) + instrument = true; + } + else + { + if ((flag_sanitize & SANITIZE_NULL) && TREE_CODE (op) == ADDR_EXPR) + { + bool strict_overflow_p = false; + /* tree_single_nonzero_warnv_p will not return true for non-weak + non-automatic decls with -fno-delete-null-pointer-checks, + which is disabled during -fsanitize=null. We don't want to + instrument those, just weak vars though. */ + int save_flag_delete_null_pointer_checks + = flag_delete_null_pointer_checks; + flag_delete_null_pointer_checks = 1; + if (!tree_single_nonzero_warnv_p (op, &strict_overflow_p) + || strict_overflow_p) + instrument = true; + flag_delete_null_pointer_checks + = save_flag_delete_null_pointer_checks; + } + else if (flag_sanitize & SANITIZE_NULL) + instrument = true; + if (mina && mina > get_pointer_alignment (op) / BITS_PER_UNIT) + instrument = true; + } + if (!instrument) + return NULL_TREE; + op = save_expr (orig_op); + tree kind = build_int_cst (TREE_TYPE (op), ckind); + tree align = build_int_cst (pointer_sized_int_node, mina); + tree call + = build_call_expr_internal_loc (loc, IFN_UBSAN_NULL, void_type_node, + 3, op, kind, align); + TREE_SIDE_EFFECTS (call) = 1; + return fold_build2 (COMPOUND_EXPR, TREE_TYPE (op), call, op); +} + +/* Instrument a NOP_EXPR to REFERENCE_TYPE if needed. */ + +void +ubsan_maybe_instrument_reference (tree stmt) +{ + tree op = TREE_OPERAND (stmt, 0); + op = ubsan_maybe_instrument_reference_or_call (EXPR_LOCATION (stmt), op, + TREE_TYPE (TREE_TYPE (stmt)), + UBSAN_REF_BINDING); + if (op) + TREE_OPERAND (stmt, 0) = op; +} + +/* Instrument a CALL_EXPR to a method if needed. */ + +void +ubsan_maybe_instrument_member_call (tree stmt, bool is_ctor) +{ + if (call_expr_nargs (stmt) == 0) + return; + tree op = CALL_EXPR_ARG (stmt, 0); + if (op == error_mark_node + || !POINTER_TYPE_P (TREE_TYPE (op))) + return; + op = ubsan_maybe_instrument_reference_or_call (EXPR_LOCATION (stmt), op, + TREE_TYPE (TREE_TYPE (op)), + is_ctor ? UBSAN_CTOR_CALL + : UBSAN_MEMBER_CALL); + if (op) + CALL_EXPR_ARG (stmt, 0) = op; +} diff --git a/gcc/c-family/c-ubsan.h b/gcc/c-family/c-ubsan.h index edf5bc6..7feec45 100644 --- a/gcc/c-family/c-ubsan.h +++ b/gcc/c-family/c-ubsan.h @@ -28,5 +28,7 @@ extern tree ubsan_instrument_return (location_t); extern tree ubsan_instrument_bounds (location_t, tree, tree *, bool); extern bool ubsan_array_ref_instrumented_p (const_tree); extern void ubsan_maybe_instrument_array_ref (tree *, bool); +extern void ubsan_maybe_instrument_reference (tree); +extern void ubsan_maybe_instrument_member_call (tree, bool); #endif /* GCC_C_UBSAN_H */ |