aboutsummaryrefslogtreecommitdiff
path: root/gcc/c-family
diff options
context:
space:
mode:
authorJakub Jelinek <jakub@redhat.com>2014-08-01 09:52:43 +0200
committerJakub Jelinek <jakub@gcc.gnu.org>2014-08-01 09:52:43 +0200
commit944fa280bc92d197c443e369bb24405f007d46ab (patch)
tree893b88f145db7b629d24315901550a2b349d00ae /gcc/c-family
parentbbe2542f728dbd46ffc9997537e62228173ffa24 (diff)
downloadgcc-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/ChangeLog11
-rw-r--r--gcc/c-family/c-common.c20
-rw-r--r--gcc/c-family/c-common.h1
-rw-r--r--gcc/c-family/c-ubsan.c98
-rw-r--r--gcc/c-family/c-ubsan.h2
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 */