From 046ce41931ea1d4cb51c14b74f2bcddc2cb4c6ca Mon Sep 17 00:00:00 2001
From: marxin <mliska@suse.cz>
Date: Wed, 21 Dec 2016 11:13:34 +0100
Subject: [PATCH] Implement no_sanitize function attribute
gcc/cp/ChangeLog:
2016-12-22 Martin Liska <mliska@suse.cz>
* class.c (build_base_path): Use sanitize_flags_p predicate.
* cp-gimplify.c (cp_genericize_r): Likewise.
(cp_genericize_tree): Likewise.
(cp_genericize): Likewise.
* cp-ubsan.c (cp_ubsan_instrument_vptr_p): Likewise.
* decl.c (compute_array_index_type): Likewise.
(start_preparsed_function): Likewise.
* decl2.c (one_static_initialization_or_destruction): Likewise.
* init.c (build_vec_init): Likewise.
* lambda.c (maybe_add_lambda_conv_op): Use
add_no_sanitize_value.
* typeck.c (cp_build_binary_op): Use sanitize_flags_p.
(build_static_cast_1): Likewise.
gcc/c-family/ChangeLog:
2016-12-22 Martin Liska <mliska@suse.cz>
* c-attribs.c (add_no_sanitize_value): New function.
(handle_no_sanitize_attribute): Likewise.
(handle_no_sanitize_address_attribute): Use
add_no_sanitize_value.
(handle_no_sanitize_thread_attribute): New function.
(handle_no_address_safety_analysis_attribute): Use
add_no_sanitize_value.
(handle_no_sanitize_undefined_attribute): Likewise.
* c-common.h (add_no_sanitize_value): Declare.
* c-ubsan.c (ubsan_instrument_division): Use sanitize_flags_p.
(ubsan_instrument_shift): Likewise.
(ubsan_instrument_bounds): Likewise.
(ubsan_maybe_instrument_array_ref): Likewise.
(ubsan_maybe_instrument_reference_or_call): Likewise.
* c-ubsan.h (do_ubsan_in_current_function): Remove declaration.
gcc/testsuite/ChangeLog:
2016-12-22 Martin Liska <mliska@suse.cz>
* c-c++-common/ubsan/align-10.c: New test.
* c-c++-common/ubsan/attrib-5.c: New test.
* c-c++-common/ubsan/attrib-6.c: New test.
* c-c++-common/ubsan/bounds-14.c: New test.
* c-c++-common/ubsan/div-by-zero-8.c: New test.
* c-c++-common/ubsan/float-cast-overflow-11.c: New test.
* c-c++-common/ubsan/float-div-by-zero-2.c: New test.
* c-c++-common/ubsan/load-bool-enum-2.c: New test.
* c-c++-common/ubsan/nonnull-6.c: New test.
* c-c++-common/ubsan/null-12.c: New test.
* c-c++-common/ubsan/object-size-11.c: New test.
* c-c++-common/ubsan/overflow-3.c: New test.
* c-c++-common/ubsan/unreachable-5.c: New test.
* c-c++-common/ubsan/vla-5.c: New test.
* g++.dg/ubsan/return-8.C: New test.
* g++.dg/ubsan/vptr-12.C: New test.
* gcc.dg/ubsan/bounds-4.c: New test.
* gcc.dg/ubsan/c99-shift-7.c: New test.
* gcc.dg/ubsan/c99-shift-8.c: New test.
gcc/ChangeLog:
2016-12-22 Martin Liska <mliska@suse.cz>
* asan.c (asan_sanitize_stack_p): Use sanitize_flags_p.
(gate_asan): Likewise.
* asan.h (asan_no_sanitize_address_p): Remove.
* builtins.def: Use renamed SANITIZE_UNDEFINED_NONDEFAULT.
* common.opt: Likewise.
* convert.c (convert_to_integer_1): Use sanitize_flags_p.
* doc/extend.texi: Document the new attribute.
* doc/invoke.texi: Improve documentation of
-sanitize=bounds-strict.
* flag-types.h (enum sanitize_code): Rename
SANITIZE_NONDEFAULT to SANITIZE_UNDEFINED_NONDEFAULT.
* gcc.c (sanitize_spec_function): Use the renamed enum value.
* gimple-fold.c (optimize_atomic_compare_exchange_p): Use
sanitize_flags_p.
* gimplify.c (gimplify_decl_expr): Likewise.
(gimplify_function_tree): Likewise.
* ipa-inline.c (sanitize_attrs_match_for_inline_p): Likewise.
* opts.c (parse_no_sanitize_attribute): New function.
(common_handle_option): Use the renamed enum value.
* opts.h (parse_no_sanitize_attribute): Declare.
* tree.c (sanitize_flags_p): New function.
* tree.h (sanitize_flags_p): New declaration.
* tsan.c (gate): Use sanitize_flags_p.
* ubsan.c (ubsan_expand_null_ifn): Likewise.
(instrument_mem_ref): Likewise.
(instrument_bool_enum_load): Likewise.
(do_ubsan_in_current_function): Remove.
(pass_ubsan::execute): Use sanitize_flags_p.
* ubsan.h (do_ubsan_in_current_function): Remove.
gcc/c/ChangeLog:
2016-12-22 Martin Liska <mliska@suse.cz>
* c-convert.c (convert): Use sanitize_flags_p.
* c-decl.c (grokdeclarator): Likewise.
* c-typeck.c (convert_for_assignment): Likewise.
(c_finish_return): Likewise.
(build_binary_op): Likewise.
---
gcc/asan.c | 14 +-
gcc/asan.h | 7 -
gcc/builtins.def | 3 +-
gcc/c-family/c-attribs.c | 99 +++++++-
gcc/c-family/c-common.h | 1 +
gcc/c-family/c-ubsan.c | 22 +-
gcc/c-family/c-ubsan.h | 3 -
gcc/c/c-convert.c | 5 +-
gcc/c/c-decl.c | 5 +-
gcc/c/c-typeck.c | 15 +-
gcc/common.opt | 2 +-
gcc/convert.c | 3 +-
gcc/cp/class.c | 3 +-
gcc/cp/cp-gimplify.c | 18 +-
gcc/cp/cp-ubsan.c | 2 +-
gcc/cp/decl.c | 5 +-
gcc/cp/decl2.c | 2 +-
gcc/cp/init.c | 3 +-
gcc/cp/lambda.c | 4 +-
gcc/cp/typeck.c | 15 +-
gcc/doc/extend.texi | 12 +
gcc/doc/invoke.texi | 2 +
gcc/flag-types.h | 4 +-
gcc/gcc.c | 3 +-
gcc/gimple-fold.c | 2 +-
gcc/gimplify.c | 5 +-
gcc/ipa-inline.c | 10 +-
gcc/opts.c | 31 ++-
gcc/opts.h | 2 +
gcc/testsuite/c-c++-common/ubsan/align-10.c | 56 +++++
gcc/testsuite/c-c++-common/ubsan/attrib-5.c | 12 +
gcc/testsuite/c-c++-common/ubsan/attrib-6.c | 15 ++
gcc/testsuite/c-c++-common/ubsan/bounds-14.c | 17 ++
gcc/testsuite/c-c++-common/ubsan/div-by-zero-8.c | 9 +
.../c-c++-common/ubsan/float-cast-overflow-11.c | 205 ++++++++++++++++
.../c-c++-common/ubsan/float-div-by-zero-2.c | 27 +++
.../c-c++-common/ubsan/load-bool-enum-2.c | 31 +++
gcc/testsuite/c-c++-common/ubsan/nonnull-6.c | 40 ++++
gcc/testsuite/c-c++-common/ubsan/null-12.c | 13 +
gcc/testsuite/c-c++-common/ubsan/object-size-11.c | 131 +++++++++++
gcc/testsuite/c-c++-common/ubsan/overflow-3.c | 262 +++++++++++++++++++++
gcc/testsuite/c-c++-common/ubsan/unreachable-5.c | 11 +
gcc/testsuite/c-c++-common/ubsan/vla-5.c | 14 ++
gcc/testsuite/g++.dg/ubsan/return-8.C | 29 +++
gcc/testsuite/g++.dg/ubsan/vptr-12.C | 185 +++++++++++++++
gcc/testsuite/gcc.dg/ubsan/bounds-4.c | 20 ++
gcc/testsuite/gcc.dg/ubsan/c99-shift-7.c | 11 +
gcc/testsuite/gcc.dg/ubsan/c99-shift-8.c | 12 +
gcc/tree.c | 17 ++
gcc/tree.h | 4 +
gcc/tsan.c | 12 +-
gcc/ubsan.c | 48 ++--
gcc/ubsan.h | 1 -
53 files changed, 1345 insertions(+), 139 deletions(-)
create mode 100644 gcc/testsuite/c-c++-common/ubsan/align-10.c
create mode 100644 gcc/testsuite/c-c++-common/ubsan/attrib-5.c
create mode 100644 gcc/testsuite/c-c++-common/ubsan/attrib-6.c
create mode 100644 gcc/testsuite/c-c++-common/ubsan/bounds-14.c
create mode 100644 gcc/testsuite/c-c++-common/ubsan/div-by-zero-8.c
create mode 100644 gcc/testsuite/c-c++-common/ubsan/float-cast-overflow-11.c
create mode 100644 gcc/testsuite/c-c++-common/ubsan/float-div-by-zero-2.c
create mode 100644 gcc/testsuite/c-c++-common/ubsan/load-bool-enum-2.c
create mode 100644 gcc/testsuite/c-c++-common/ubsan/nonnull-6.c
create mode 100644 gcc/testsuite/c-c++-common/ubsan/null-12.c
create mode 100644 gcc/testsuite/c-c++-common/ubsan/object-size-11.c
create mode 100644 gcc/testsuite/c-c++-common/ubsan/overflow-3.c
create mode 100644 gcc/testsuite/c-c++-common/ubsan/unreachable-5.c
create mode 100644 gcc/testsuite/c-c++-common/ubsan/vla-5.c
create mode 100644 gcc/testsuite/g++.dg/ubsan/return-8.C
create mode 100644 gcc/testsuite/g++.dg/ubsan/vptr-12.C
create mode 100644 gcc/testsuite/gcc.dg/ubsan/bounds-4.c
create mode 100644 gcc/testsuite/gcc.dg/ubsan/c99-shift-7.c
create mode 100644 gcc/testsuite/gcc.dg/ubsan/c99-shift-8.c
@@ -304,9 +304,7 @@ asan_mark_p (gimple *stmt, enum asan_mark_flags flag)
bool
asan_sanitize_stack_p (void)
{
- return ((flag_sanitize & SANITIZE_ADDRESS)
- && ASAN_STACK
- && !asan_no_sanitize_address_p ());
+ return (sanitize_flags_p (SANITIZE_ADDRESS) && ASAN_STACK);
}
/* Checks whether section SEC should be sanitized. */
@@ -3067,11 +3065,9 @@ asan_instrument (void)
}
static bool
-gate_asan (void)
+gate_asan (function *fn)
{
- return (flag_sanitize & SANITIZE_ADDRESS) != 0
- && !lookup_attribute ("no_sanitize_address",
- DECL_ATTRIBUTES (current_function_decl));
+ return sanitize_flags_p (SANITIZE_ADDRESS, fn->decl);
}
namespace {
@@ -3098,7 +3094,7 @@ public:
/* opt_pass methods: */
opt_pass * clone () { return new pass_asan (m_ctxt); }
- virtual bool gate (function *) { return gate_asan (); }
+ virtual bool gate (function *fn) { return gate_asan (fn); }
virtual unsigned int execute (function *) { return asan_instrument (); }
}; // class pass_asan
@@ -3134,7 +3130,7 @@ public:
{}
/* opt_pass methods: */
- virtual bool gate (function *) { return !optimize && gate_asan (); }
+ virtual bool gate (function *fn) { return !optimize && gate_asan (fn); }
virtual unsigned int execute (function *) { return asan_instrument (); }
}; // class pass_asan_O0
@@ -140,13 +140,6 @@ asan_sanitize_use_after_scope (void)
return (flag_sanitize_address_use_after_scope && asan_sanitize_stack_p ());
}
-static inline bool
-asan_no_sanitize_address_p (void)
-{
- return lookup_attribute ("no_sanitize_address",
- DECL_ATTRIBUTES (current_function_decl));
-}
-
/* Return true if DECL should be guarded on the stack. */
static inline bool
@@ -236,7 +236,8 @@ along with GCC; see the file COPYING3. If not see
DEF_BUILTIN (ENUM, "__builtin_" NAME, BUILT_IN_NORMAL, TYPE, TYPE, \
true, true, true, ATTRS, true, \
(flag_sanitize & (SANITIZE_ADDRESS | SANITIZE_THREAD \
- | SANITIZE_UNDEFINED | SANITIZE_NONDEFAULT) \
+ | SANITIZE_UNDEFINED \
+ | SANITIZE_UNDEFINED_NONDEFAULT) \
|| flag_sanitize_coverage))
#undef DEF_CILKPLUS_BUILTIN
@@ -51,8 +51,11 @@ static tree handle_common_attribute (tree *, tree, tree, int, bool *);
static tree handle_noreturn_attribute (tree *, tree, tree, int, bool *);
static tree handle_hot_attribute (tree *, tree, tree, int, bool *);
static tree handle_cold_attribute (tree *, tree, tree, int, bool *);
+static tree handle_no_sanitize_attribute (tree *, tree, tree, int, bool *);
static tree handle_no_sanitize_address_attribute (tree *, tree, tree,
int, bool *);
+static tree handle_no_sanitize_thread_attribute (tree *, tree, tree,
+ int, bool *);
static tree handle_no_address_safety_analysis_attribute (tree *, tree, tree,
int, bool *);
static tree handle_no_sanitize_undefined_attribute (tree *, tree, tree, int,
@@ -285,11 +288,14 @@ const struct attribute_spec c_common_attribute_table[] =
0, 0, true, false, false,
handle_no_address_safety_analysis_attribute,
false },
+ { "no_sanitize", 1, 1, true, false, false,
+ handle_no_sanitize_attribute,
+ false },
{ "no_sanitize_address", 0, 0, true, false, false,
handle_no_sanitize_address_attribute,
false },
{ "no_sanitize_thread", 0, 0, true, false, false,
- handle_no_sanitize_address_attribute,
+ handle_no_sanitize_thread_attribute,
false },
{ "no_sanitize_undefined", 0, 0, true, false, false,
handle_no_sanitize_undefined_attribute,
@@ -547,6 +553,60 @@ handle_cold_attribute (tree *node, tree name, tree ARG_UNUSED (args),
return NULL_TREE;
}
+/* Add FLAGS for a function NODE to no_sanitize_flags in DECL_ATTRIBUTES. */
+
+void
+add_no_sanitize_value (tree node, unsigned int flags)
+{
+ tree attr = lookup_attribute ("no_sanitize_flags", DECL_ATTRIBUTES (node));
+ if (attr)
+ {
+ unsigned int old_value = tree_to_uhwi (TREE_VALUE (attr));
+ flags |= old_value;
+ }
+
+ DECL_ATTRIBUTES (node)
+ = tree_cons (get_identifier ("no_sanitize_flags"),
+ build_int_cst (integer_type_node, flags),
+ DECL_ATTRIBUTES (node));
+}
+
+/* Handle a "no_sanitize" attribute; arguments as in
+ struct attribute_spec.handler. */
+
+static tree
+handle_no_sanitize_attribute (tree *node, tree name, tree args, int,
+ bool *no_add_attrs)
+{
+ tree id = TREE_VALUE (args);
+ if (TREE_CODE (*node) != FUNCTION_DECL)
+ {
+ warning (OPT_Wattributes, "%qE attribute ignored", name);
+ *no_add_attrs = true;
+ return NULL_TREE;
+ }
+
+ if (TREE_CODE (id) != STRING_CST)
+ {
+ error ("no_sanitize argument not a string");
+ return NULL_TREE;
+ }
+
+ char *error_value = NULL;
+ char *string = ASTRDUP (TREE_STRING_POINTER (id));
+ unsigned int flags = parse_no_sanitize_attribute (string, &error_value);
+
+ if (error_value)
+ {
+ error ("wrong argument: \"%s\"", error_value);
+ return NULL_TREE;
+ }
+
+ add_no_sanitize_value (*node, flags);
+
+ return NULL_TREE;
+}
+
/* Handle a "no_sanitize_address" attribute; arguments as in
struct attribute_spec.handler. */
@@ -559,10 +619,31 @@ handle_no_sanitize_address_attribute (tree *node, tree name, tree, int,
warning (OPT_Wattributes, "%qE attribute ignored", name);
*no_add_attrs = true;
}
+ else
+ add_no_sanitize_value (*node, SANITIZE_ADDRESS);
+
+ return NULL_TREE;
+}
+
+/* Handle a "no_sanitize_thread" attribute; arguments as in
+ struct attribute_spec.handler. */
+
+static tree
+handle_no_sanitize_thread_attribute (tree *node, tree name, tree, int,
+ bool *no_add_attrs)
+{
+ if (TREE_CODE (*node) != FUNCTION_DECL)
+ {
+ warning (OPT_Wattributes, "%qE attribute ignored", name);
+ *no_add_attrs = true;
+ }
+ else
+ add_no_sanitize_value (*node, SANITIZE_THREAD);
return NULL_TREE;
}
+
/* Handle a "no_address_safety_analysis" attribute; arguments as in
struct attribute_spec.handler. */
@@ -571,12 +652,13 @@ handle_no_address_safety_analysis_attribute (tree *node, tree name, tree, int,
bool *no_add_attrs)
{
if (TREE_CODE (*node) != FUNCTION_DECL)
- warning (OPT_Wattributes, "%qE attribute ignored", name);
- else if (!lookup_attribute ("no_sanitize_address", DECL_ATTRIBUTES (*node)))
- DECL_ATTRIBUTES (*node)
- = tree_cons (get_identifier ("no_sanitize_address"),
- NULL_TREE, DECL_ATTRIBUTES (*node));
- *no_add_attrs = true;
+ {
+ warning (OPT_Wattributes, "%qE attribute ignored", name);
+ *no_add_attrs = true;
+ }
+ else
+ add_no_sanitize_value (*node, SANITIZE_ADDRESS);
+
return NULL_TREE;
}
@@ -592,6 +674,9 @@ handle_no_sanitize_undefined_attribute (tree *node, tree name, tree, int,
warning (OPT_Wattributes, "%qE attribute ignored", name);
*no_add_attrs = true;
}
+ else
+ add_no_sanitize_value (*node,
+ SANITIZE_UNDEFINED | SANITIZE_UNDEFINED_NONDEFAULT);
return NULL_TREE;
}
@@ -1550,6 +1550,7 @@ extern enum flt_eval_method
excess_precision_mode_join (enum flt_eval_method, enum flt_eval_method);
extern int c_flt_eval_method (bool ts18661_p);
+extern void add_no_sanitize_value (tree node, unsigned int flags);
#if CHECKING_P
namespace selftest {
@@ -49,11 +49,11 @@ ubsan_instrument_division (location_t loc, tree op0, tree op1)
op1 = unshare_expr (op1);
if (TREE_CODE (type) == INTEGER_TYPE
- && (flag_sanitize & SANITIZE_DIVIDE))
+ && sanitize_flags_p (SANITIZE_DIVIDE))
t = fold_build2 (EQ_EXPR, boolean_type_node,
op1, build_int_cst (type, 0));
else if (TREE_CODE (type) == REAL_TYPE
- && (flag_sanitize & SANITIZE_FLOAT_DIVIDE))
+ && sanitize_flags_p (SANITIZE_FLOAT_DIVIDE))
t = fold_build2 (EQ_EXPR, boolean_type_node,
op1, build_real (type, dconst0));
else
@@ -61,7 +61,7 @@ ubsan_instrument_division (location_t loc, tree op0, tree op1)
/* We check INT_MIN / -1 only for signed types. */
if (TREE_CODE (type) == INTEGER_TYPE
- && (flag_sanitize & SANITIZE_DIVIDE)
+ && sanitize_flags_p (SANITIZE_DIVIDE)
&& !TYPE_UNSIGNED (type))
{
tree x;
@@ -131,7 +131,7 @@ ubsan_instrument_shift (location_t loc, enum tree_code code,
Also punt on bit-fields. */
if (TYPE_OVERFLOW_WRAPS (type0)
|| GET_MODE_BITSIZE (TYPE_MODE (type0)) != TYPE_PRECISION (type0)
- || (flag_sanitize & SANITIZE_SHIFT_BASE) == 0)
+ || !sanitize_flags_p (SANITIZE_SHIFT_BASE))
;
/* For signed x << y, in C99/C11, the following:
@@ -177,7 +177,7 @@ ubsan_instrument_shift (location_t loc, enum tree_code code,
tree else_t = void_node;
if (tt)
{
- if ((flag_sanitize & SANITIZE_SHIFT_EXPONENT) == 0)
+ if (!sanitize_flags_p (SANITIZE_SHIFT_EXPONENT))
{
t = fold_build1 (TRUTH_NOT_EXPR, boolean_type_node, t);
t = fold_build2 (TRUTH_AND_EXPR, boolean_type_node, t, tt);
@@ -300,7 +300,7 @@ ubsan_instrument_bounds (location_t loc, tree array, tree *index,
/* Detect flexible array members and suchlike, unless
-fsanitize=bounds-strict. */
tree base = get_base_address (array);
- if ((flag_sanitize & SANITIZE_BOUNDS_STRICT) == 0
+ if (!sanitize_flags_p (SANITIZE_BOUNDS_STRICT)
&& TREE_CODE (array) == COMPONENT_REF
&& base && (INDIRECT_REF_P (base) || TREE_CODE (base) == MEM_REF))
{
@@ -372,7 +372,7 @@ void
ubsan_maybe_instrument_array_ref (tree *expr_p, bool ignore_off_by_one)
{
if (!ubsan_array_ref_instrumented_p (*expr_p)
- && do_ubsan_in_current_function ())
+ && sanitize_flags_p (SANITIZE_BOUNDS | SANITIZE_BOUNDS_STRICT))
{
tree op0 = TREE_OPERAND (*expr_p, 0);
tree op1 = TREE_OPERAND (*expr_p, 1);
@@ -392,7 +392,7 @@ static tree
ubsan_maybe_instrument_reference_or_call (location_t loc, tree op, tree ptype,
enum ubsan_null_ckind ckind)
{
- if (!do_ubsan_in_current_function ())
+ if (!sanitize_flags_p (SANITIZE_ALIGNMENT | SANITIZE_NULL))
return NULL_TREE;
tree type = TREE_TYPE (ptype);
@@ -400,7 +400,7 @@ ubsan_maybe_instrument_reference_or_call (location_t loc, tree op, tree ptype,
bool instrument = false;
unsigned int mina = 0;
- if (flag_sanitize & SANITIZE_ALIGNMENT)
+ if (sanitize_flags_p (SANITIZE_ALIGNMENT))
{
mina = min_align_of_type (type);
if (mina <= 1)
@@ -418,7 +418,7 @@ ubsan_maybe_instrument_reference_or_call (location_t loc, tree op, tree ptype,
}
else
{
- if ((flag_sanitize & SANITIZE_NULL) && TREE_CODE (op) == ADDR_EXPR)
+ if (sanitize_flags_p (SANITIZE_NULL) && TREE_CODE (op) == ADDR_EXPR)
{
bool strict_overflow_p = false;
/* tree_single_nonzero_warnv_p will not return true for non-weak
@@ -434,7 +434,7 @@ ubsan_maybe_instrument_reference_or_call (location_t loc, tree op, tree ptype,
flag_delete_null_pointer_checks
= save_flag_delete_null_pointer_checks;
}
- else if (flag_sanitize & SANITIZE_NULL)
+ else if (sanitize_flags_p (SANITIZE_NULL))
instrument = true;
if (mina && mina > 1)
{
@@ -31,7 +31,4 @@ 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);
-/* Declare this here as well as in ubsan.h. */
-extern bool do_ubsan_in_current_function (void);
-
#endif /* GCC_C_UBSAN_H */
@@ -106,10 +106,9 @@ convert (tree type, tree expr)
case INTEGER_TYPE:
case ENUMERAL_TYPE:
- if (flag_sanitize & SANITIZE_FLOAT_CAST
+ if (sanitize_flags_p (SANITIZE_FLOAT_CAST)
&& TREE_CODE (TREE_TYPE (expr)) == REAL_TYPE
- && COMPLETE_TYPE_P (type)
- && do_ubsan_in_current_function ())
+ && COMPLETE_TYPE_P (type))
{
if (in_late_binary_op)
expr = save_expr (expr);
@@ -6051,9 +6051,8 @@ grokdeclarator (const struct c_declarator *declarator,
with known value. */
this_size_varies = size_varies = true;
warn_variable_length_array (name, size);
- if (flag_sanitize & SANITIZE_VLA
- && decl_context == NORMAL
- && do_ubsan_in_current_function ())
+ if (sanitize_flags_p (SANITIZE_VLA)
+ && decl_context == NORMAL)
{
/* Evaluate the array size only once. */
size = c_save_expr (size);
@@ -6320,7 +6320,7 @@ convert_for_assignment (location_t location, location_t expr_loc, tree type,
if (codel == BOOLEAN_TYPE || codel == COMPLEX_TYPE
|| (coder == REAL_TYPE
&& (codel == INTEGER_TYPE || codel == ENUMERAL_TYPE)
- && (flag_sanitize & SANITIZE_FLOAT_CAST)))
+ && sanitize_flags_p (SANITIZE_FLOAT_CAST)))
in_late_binary_op = true;
ret = convert_and_check (expr_loc != UNKNOWN_LOCATION
? expr_loc : location, type, orig_rhs);
@@ -9867,7 +9867,7 @@ c_finish_return (location_t loc, tree retval, tree origtype)
|| (TREE_CODE (TREE_TYPE (t)) == REAL_TYPE
&& (TREE_CODE (TREE_TYPE (res)) == INTEGER_TYPE
|| TREE_CODE (TREE_TYPE (res)) == ENUMERAL_TYPE)
- && (flag_sanitize & SANITIZE_FLOAT_CAST)))
+ && sanitize_flags_p (SANITIZE_FLOAT_CAST)))
in_late_binary_op = true;
inner = t = convert (TREE_TYPE (res), t);
in_late_binary_op = save;
@@ -11747,9 +11747,8 @@ build_binary_op (location_t location, enum tree_code code,
return error_mark_node;
}
- if ((flag_sanitize & (SANITIZE_SHIFT | SANITIZE_DIVIDE
- | SANITIZE_FLOAT_DIVIDE))
- && do_ubsan_in_current_function ()
+ if (sanitize_flags_p ((SANITIZE_SHIFT
+ | SANITIZE_DIVIDE | SANITIZE_FLOAT_DIVIDE))
&& (doing_div_or_mod || doing_shift)
&& !require_constant_value)
{
@@ -11758,10 +11757,10 @@ build_binary_op (location_t location, enum tree_code code,
op1 = c_save_expr (op1);
op0 = c_fully_fold (op0, false, NULL);
op1 = c_fully_fold (op1, false, NULL);
- if (doing_div_or_mod && (flag_sanitize & (SANITIZE_DIVIDE
- | SANITIZE_FLOAT_DIVIDE)))
+ if (doing_div_or_mod && (sanitize_flags_p ((SANITIZE_DIVIDE
+ | SANITIZE_FLOAT_DIVIDE))))
instrument_expr = ubsan_instrument_division (location, op0, op1);
- else if (doing_shift && (flag_sanitize & SANITIZE_SHIFT))
+ else if (doing_shift && sanitize_flags_p (SANITIZE_SHIFT))
instrument_expr = ubsan_instrument_shift (location, code, op0, op1);
}
@@ -224,7 +224,7 @@ unsigned int flag_sanitize
; What sanitizers should recover from errors
Variable
-unsigned int flag_sanitize_recover = (SANITIZE_UNDEFINED | SANITIZE_NONDEFAULT | SANITIZE_KERNEL_ADDRESS) & ~(SANITIZE_UNREACHABLE | SANITIZE_RETURN)
+unsigned int flag_sanitize_recover = (SANITIZE_UNDEFINED | SANITIZE_UNDEFINED_NONDEFAULT | SANITIZE_KERNEL_ADDRESS) & ~(SANITIZE_UNREACHABLE | SANITIZE_RETURN)
fsanitize-coverage=trace-pc
Common Report Var(flag_sanitize_coverage)
@@ -917,8 +917,7 @@ convert_to_integer_1 (tree type, tree expr, bool dofold)
return build1 (CONVERT_EXPR, type, expr);
case REAL_TYPE:
- if (flag_sanitize & SANITIZE_FLOAT_CAST
- && do_ubsan_in_current_function ())
+ if (sanitize_flags_p (SANITIZE_FLOAT_CAST))
{
expr = save_expr (expr);
tree check = ubsan_instrument_float_cast (loc, type, expr);
@@ -458,7 +458,8 @@ build_base_path (enum tree_code code,
else
{
tree t = expr;
- if ((flag_sanitize & SANITIZE_VPTR) && fixed_type_p == 0)
+ if (sanitize_flags_p (SANITIZE_VPTR)
+ && fixed_type_p == 0)
{
t = cp_ubsan_maybe_instrument_cast_to_vbase (input_location,
probe, expr);
@@ -1288,8 +1288,7 @@ cp_genericize_r (tree *stmt_p, int *walk_subtrees, void *data)
: OMP_CLAUSE_DEFAULT_PRIVATE);
}
}
- if (flag_sanitize
- & (SANITIZE_NULL | SANITIZE_ALIGNMENT | SANITIZE_VPTR))
+ if (sanitize_flags_p (SANITIZE_NULL | SANITIZE_ALIGNMENT | SANITIZE_VPTR))
{
/* The point here is to not sanitize static initializers. */
bool no_sanitize_p = wtd->no_sanitize_p;
@@ -1476,11 +1475,11 @@ cp_genericize_r (tree *stmt_p, int *walk_subtrees, void *data)
*stmt_p = cplus_expand_constant (stmt);
*walk_subtrees = 0;
}
- else if ((flag_sanitize
- & (SANITIZE_NULL | SANITIZE_ALIGNMENT | SANITIZE_VPTR))
+ else if (sanitize_flags_p ((SANITIZE_NULL
+ | SANITIZE_ALIGNMENT | SANITIZE_VPTR))
&& !wtd->no_sanitize_p)
{
- if ((flag_sanitize & (SANITIZE_NULL | SANITIZE_ALIGNMENT))
+ if (sanitize_flags_p (SANITIZE_NULL | SANITIZE_ALIGNMENT)
&& TREE_CODE (stmt) == NOP_EXPR
&& TREE_CODE (TREE_TYPE (stmt)) == REFERENCE_TYPE)
ubsan_maybe_instrument_reference (stmt);
@@ -1496,9 +1495,9 @@ cp_genericize_r (tree *stmt_p, int *walk_subtrees, void *data)
= TREE_CODE (fn) == ADDR_EXPR
&& TREE_CODE (TREE_OPERAND (fn, 0)) == FUNCTION_DECL
&& DECL_CONSTRUCTOR_P (TREE_OPERAND (fn, 0));
- if (flag_sanitize & (SANITIZE_NULL | SANITIZE_ALIGNMENT))
+ if (sanitize_flags_p (SANITIZE_NULL | SANITIZE_ALIGNMENT))
ubsan_maybe_instrument_member_call (stmt, is_ctor);
- if ((flag_sanitize & SANITIZE_VPTR) && !is_ctor)
+ if (sanitize_flags_p (SANITIZE_VPTR) && !is_ctor)
cp_ubsan_maybe_instrument_member_call (stmt);
}
}
@@ -1525,7 +1524,7 @@ cp_genericize_tree (tree* t_p, bool handle_invisiref_parm_p)
cp_walk_tree (t_p, cp_genericize_r, &wtd, NULL);
delete wtd.p_set;
wtd.bind_expr_stack.release ();
- if (flag_sanitize & SANITIZE_VPTR)
+ if (sanitize_flags_p (SANITIZE_VPTR))
cp_ubsan_instrument_member_accesses (t_p);
}
@@ -1648,8 +1647,7 @@ cp_genericize (tree fndecl)
walk_tree's hash functionality. */
cp_genericize_tree (&DECL_SAVED_TREE (fndecl), true);
- if (flag_sanitize & SANITIZE_RETURN
- && do_ubsan_in_current_function ())
+ if (sanitize_flags_p (SANITIZE_RETURN))
cp_ubsan_maybe_instrument_return (fndecl);
/* Do everything else. */
@@ -32,7 +32,7 @@ cp_ubsan_instrument_vptr_p (tree type)
if (!flag_rtti || flag_sanitize_undefined_trap_on_error)
return false;
- if (!do_ubsan_in_current_function ())
+ if (!sanitize_flags_p (SANITIZE_VPTR))
return false;
if (type)
@@ -9529,8 +9529,7 @@ compute_array_index_type (tree name, tree size, tsubst_flags_t complain)
stabilize_vla_size (itype);
- if (flag_sanitize & SANITIZE_VLA
- && do_ubsan_in_current_function ())
+ if (sanitize_flags_p (SANITIZE_VLA))
{
/* We have to add 1 -- in the ubsan routine we generate
LE_EXPR rather than LT_EXPR. */
@@ -15066,7 +15065,7 @@ start_preparsed_function (tree decl1, tree attrs, int flags)
if (!processing_template_decl
&& DECL_CONSTRUCTOR_P (decl1)
- && (flag_sanitize & SANITIZE_VPTR)
+ && sanitize_flags_p (SANITIZE_VPTR)
&& !DECL_CLONED_FUNCTION_P (decl1)
&& !implicit_default_ctor_p (decl1))
cp_ubsan_maybe_initialize_vtbl_ptrs (current_class_ptr);
@@ -3730,7 +3730,7 @@ one_static_initialization_or_destruction (tree decl, tree init, bool initp)
if (init)
{
finish_expr_stmt (init);
- if (flag_sanitize & SANITIZE_ADDRESS)
+ if (sanitize_flags_p (SANITIZE_ADDRESS, decl))
{
varpool_node *vnode = varpool_node::get (decl);
if (vnode)
@@ -3991,8 +3991,7 @@ build_vec_init (tree base, tree maxindex, tree init,
}
/* Don't check an array new when -fno-exceptions. */
}
- else if (flag_sanitize & SANITIZE_BOUNDS
- && do_ubsan_in_current_function ())
+ else if (sanitize_flags_p (SANITIZE_BOUNDS))
{
/* Make sure the last element of the initializer is in bounds. */
finish_expr_stmt
@@ -1099,9 +1099,7 @@ maybe_add_lambda_conv_op (tree type)
{
/* Don't UBsan this function; we're deliberately calling op() with a null
object argument. */
- tree attrs = build_tree_list (get_identifier ("no_sanitize_undefined"),
- NULL_TREE);
- cplus_decl_attributes (&fn, attrs, 0);
+ add_no_sanitize_value (fn, SANITIZE_UNDEFINED);
}
add_method (type, fn, NULL_TREE);
@@ -5167,10 +5167,9 @@ cp_build_binary_op (location_t location,
if (build_type == NULL_TREE)
build_type = result_type;
- if ((flag_sanitize & (SANITIZE_SHIFT | SANITIZE_DIVIDE
- | SANITIZE_FLOAT_DIVIDE))
+ if (sanitize_flags_p ((SANITIZE_SHIFT
+ | SANITIZE_DIVIDE | SANITIZE_FLOAT_DIVIDE))
&& !processing_template_decl
- && do_ubsan_in_current_function ()
&& (doing_div_or_mod || doing_shift))
{
/* OP0 and/or OP1 might have side-effects. */
@@ -5178,8 +5177,8 @@ cp_build_binary_op (location_t location,
op1 = cp_save_expr (op1);
op0 = fold_non_dependent_expr (op0);
op1 = fold_non_dependent_expr (op1);
- if (doing_div_or_mod && (flag_sanitize & (SANITIZE_DIVIDE
- | SANITIZE_FLOAT_DIVIDE)))
+ if (doing_div_or_mod
+ && sanitize_flags_p (SANITIZE_DIVIDE | SANITIZE_FLOAT_DIVIDE))
{
/* For diagnostics we want to use the promoted types without
shorten_binary_op. So convert the arguments to the
@@ -5193,7 +5192,7 @@ cp_build_binary_op (location_t location,
}
instrument_expr = ubsan_instrument_division (location, cop0, cop1);
}
- else if (doing_shift && (flag_sanitize & SANITIZE_SHIFT))
+ else if (doing_shift && sanitize_flags_p (SANITIZE_SHIFT))
instrument_expr = ubsan_instrument_shift (location, code, op0, op1);
}
@@ -6707,7 +6706,7 @@ build_static_cast_1 (tree type, tree expr, bool c_cast_p,
NULL, complain);
expr = build_address (expr);
- if (flag_sanitize & SANITIZE_VPTR)
+ if (sanitize_flags_p (SANITIZE_VPTR))
{
tree ubsan_check
= cp_ubsan_maybe_instrument_downcast (input_location, type,
@@ -6851,7 +6850,7 @@ build_static_cast_1 (tree type, tree expr, bool c_cast_p,
expr = build_base_path (MINUS_EXPR, expr, base, /*nonnull=*/false,
complain);
- if (flag_sanitize & SANITIZE_VPTR)
+ if (sanitize_flags_p (SANITIZE_VPTR))
{
tree ubsan_check
= cp_ubsan_maybe_instrument_downcast (input_location, type,
@@ -2894,6 +2894,18 @@ This has a similar effect
as the @option{-fno-toplevel-reorder} option, but only applies to the
marked symbols.
+@item no_sanitize ("@var{sanitize_option}")
+@cindex @code{no_sanitize} function attribute
+The @code{no_sanitize} attribute on functions is used
+to inform the compiler that it should not do sanitization of all options
+mentioned in @var{sanitize_option}. A list of values acceptable by
+@option{-fsanitize} option can be provided.
+
+@smallexample
+void __attribute__ ((no_sanitize ("alignment", "object-size")))
+f () @{ /* @r{Do something.} */; @}
+@end smallexample
+
@item no_sanitize_address
@itemx no_address_safety_analysis
@cindex @code{no_sanitize_address} function attribute
@@ -10770,6 +10770,8 @@ This option enables strict instrumentation of array bounds. Most out of bounds
accesses are detected, including flexible array members and flexible array
member-like arrays. Initializers of variables with static storage are not
instrumented.
+Unlike other similar options, @option{-fsanitize=bounds-strict} is
+not enabled by @option{-fsanitize=undefined}.
@item -fsanitize=alignment
@opindex fsanitize=alignment
@@ -246,8 +246,8 @@ enum sanitize_code {
| SANITIZE_NONNULL_ATTRIBUTE
| SANITIZE_RETURNS_NONNULL_ATTRIBUTE
| SANITIZE_OBJECT_SIZE | SANITIZE_VPTR,
- SANITIZE_NONDEFAULT = SANITIZE_FLOAT_DIVIDE | SANITIZE_FLOAT_CAST
- | SANITIZE_BOUNDS_STRICT
+ SANITIZE_UNDEFINED_NONDEFAULT = SANITIZE_FLOAT_DIVIDE | SANITIZE_FLOAT_CAST
+ | SANITIZE_BOUNDS_STRICT
};
/* flag_vtable_verify initialization levels. */
@@ -9312,7 +9312,8 @@ sanitize_spec_function (int argc, const char **argv)
if (strcmp (argv[0], "thread") == 0)
return (flag_sanitize & SANITIZE_THREAD) ? "" : NULL;
if (strcmp (argv[0], "undefined") == 0)
- return ((flag_sanitize & (SANITIZE_UNDEFINED | SANITIZE_NONDEFAULT))
+ return ((flag_sanitize
+ & (SANITIZE_UNDEFINED | SANITIZE_UNDEFINED_NONDEFAULT))
&& !flag_sanitize_undefined_trap_on_error) ? "" : NULL;
if (strcmp (argv[0], "leak") == 0)
return ((flag_sanitize
@@ -3442,7 +3442,7 @@ optimize_atomic_compare_exchange_p (gimple *stmt)
if (gimple_call_num_args (stmt) != 6
|| !flag_inline_atomics
|| !optimize
- || (flag_sanitize & (SANITIZE_THREAD | SANITIZE_ADDRESS)) != 0
+ || sanitize_flags_p (SANITIZE_THREAD | SANITIZE_ADDRESS)
|| !gimple_call_builtin_p (stmt, BUILT_IN_NORMAL)
|| !gimple_vdef (stmt)
|| !gimple_vuse (stmt))
@@ -1621,7 +1621,7 @@ gimplify_decl_expr (tree *stmt_p, gimple_seq *seq_p)
}
if (asan_sanitize_use_after_scope ()
- && !asan_no_sanitize_address_p ()
+ && sanitize_flags_p (SANITIZE_ADDRESS)
&& !is_vla
&& TREE_ADDRESSABLE (decl)
&& !TREE_STATIC (decl)
@@ -12594,8 +12594,7 @@ gimplify_function_tree (tree fndecl)
bind = new_bind;
}
- if ((flag_sanitize & SANITIZE_THREAD) != 0
- && !lookup_attribute ("no_sanitize_thread", DECL_ATTRIBUTES (fndecl)))
+ if (sanitize_flags_p (SANITIZE_THREAD))
{
gcall *call = gimple_build_call_internal (IFN_TSAN_FUNC_EXIT, 0);
gimple *tf = gimple_build_try (seq, call, GIMPLE_TRY_FINALLY);
@@ -256,17 +256,11 @@ report_inline_failed_reason (struct cgraph_edge *e)
static bool
sanitize_attrs_match_for_inline_p (const_tree caller, const_tree callee)
{
- /* Don't care if sanitizer is disabled */
- if (!(flag_sanitize & SANITIZE_ADDRESS))
- return true;
-
if (!caller || !callee)
return true;
- return !!lookup_attribute ("no_sanitize_address",
- DECL_ATTRIBUTES (caller)) ==
- !!lookup_attribute ("no_sanitize_address",
- DECL_ATTRIBUTES (callee));
+ return sanitize_flags_p (SANITIZE_ADDRESS, caller)
+ == sanitize_flags_p (SANITIZE_ADDRESS, callee);
}
/* Used for flags where it is safe to inline when caller's value is
@@ -1582,6 +1582,33 @@ parse_sanitizer_options (const char *p, location_t loc, int scode,
return flags;
}
+unsigned int
+parse_no_sanitize_attribute (char *value, char **wrong_argument)
+{
+ unsigned int flags = 0;
+ unsigned int i;
+ char *q = strtok (value, ",");
+
+ while (q != NULL)
+ {
+ for (i = 0; sanitizer_opts[i].name != NULL; ++i)
+ if (strcmp (sanitizer_opts[i].name, q) == 0)
+ {
+ flags |= sanitizer_opts[i].flag;
+ if (sanitizer_opts[i].flag == SANITIZE_UNDEFINED)
+ flags |= SANITIZE_UNDEFINED_NONDEFAULT;
+ break;
+ }
+
+ if (sanitizer_opts[i].name == NULL)
+ *wrong_argument = q;
+
+ q = strtok (NULL, ",");
+ }
+
+ return flags;
+}
+
/* Handle target- and language-independent options. Return zero to
generate an "unknown option" message. Only options that need
extra handling need to be listed here; if you simply want
@@ -1818,11 +1845,11 @@ common_handle_option (struct gcc_options *opts,
case OPT_fsanitize_recover:
if (value)
opts->x_flag_sanitize_recover
- |= (SANITIZE_UNDEFINED | SANITIZE_NONDEFAULT)
+ |= (SANITIZE_UNDEFINED | SANITIZE_UNDEFINED_NONDEFAULT)
& ~(SANITIZE_UNREACHABLE | SANITIZE_RETURN);
else
opts->x_flag_sanitize_recover
- &= ~(SANITIZE_UNDEFINED | SANITIZE_NONDEFAULT);
+ &= ~(SANITIZE_UNDEFINED | SANITIZE_UNDEFINED_NONDEFAULT);
break;
case OPT_O:
@@ -378,6 +378,8 @@ extern void print_ignored_options (void);
extern void handle_common_deferred_options (void);
unsigned int parse_sanitizer_options (const char *, location_t, int,
unsigned int, int, bool);
+
+unsigned int parse_no_sanitize_attribute (char *value, char **wrong_argument);
extern bool common_handle_option (struct gcc_options *opts,
struct gcc_options *opts_set,
const struct cl_decoded_option *decoded,
new file mode 100644
@@ -0,0 +1,56 @@
+/* Limit this to known non-strict alignment targets. */
+/* { dg-do run { target { i?86-*-linux* x86_64-*-linux* } } } */
+/* { dg-options "-fsanitize=alignment" } */
+
+struct S { int a; char b; long long c; short d[10]; };
+struct T { char a; long long b; };
+struct U { char a; int b; int c; long long d; struct S e; struct T f; } __attribute__((packed));
+struct V { long long a; struct S b; struct T c; struct U u; } v;
+
+__attribute__((noinline, noclone,no_sanitize(("shift,shift-base,shift-exponent,integer-divide-by-zero,unreachable,vla-bound,return,null,signed-integer-overflow,bool,enum,float-divide-by-zero,float-cast-overflow,bounds,bounds-strict,nonnull-attribute,returns-nonnull-attribute,object-size,vptr")))) void
+f1 (int *p, int *q, char *r, long long *s)
+{
+ *p =
+ *q
+ + *r
+ + *s;
+}
+
+
+__attribute__((noinline, noclone,no_sanitize(("shift,shift-base,shift-exponent,integer-divide-by-zero,unreachable,vla-bound,return,null,signed-integer-overflow,bool,enum,float-divide-by-zero,float-cast-overflow,bounds,bounds-strict,nonnull-attribute,returns-nonnull-attribute,object-size,vptr")))) int
+f2 (struct S *p)
+{
+ return p->a;
+}
+
+__attribute__((noinline, noclone,no_sanitize(("shift,shift-base,shift-exponent,integer-divide-by-zero,unreachable,vla-bound,return,null,signed-integer-overflow,bool,enum,float-divide-by-zero,float-cast-overflow,bounds,bounds-strict,nonnull-attribute,returns-nonnull-attribute,object-size,vptr")))) long long
+f3 (struct S *p, int i)
+{
+ return p->c
+ + p->d[1]
+ + p->d[i];
+}
+
+__attribute__((noinline, noclone,no_sanitize(("shift,shift-base,shift-exponent,integer-divide-by-zero,unreachable,vla-bound,return,null,signed-integer-overflow,bool,enum,float-divide-by-zero,float-cast-overflow,bounds,bounds-strict,nonnull-attribute,returns-nonnull-attribute,object-size,vptr")))) long long
+f4 (long long *p)
+{
+ return *p;
+}
+
+int
+main ()
+{
+ f1 (&v.u.b, &v.u.c, &v.u.a, &v.u.d);
+ if (f2 (&v.u.e) + f3 (&v.u.e, 4) + f4 (&v.u.f.b) != 0)
+ __builtin_abort ();
+ return 0;
+}
+
+/* { dg-output "\.c:(14|15):\[0-9]*: \[^\n\r]*load of misaligned address 0x\[0-9a-fA-F]* for type 'int', which requires 4 byte alignment.*" } */
+/* { dg-output "\.c:16:\[0-9]*: \[^\n\r]*load of misaligned address 0x\[0-9a-fA-F]* for type 'long long int', which requires \[48] byte alignment.*" } */
+/* { dg-output "\.c:(13|16):\[0-9]*: \[^\n\r]*store to misaligned address 0x\[0-9a-fA-F]* for type 'int', which requires 4 byte alignment.*" } */
+/* { dg-output "\.c:23:\[0-9]*: \[^\n\r]*member access within misaligned address 0x\[0-9a-fA-F]* for type 'struct S', which requires \[48] byte alignment.*" } */
+/* { dg-output "\.c:(29|30):\[0-9]*: \[^\n\r]*member access within misaligned address 0x\[0-9a-fA-F]* for type 'struct S', which requires \[48] byte alignment.*" } */
+/* { dg-output "\.c:30:\[0-9]*: \[^\n\r]*member access within misaligned address 0x\[0-9a-fA-F]* for type 'struct S', which requires \[48] byte alignment.*" } */
+/* { dg-output "\.c:31:\[0-9]*: \[^\n\r]*member access within misaligned address 0x\[0-9a-fA-F]* for type 'struct S', which requires \[48] byte alignment.*" } */
+/* { dg-output "\.c:37:\[0-9]*: \[^\n\r]*load of misaligned address 0x\[0-9a-fA-F]* for type 'long long int', which requires \[48] byte alignment" } */
new file mode 100644
@@ -0,0 +1,12 @@
+/* { dg-do compile } */
+/* { dg-options "-fsanitize=undefined" } */
+
+struct S { int a[16]; };
+
+__attribute__((no_sanitize(("undefined")))) long long
+foo (int *a, long long *b, struct S *c)
+{
+ return a[1] + *b + c->a[a[0]];
+}
+
+/* { dg-final { scan-assembler-not "__ubsan_handle" } } */
new file mode 100644
@@ -0,0 +1,15 @@
+/* { dg-do compile } */
+/* { dg-options "-fsanitize=undefined" } */
+
+/* Test that we don't instrument functions marked with
+ no_sanitize_undefined attribute. */
+
+struct S { int a[16]; };
+
+__attribute__((no_sanitize("signed-integer-overflow,null,alignment"))) long long
+foo (int *a, long long *b, struct S *c)
+{
+ return a[1] + *b + c->a[a[0]];
+}
+
+/* { dg-final { scan-assembler-not "__ubsan_handle" } } */
new file mode 100644
@@ -0,0 +1,17 @@
+/* { dg-do run } */
+/* { dg-options "-fsanitize=bounds-strict" } */
+
+struct V { int l; int a[1]; };
+
+int
+__attribute__((no_sanitize(("shift,shift-base,shift-exponent,integer-divide-by-zero,unreachable,vla-bound,return,null,signed-integer-overflow,bool,enum,float-divide-by-zero,float-cast-overflow,bounds,alignment,nonnull-attribute,returns-nonnull-attribute,object-size,vptr"))))
+main (void)
+{
+ /* For strict, do instrument last array in a struct. */
+ struct V *v = (struct V *) __builtin_malloc (sizeof (struct V) + 10);
+ v->a[1] = 1;
+
+ return 0;
+}
+
+/* { dg-output "index 1 out of bounds for type 'int \\\[1\\\]'" } */
new file mode 100644
@@ -0,0 +1,9 @@
+/* { dg-do compile } */
+/* { dg-options "-fsanitize=integer-divide-by-zero" } */
+
+void
+__attribute__((no_sanitize(("shift,shift-base,shift-exponent,unreachable,vla-bound,return,null,signed-integer-overflow,bool,enum,float-divide-by-zero,float-cast-overflow,bounds,bounds-strict,alignment,nonnull-attribute,returns-nonnull-attribute,object-size,vptr"))))
+foo (void)
+{
+ int A[-2 / -1] = {};
+}
new file mode 100644
@@ -0,0 +1,205 @@
+/* { dg-do run { target { lp64 || ilp32 } } } */
+/* { dg-options "-fsanitize=float-cast-overflow" } */
+/* { dg-additional-options "-msse2 -mfpmath=sse" { target { sse2_runtime && ia32 } } } */
+
+#include <limits.h>
+#include "float-cast.h"
+
+int
+__attribute__((no_sanitize(("shift,shift-base,shift-exponent,integer-divide-by-zero,unreachable,vla-bound,return,null,signed-integer-overflow,bool,enum,float-divide-by-zero,bounds,bounds-strict,alignment,nonnull-attribute,returns-nonnull-attribute,object-size,vptr"))))
+main (void)
+{
+ const double inf = __builtin_inf ();
+ const double nan = __builtin_nan ("");
+ volatile double d;
+
+ volatile signed char sc;
+ d = SCHAR_MIN;
+ CHECK_BOUNDARY (sc, d);
+ d = 0.0;
+ CHECK_BOUNDARY (sc, d);
+ d = SCHAR_MAX;
+ CHECK_BOUNDARY (sc, d);
+ CHECK_NONNUMBERS (sc);
+
+ volatile unsigned char uc;
+ d = UCHAR_MAX;
+ CHECK_BOUNDARY (uc, d);
+ d = 0.0;
+ CHECK_BOUNDARY (uc, d);
+ CHECK_NONNUMBERS (uc);
+
+ volatile short int s;
+ d = SHRT_MIN;
+ CHECK_BOUNDARY (s, d);
+ d = 0.0;
+ CHECK_BOUNDARY (s, d);
+ d = SHRT_MAX;
+ CHECK_BOUNDARY (s, d);
+ CHECK_NONNUMBERS (s);
+
+ volatile unsigned short int us;
+ d = USHRT_MAX;
+ CHECK_BOUNDARY (us, d);
+ d = 0.0;
+ CHECK_BOUNDARY (us, d);
+ CHECK_NONNUMBERS (us);
+
+ volatile int i;
+ d = INT_MIN;
+ CHECK_BOUNDARY (i, d);
+ d = 0.0;
+ CHECK_BOUNDARY (i, d);
+ d = INT_MAX;
+ CHECK_BOUNDARY (i, d);
+ CHECK_NONNUMBERS (i);
+
+ volatile unsigned int u;
+ d = UINT_MAX;
+ CHECK_BOUNDARY (u, d);
+ d = 0.0;
+ CHECK_BOUNDARY (u, d);
+ CHECK_NONNUMBERS (u);
+
+ volatile long l;
+ /* 64-bit vs 32-bit longs matter causes too much of a headache. */
+ d = 0.0;
+ CHECK_BOUNDARY (l, d);
+ CHECK_NONNUMBERS (l);
+
+ volatile unsigned long ul;
+ d = 0.0;
+ CHECK_BOUNDARY (ul, d);
+ CHECK_NONNUMBERS (ul);
+
+ volatile long long ll;
+ d = LLONG_MIN;
+ CHECK_BOUNDARY (ll, d);
+ d = 0.0;
+ CHECK_BOUNDARY (ll, d);
+ d = LLONG_MAX;
+ CHECK_BOUNDARY (ll, d);
+ CHECK_NONNUMBERS (ll);
+
+ volatile unsigned long long ull;
+ d = ULLONG_MAX;
+ CHECK_BOUNDARY (ull, d);
+ d = 0.0;
+ CHECK_BOUNDARY (ull, d);
+ CHECK_NONNUMBERS (ull);
+
+ return 0;
+}
+
+/* { dg-output "value -133 is outside the range of representable values of type 'signed char'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value -129.5 is outside the range of representable values of type 'signed char'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value -129 is outside the range of representable values of type 'signed char'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value 128 is outside the range of representable values of type 'signed char'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value 128.5 is outside the range of representable values of type 'signed char'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value 132 is outside the range of representable values of type 'signed char'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value nan is outside the range of representable values of type 'signed char'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value -?nan is outside the range of representable values of type 'signed char'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value inf is outside the range of representable values of type 'signed char'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value -inf is outside the range of representable values of type 'signed char'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value 256 is outside the range of representable values of type 'unsigned char'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value 256.5 is outside the range of representable values of type 'unsigned char'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value 260 is outside the range of representable values of type 'unsigned char'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value -5 is outside the range of representable values of type 'unsigned char'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value -1.5 is outside the range of representable values of type 'unsigned char'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value -1 is outside the range of representable values of type 'unsigned char'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value nan is outside the range of representable values of type 'unsigned char'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value -?nan is outside the range of representable values of type 'unsigned char'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value inf is outside the range of representable values of type 'unsigned char'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value -inf is outside the range of representable values of type 'unsigned char'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value -32773 is outside the range of representable values of type 'short int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value -32769.5 is outside the range of representable values of type 'short int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value -32769 is outside the range of representable values of type 'short int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value 32768 is outside the range of representable values of type 'short int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value 32768.5 is outside the range of representable values of type 'short int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value 32772 is outside the range of representable values of type 'short int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value nan is outside the range of representable values of type 'short int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value -?nan is outside the range of representable values of type 'short int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value inf is outside the range of representable values of type 'short int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value -inf is outside the range of representable values of type 'short int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value 65536 is outside the range of representable values of type 'short unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value 65536.5 is outside the range of representable values of type 'short unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value 65540 is outside the range of representable values of type 'short unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value -5 is outside the range of representable values of type 'short unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value -1.5 is outside the range of representable values of type 'short unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value -1 is outside the range of representable values of type 'short unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value nan is outside the range of representable values of type 'short unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value -?nan is outside the range of representable values of type 'short unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value inf is outside the range of representable values of type 'short unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value -inf is outside the range of representable values of type 'short unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value -2.14748e\\\+09 is outside the range of representable values of type 'int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value -2.14748e\\\+09 is outside the range of representable values of type 'int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value -2.14748e\\\+09 is outside the range of representable values of type 'int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value 2.14748e\\\+09 is outside the range of representable values of type 'int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value 2.14748e\\\+09 is outside the range of representable values of type 'int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value 2.14748e\\\+09 is outside the range of representable values of type 'int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value nan is outside the range of representable values of type 'int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value -?nan is outside the range of representable values of type 'int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value inf is outside the range of representable values of type 'int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value -inf is outside the range of representable values of type 'int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value 4.29497e\\\+09 is outside the range of representable values of type 'unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value 4.29497e\\\+09 is outside the range of representable values of type 'unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value 4.29497e\\\+09 is outside the range of representable values of type 'unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value -5 is outside the range of representable values of type 'unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value -1.5 is outside the range of representable values of type 'unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value -1 is outside the range of representable values of type 'unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value nan is outside the range of representable values of type 'unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value -?nan is outside the range of representable values of type 'unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value inf is outside the range of representable values of type 'unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value -inf is outside the range of representable values of type 'unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value nan is outside the range of representable values of type 'long int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value -?nan is outside the range of representable values of type 'long int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value inf is outside the range of representable values of type 'long int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value -inf is outside the range of representable values of type 'long int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value -5 is outside the range of representable values of type 'long unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value -1.5 is outside the range of representable values of type 'long unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value -1 is outside the range of representable values of type 'long unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value nan is outside the range of representable values of type 'long unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value -?nan is outside the range of representable values of type 'long unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value inf is outside the range of representable values of type 'long unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value -inf is outside the range of representable values of type 'long unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value 9.22337e\\\+18 is outside the range of representable values of type 'long long int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value 9.22337e\\\+18 is outside the range of representable values of type 'long long int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value 9.22337e\\\+18 is outside the range of representable values of type 'long long int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value 9.22337e\\\+18 is outside the range of representable values of type 'long long int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value 9.22337e\\\+18 is outside the range of representable values of type 'long long int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value 9.22337e\\\+18 is outside the range of representable values of type 'long long int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value 9.22337e\\\+18 is outside the range of representable values of type 'long long int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value 9.22337e\\\+18 is outside the range of representable values of type 'long long int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value 9.22337e\\\+18 is outside the range of representable values of type 'long long int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value 9.22337e\\\+18 is outside the range of representable values of type 'long long int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value 9.22337e\\\+18 is outside the range of representable values of type 'long long int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value 9.22337e\\\+18 is outside the range of representable values of type 'long long int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value 9.22337e\\\+18 is outside the range of representable values of type 'long long int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value 9.22337e\\\+18 is outside the range of representable values of type 'long long int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value 9.22337e\\\+18 is outside the range of representable values of type 'long long int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value nan is outside the range of representable values of type 'long long int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value -?nan is outside the range of representable values of type 'long long int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value inf is outside the range of representable values of type 'long long int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value -inf is outside the range of representable values of type 'long long int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value 1.84467e\\\+19 is outside the range of representable values of type 'long long unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value 1.84467e\\\+19 is outside the range of representable values of type 'long long unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value 1.84467e\\\+19 is outside the range of representable values of type 'long long unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value 1.84467e\\\+19 is outside the range of representable values of type 'long long unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value 1.84467e\\\+19 is outside the range of representable values of type 'long long unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value 1.84467e\\\+19 is outside the range of representable values of type 'long long unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value 1.84467e\\\+19 is outside the range of representable values of type 'long long unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value 1.84467e\\\+19 is outside the range of representable values of type 'long long unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value 1.84467e\\\+19 is outside the range of representable values of type 'long long unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value 1.84467e\\\+19 is outside the range of representable values of type 'long long unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value 1.84467e\\\+19 is outside the range of representable values of type 'long long unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value 1.84467e\\\+19 is outside the range of representable values of type 'long long unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value 1.84467e\\\+19 is outside the range of representable values of type 'long long unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value 1.84467e\\\+19 is outside the range of representable values of type 'long long unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value 1.84467e\\\+19 is outside the range of representable values of type 'long long unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value -5 is outside the range of representable values of type 'long long unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value -1.5 is outside the range of representable values of type 'long long unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value -1 is outside the range of representable values of type 'long long unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value nan is outside the range of representable values of type 'long long unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value -?nan is outside the range of representable values of type 'long long unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value inf is outside the range of representable values of type 'long long unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*value -inf is outside the range of representable values of type 'long long unsigned int'" } */
new file mode 100644
@@ -0,0 +1,27 @@
+/* { dg-do run } */
+/* { dg-options "-fsanitize=float-divide-by-zero" } */
+
+int
+__attribute__((no_sanitize(("shift,shift-base,shift-exponent,integer-divide-by-zero,unreachable,vla-bound,return,null,signed-integer-overflow,bool,enum,float-cast-overflow,bounds,bounds-strict,alignment,nonnull-attribute,returns-nonnull-attribute,object-size,vptr"))))
+main (void)
+{
+ volatile float a = 1.3f;
+ volatile double b = 0.0;
+ volatile int c = 4;
+ volatile float res;
+
+ res = a / b;
+ res = a / 0.0;
+ res = 2.7f / b;
+ res = 3.6 / (b = 0.0, b);
+ res = c / b;
+ res = b / c;
+
+ return 0;
+}
+
+/* { dg-output "division by zero\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*division by zero\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*division by zero\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*division by zero\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*division by zero\[^\n\r]*" } */
new file mode 100644
@@ -0,0 +1,31 @@
+/* { dg-do run } */
+/* { dg-options "-fsanitize=bool,enum" } */
+
+#ifndef __cplusplus
+#define bool _Bool
+#endif
+enum A { B = -3, C = 2 } a;
+bool b;
+
+__attribute__((noinline, noclone)) enum A
+__attribute__((no_sanitize(("shift,shift-base,shift-exponent,integer-divide-by-zero,unreachable,vla-bound,return,null,signed-integer-overflow,float-divide-by-zero,float-cast-overflow,bounds,bounds-strict,alignment,nonnull-attribute,returns-nonnull-attribute,object-size,vptr"))))
+foo (bool *p)
+{
+ *p = b; /* { dg-output "load-bool-enum-2.c:14:\[^\n\r]*runtime error: \[^\n\r]*load of value 4, which is not a valid value for type '(_B|b)ool'\[^\n\r]*(\n|\r\n|\r)*" } */
+ return a; /* { dg-output "\[^\n\r]*load-bool-enum-2.c:15:\[^\n\r]*runtime error: \[^\n\r]*load of value 9, which is not a valid value for type 'A'" { target c++ } } */
+}
+
+int
+__attribute__((no_sanitize(("shift,shift-base,shift-exponent,integer-divide-by-zero,unreachable,vla-bound,return,null,signed-integer-overflow,float-divide-by-zero,float-cast-overflow,bounds,bounds-strict,alignment,nonnull-attribute,returns-nonnull-attribute,object-size,vptr"))))
+main ()
+{
+ char c = 4;
+ int d = 9;
+ if (sizeof (int) != sizeof (a) || sizeof (b) != 1)
+ return 0;
+ __builtin_memcpy (&a, &d, sizeof (int));
+ __builtin_memcpy (&b, &c, 1);
+ bool e;
+ foo (&e);
+ return 0;
+}
new file mode 100644
@@ -0,0 +1,40 @@
+/* { dg-do run } */
+/* { dg-options "-fsanitize=nonnull-attribute,returns-nonnull-attribute" } */
+
+int q, r;
+void *a, *b, *c = (void *) &q, *d, *e, *f = (void *) &q, *g, *h;
+
+__attribute__((returns_nonnull, nonnull (1, 3),no_sanitize(("shift,shift-base,shift-exponent,integer-divide-by-zero,unreachable,vla-bound,return,null,signed-integer-overflow,bool,enum,float-divide-by-zero,float-cast-overflow,bounds,bounds-strict,alignment,object-size,vptr"))))
+void *
+foo (void *p, void *q, void *r)
+{
+ a = p;
+ b = r;
+ return q;
+}
+
+int
+__attribute__((no_sanitize(("shift,shift-base,shift-exponent,integer-divide-by-zero,unreachable,vla-bound,return,null,signed-integer-overflow,bool,enum,float-divide-by-zero,float-cast-overflow,bounds,bounds-strict,alignment,object-size,vptr"))))
+bar (const void *a, const void *b)
+{
+ int c = *(const int *) a;
+ int d = *(const int *) b;
+ return c - d;
+}
+
+int
+__attribute__((no_sanitize(("shift,shift-base,shift-exponent,integer-divide-by-zero,unreachable,vla-bound,return,null,signed-integer-overflow,bool,enum,float-divide-by-zero,float-cast-overflow,bounds,bounds-strict,alignment,object-size,vptr"))))
+main ()
+{
+ asm volatile ("" : : : "memory");
+ d = foo (c, b, c);
+ e = foo (e, c, f);
+ g = foo (c, f, g);
+ __builtin_memset (d, '\0', q);
+ return 0;
+}
+
+/* { dg-output "\.c:13:\[0-9]*:\[^\n\r]*null pointer returned from function declared to never return null\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*\.c:31:\[0-9]*:\[^\n\r]*null pointer passed as argument 1, which is declared to never be null\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*\.c:32:\[0-9]*:\[^\n\r]*null pointer passed as argument 3, which is declared to never be null\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*\.c:33:\[0-9]*:\[^\n\r]*null pointer passed as argument 1, which is declared to never be null" } */
new file mode 100644
@@ -0,0 +1,13 @@
+/* { dg-do run } */
+/* { dg-options "-fsanitize=null -w" } */
+/* { dg-shouldfail "ubsan" } */
+
+int
+__attribute__((no_sanitize(("shift,shift-base,shift-exponent,integer-divide-by-zero,unreachable,vla-bound,return,signed-integer-overflow,bool,enum,float-divide-by-zero,float-cast-overflow,bounds,bounds-strict,alignment,nonnull-attribute,returns-nonnull-attribute,object-size,vptr"))))
+main (void)
+{
+ int *p = 0;
+ return *p;
+}
+
+/* { dg-output "load of null pointer of type 'int'" } */
new file mode 100644
@@ -0,0 +1,131 @@
+/* { dg-do run } */
+/* { dg-skip-if "" { *-*-* } { "*" } { "-O2" } } */
+/* { dg-options "-fsanitize=undefined" } */
+
+/* Sanity-test -fsanitize=object-size. We use -fsanitize=undefined option
+ to check that this feature doesn't clash with -fsanitize=bounds et al. */
+
+#define N 20
+
+__attribute__((noinline, noclone)) void
+__attribute__((no_sanitize(("shift,shift-base,shift-exponent,integer-divide-by-zero,unreachable,vla-bound,return,null,signed-integer-overflow,bool,enum,float-divide-by-zero,float-cast-overflow,bounds,bounds-strict,alignment,nonnull-attribute,returns-nonnull-attribute,vptr"))))
+f1 (int i)
+{
+ volatile int j;
+ char *p, *orig;
+ orig = p = (char *) __builtin_calloc (N, 1);
+ j = *(p + i);
+ j = p[i];
+ p++;
+ j = p[i - 1];
+ j = *(p + i - 1);
+ __builtin_free (orig);
+}
+
+/* { dg-output "load of address \[^\n\r]* with insufficient space for an object of type 'char'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*note: pointer points here\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*\\^\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*load of address \[^\n\r]* with insufficient space for an object of type 'char'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*note: pointer points here\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*\\^\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*load of address \[^\n\r]* with insufficient space for an object of type 'char'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*note: pointer points here\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*\\^\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*load of address \[^\n\r]* with insufficient space for an object of type 'char'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*note: pointer points here\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*\\^\[^\n\r]*(\n|\r\n|\r)" } */
+
+__attribute__((noinline, noclone)) void
+__attribute__((no_sanitize(("shift,shift-base,shift-exponent,integer-divide-by-zero,unreachable,vla-bound,return,null,signed-integer-overflow,bool,enum,float-divide-by-zero,float-cast-overflow,bounds,bounds-strict,alignment,nonnull-attribute,returns-nonnull-attribute,vptr"))))
+f2 (int i)
+{
+ volatile int j;
+ char a[N];
+ __builtin_memset (a, 0, N);
+ j = *(a + i);
+ char *p = a;
+ j = *(p + i);
+ j = p[i];
+ p += 10;
+ j = *(p + i - 10);
+ j = p[i - 10];
+}
+
+/* { dg-output "\[^\n\r]*load of address \[^\n\r]* with insufficient space for an object of type 'char'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*note: pointer points here\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*\\^\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*load of address \[^\n\r]* with insufficient space for an object of type 'char'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*note: pointer points here\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*\\^\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*load of address \[^\n\r]* with insufficient space for an object of type 'char'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*note: pointer points here\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*\\^\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*load of address \[^\n\r]* with insufficient space for an object of type 'char'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*note: pointer points here\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*\\^\[^\n\r]*(\n|\r\n|\r)" } */
+
+__attribute__((noinline, noclone)) void
+__attribute__((no_sanitize(("shift,shift-base,shift-exponent,integer-divide-by-zero,unreachable,vla-bound,return,null,signed-integer-overflow,bool,enum,float-divide-by-zero,float-cast-overflow,bounds,bounds-strict,alignment,nonnull-attribute,returns-nonnull-attribute,vptr"))))
+f3 (int i)
+{
+ volatile int j;
+ int *p = (int *) __builtin_calloc (N, sizeof (*p));
+ int *o = &p[i];
+ j = *o;
+ j = o[0];
+ __builtin_free (p);
+}
+
+/* { dg-output "\[^\n\r]*load of address \[^\n\r]* with insufficient space for an object of type 'int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*note: pointer points here\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*\\^\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*load of address \[^\n\r]* with insufficient space for an object of type 'int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*note: pointer points here\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*\\^\[^\n\r]*(\n|\r\n|\r)" } */
+
+__attribute__((noinline, noclone)) void
+__attribute__((no_sanitize(("shift,shift-base,shift-exponent,integer-divide-by-zero,unreachable,vla-bound,return,null,signed-integer-overflow,bool,enum,float-divide-by-zero,float-cast-overflow,bounds,bounds-strict,alignment,nonnull-attribute,returns-nonnull-attribute,vptr"))))
+f4 (void)
+{
+ /* The second argument to __builtin_calloc is intentional. */
+ int *p = (int *) __builtin_calloc (3, 1);
+ *p = 42;
+ __builtin_free (p);
+}
+
+/* { dg-output "\[^\n\r]*store to address \[^\n\r]* with insufficient space for an object of type 'int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*note: pointer points here\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*\\^" } */
+
+__attribute__((noinline, noclone)) void
+__attribute__((no_sanitize(("shift,shift-base,shift-exponent,integer-divide-by-zero,unreachable,vla-bound,return,null,signed-integer-overflow,bool,enum,float-divide-by-zero,float-cast-overflow,bounds,bounds-strict,alignment,nonnull-attribute,returns-nonnull-attribute,vptr"))))
+f5 (int *p)
+{
+ /* This is not instrumented. But don't ICE, etc. */
+ volatile int i = p[N];
+}
+
+int
+__attribute__((no_sanitize(("shift,shift-base,shift-exponent,integer-divide-by-zero,unreachable,vla-bound,return,null,signed-integer-overflow,bool,enum,float-divide-by-zero,float-cast-overflow,bounds,bounds-strict,alignment,nonnull-attribute,returns-nonnull-attribute,vptr"))))
+main ()
+{
+ f1 (N);
+ f2 (N);
+ f3 (N);
+ f4 ();
+ int *p = (int *) __builtin_calloc (N, sizeof (*p));
+ f5 (p);
+ __builtin_free (p);
+ return 0;
+}
new file mode 100644
@@ -0,0 +1,262 @@
+/* { dg-do run } */
+/* { dg-options "-fsanitize=signed-integer-overflow -fno-sanitize-recover=signed-integer-overflow" } */
+
+#ifndef ASM1
+# define ASM1(a) /* Nothing */
+#endif
+#ifndef ASM2
+# define ASM2(a, b) /* Nothing */
+#endif
+
+#define CHECK(A, B) ({ if ((A) != (B)) __builtin_abort (); })
+
+#define FN1(T1, T2, OP) \
+ ({ \
+ T1 a = 14; \
+ T2 b = 9; \
+ ASM2 (a, b); \
+ a OP b; \
+ })
+
+#define FN2(T, OP) \
+ ({ \
+ T a = 14; \
+ ASM1 (a); \
+ a OP 7; \
+ })
+
+#define FN3(T1, T2, OP) \
+ ({ \
+ T1 a = 4; \
+ T2 b = 1; \
+ ASM2 (a, b); \
+ ~a OP b; \
+ })
+
+#define FN4(T1, T2, OP) \
+ ({ \
+ T1 a = 4; \
+ T2 b = 1; \
+ ASM2 (a, b); \
+ a OP ~b; \
+ })
+
+#define FN5(T) \
+ ({ \
+ T a = 77; \
+ ASM1 (a); \
+ -a; \
+ })
+
+int
+__attribute__((no_sanitize(("shift,shift-base,shift-exponent,integer-divide-by-zero,unreachable,vla-bound,return,null,bool,enum,float-divide-by-zero,float-cast-overflow,bounds,bounds-strict,alignment,nonnull-attribute,returns-nonnull-attribute,object-size,vptr"))))
+main (void)
+{
+ CHECK (FN1 (char, char, +), 23);
+ CHECK (FN1 (char, char, -), 5);
+ CHECK (FN1 (char, char, *), 126);
+ CHECK (FN1 (unsigned char, unsigned char, +), 23);
+ CHECK (FN1 (unsigned char, unsigned char, -), 5);
+ CHECK (FN1 (unsigned char, unsigned char, *), 126);
+ CHECK (FN1 (short, short, +), 23);
+ CHECK (FN1 (short, short, -), 5);
+ CHECK (FN1 (short, short, *), 126);
+ CHECK (FN1 (unsigned short, unsigned short, +), 23);
+ CHECK (FN1 (unsigned short, unsigned short, -), 5);
+ CHECK (FN1 (unsigned short, unsigned short, *), 126);
+ CHECK (FN1 (int, int, +), 23);
+ CHECK (FN1 (int, int, -), 5);
+ CHECK (FN1 (int, int, *), 126);
+ CHECK (FN1 (unsigned int, unsigned int, +), 23);
+ CHECK (FN1 (unsigned int, unsigned int, -), 5);
+ CHECK (FN1 (unsigned int, unsigned int, *), 126);
+ CHECK (FN1 (long int, long int, +), 23);
+ CHECK (FN1 (long int, long int, -), 5);
+ CHECK (FN1 (long int, long int, *), 126);
+ CHECK (FN1 (unsigned long int, unsigned long int, +), 23);
+ CHECK (FN1 (unsigned long int, unsigned long int, -), 5);
+ CHECK (FN1 (unsigned long int, unsigned long int, *), 126);
+ CHECK (FN1 (long long int, long int, +), 23);
+ CHECK (FN1 (long long int, long int, -), 5);
+ CHECK (FN1 (long long int, long int, *), 126);
+ CHECK (FN1 (unsigned long long int, unsigned long long int, +), 23);
+ CHECK (FN1 (unsigned long long int, unsigned long long int, -), 5);
+ CHECK (FN1 (unsigned long long int, unsigned long long int, *), 126);
+ CHECK (FN1 (int, unsigned char, +), 23);
+ CHECK (FN1 (int, unsigned char, -), 5);
+ CHECK (FN1 (int, unsigned char, *), 126);
+ CHECK (FN1 (unsigned char, int, +), 23);
+ CHECK (FN1 (unsigned char, int, -), 5);
+ CHECK (FN1 (unsigned char, int, *), 126);
+ CHECK (FN1 (int, long int, +), 23);
+ CHECK (FN1 (int, long int, -), 5);
+ CHECK (FN1 (int, long int, *), 126);
+ CHECK (FN1 (long int, int, +), 23);
+ CHECK (FN1 (long int, int, -), 5);
+ CHECK (FN1 (long int, int, *), 126);
+ CHECK (FN1 (unsigned int, int, +), 23);
+ CHECK (FN1 (unsigned int, int, -), 5);
+ CHECK (FN1 (unsigned int, int, *), 126);
+ CHECK (FN1 (int, unsigned int, +), 23);
+ CHECK (FN1 (int, unsigned int, -), 5);
+ CHECK (FN1 (int, unsigned int, *), 126);
+ CHECK (FN1 (unsigned long int, int, +), 23);
+ CHECK (FN1 (unsigned long int, int, -), 5);
+ CHECK (FN1 (unsigned long int, int, *), 126);
+ CHECK (FN1 (int, unsigned long int, +), 23);
+ CHECK (FN1 (int, unsigned long int, -), 5);
+ CHECK (FN1 (int, unsigned long int, *), 126);
+
+ CHECK (FN2 (char, +), 21);
+ CHECK (FN2 (char, -), 7);
+ CHECK (FN2 (char, *), 98);
+ CHECK (FN2 (unsigned char, +), 21);
+ CHECK (FN2 (unsigned char, -), 7);
+ CHECK (FN2 (unsigned char, *), 98);
+ CHECK (FN2 (short, +), 21);
+ CHECK (FN2 (short, -), 7);
+ CHECK (FN2 (short, *), 98);
+ CHECK (FN2 (unsigned short, +), 21);
+ CHECK (FN2 (unsigned short, -), 7);
+ CHECK (FN2 (unsigned short, *), 98);
+ CHECK (FN2 (int, +), 21);
+ CHECK (FN2 (int, -), 7);
+ CHECK (FN2 (int, *), 98);
+ CHECK (FN2 (unsigned int, +), 21);
+ CHECK (FN2 (unsigned int, -), 7);
+ CHECK (FN2 (unsigned int, *), 98);
+ CHECK (FN2 (long int, +), 21);
+ CHECK (FN2 (long int, -), 7);
+ CHECK (FN2 (long int, *), 98);
+ CHECK (FN2 (unsigned long int, +), 21);
+ CHECK (FN2 (unsigned long int, -), 7);
+ CHECK (FN2 (unsigned long int, *), 98);
+ CHECK (FN2 (long long int, +), 21);
+ CHECK (FN2 (long long int, -), 7);
+ CHECK (FN2 (long long int, *), 98);
+ CHECK (FN2 (unsigned long long int, +), 21);
+ CHECK (FN2 (unsigned long long int, -), 7);
+ CHECK (FN2 (unsigned long long int, *), 98);
+
+ CHECK (FN3 (char, char, +), -4);
+ CHECK (FN3 (char, char, -), -6);
+ CHECK (FN3 (char, char, *), -5);
+ CHECK (FN3 (unsigned char, unsigned char, +), -4);
+ CHECK (FN3 (unsigned char, unsigned char, -), -6);
+ CHECK (FN3 (unsigned char, unsigned char, *), -5);
+ CHECK (FN3 (short, short, +), -4);
+ CHECK (FN3 (short, short, -), -6);
+ CHECK (FN3 (short, short, *), -5);
+ CHECK (FN3 (unsigned short, unsigned short, +), -4);
+ CHECK (FN3 (unsigned short, unsigned short, -), -6);
+ CHECK (FN3 (unsigned short, unsigned short, *), -5);
+ CHECK (FN3 (int, int, +), -4);
+ CHECK (FN3 (int, int, -), -6);
+ CHECK (FN3 (int, int, *), -5);
+ CHECK (FN3 (unsigned int, unsigned int, +), -4);
+ CHECK (FN3 (unsigned int, unsigned int, -), -6);
+ CHECK (FN3 (unsigned int, unsigned int, *), -5);
+ CHECK (FN3 (long int, long int, +), -4);
+ CHECK (FN3 (long int, long int, -), -6);
+ CHECK (FN3 (long int, long int, *), -5);
+ CHECK (FN3 (unsigned long int, unsigned long int, +), -4);
+ CHECK (FN3 (unsigned long int, unsigned long int, -), -6);
+ CHECK (FN3 (unsigned long int, unsigned long int, *), -5);
+ CHECK (FN3 (long long int, long int, +), -4);
+ CHECK (FN3 (long long int, long int, -), -6);
+ CHECK (FN3 (long long int, long int, *), -5);
+ CHECK (FN3 (unsigned long long int, unsigned long long int, +), -4);
+ CHECK (FN3 (unsigned long long int, unsigned long long int, -), -6);
+ CHECK (FN3 (unsigned long long int, unsigned long long int, *), -5);
+ CHECK (FN3 (int, unsigned char, +), -4);
+ CHECK (FN3 (int, unsigned char, -), -6);
+ CHECK (FN3 (int, unsigned char, *), -5);
+ CHECK (FN3 (unsigned char, int, +), -4);
+ CHECK (FN3 (unsigned char, int, -), -6);
+ CHECK (FN3 (unsigned char, int, *), -5);
+ CHECK (FN3 (int, long int, +), -4);
+ CHECK (FN3 (int, long int, -), -6);
+ CHECK (FN3 (int, long int, *), -5);
+ CHECK (FN3 (long int, int, +), -4);
+ CHECK (FN3 (long int, int, -), -6);
+ CHECK (FN3 (long int, int, *), -5);
+ CHECK (FN3 (unsigned int, int, +), -4);
+ CHECK (FN3 (unsigned int, int, -), -6);
+ CHECK (FN3 (unsigned int, int, *), -5);
+ CHECK (FN3 (int, unsigned int, +), -4);
+ CHECK (FN3 (int, unsigned int, -), -6);
+ CHECK (FN3 (int, unsigned int, *), -5);
+ CHECK (FN3 (unsigned long int, int, +), -4);
+ CHECK (FN3 (unsigned long int, int, -), -6);
+ CHECK (FN3 (unsigned long int, int, *), -5);
+ CHECK (FN3 (int, unsigned long int, +), -4);
+ CHECK (FN3 (int, unsigned long int, -), -6);
+ CHECK (FN3 (int, unsigned long int, *), -5);
+
+ CHECK (FN4 (char, char, +), 2);
+ CHECK (FN4 (char, char, -), 6);
+ CHECK (FN4 (char, char, *), -8);
+ CHECK (FN4 (unsigned char, unsigned char, +), 2);
+ CHECK (FN4 (unsigned char, unsigned char, -), 6);
+ CHECK (FN4 (unsigned char, unsigned char, *), -8);
+ CHECK (FN4 (short, short, +), 2);
+ CHECK (FN4 (short, short, -), 6);
+ CHECK (FN4 (short, short, *), -8);
+ CHECK (FN4 (unsigned short, unsigned short, +), 2);
+ CHECK (FN4 (unsigned short, unsigned short, -), 6);
+ CHECK (FN4 (unsigned short, unsigned short, *), -8);
+ CHECK (FN4 (int, int, +), 2);
+ CHECK (FN4 (int, int, -), 6);
+ CHECK (FN4 (int, int, *), -8);
+ CHECK (FN4 (unsigned int, unsigned int, +), 2);
+ CHECK (FN4 (unsigned int, unsigned int, -), 6);
+ CHECK (FN4 (unsigned int, unsigned int, *), -8);
+ CHECK (FN4 (long int, long int, +), 2);
+ CHECK (FN4 (long int, long int, -), 6);
+ CHECK (FN4 (long int, long int, *), -8);
+ CHECK (FN4 (unsigned long int, unsigned long int, +), 2);
+ CHECK (FN4 (unsigned long int, unsigned long int, -), 6);
+ CHECK (FN4 (unsigned long int, unsigned long int, *), -8);
+ CHECK (FN4 (long long int, long int, +), 2);
+ CHECK (FN4 (long long int, long int, -), 6);
+ CHECK (FN4 (long long int, long int, *), -8);
+ CHECK (FN4 (unsigned long long int, unsigned long long int, +), 2);
+ CHECK (FN4 (unsigned long long int, unsigned long long int, -), 6);
+ CHECK (FN4 (unsigned long long int, unsigned long long int, *), -8);
+ CHECK (FN4 (int, unsigned char, +), 2);
+ CHECK (FN4 (int, unsigned char, -), 6);
+ CHECK (FN4 (int, unsigned char, *), -8);
+ CHECK (FN4 (unsigned char, int, +), 2);
+ CHECK (FN4 (unsigned char, int, -), 6);
+ CHECK (FN4 (unsigned char, int, *), -8);
+ CHECK (FN4 (int, long int, +), 2);
+ CHECK (FN4 (int, long int, -), 6);
+ CHECK (FN4 (int, long int, *), -8);
+ CHECK (FN4 (long int, int, +), 2);
+ CHECK (FN4 (long int, int, -), 6);
+ CHECK (FN4 (long int, int, *), -8);
+ CHECK (FN4 (unsigned int, int, +), 2);
+ CHECK (FN4 (unsigned int, int, -), 6);
+ CHECK (FN4 (unsigned int, int, *), -8);
+ CHECK (FN4 (int, unsigned int, +), 2);
+ CHECK (FN4 (int, unsigned int, -), 6);
+ CHECK (FN4 (int, unsigned int, *), -8);
+ CHECK (FN4 (unsigned long int, int, +), 2);
+ CHECK (FN4 (unsigned long int, int, -), 6);
+ CHECK (FN4 (unsigned long int, int, *), -8);
+ CHECK (FN4 (int, unsigned long int, +), 2);
+ CHECK (FN4 (int, unsigned long int, -), 6);
+ CHECK (FN4 (int, unsigned long int, *), -8);
+
+ CHECK (FN5 (char), -77);
+ CHECK (FN5 (unsigned char), -77);
+ CHECK (FN5 (short), -77);
+ CHECK (FN5 (unsigned short), -77);
+ CHECK (FN5 (int), -77);
+ CHECK (FN5 (unsigned int), -77);
+ CHECK (FN5 (long int), -77);
+ CHECK (FN5 (unsigned long int), -77);
+ CHECK (FN5 (long long int), -77);
+ CHECK (FN5 (unsigned long long int), -77);
+ return 0;
+}
new file mode 100644
@@ -0,0 +1,11 @@
+/* { dg-do run } */
+/* { dg-options "-fsanitize=unreachable" } */
+/* { dg-shouldfail "ubsan" } */
+
+int
+__attribute__((no_sanitize(("shift,shift-base,shift-exponent,integer-divide-by-zero,vla-bound,return,null,signed-integer-overflow,bool,enum,float-divide-by-zero,float-cast-overflow,bounds,bounds-strict,alignment,nonnull-attribute,returns-nonnull-attribute,object-size,vptr"))))
+main (void)
+{
+ __builtin_unreachable ();
+}
+ /* { dg-output "execution reached a __builtin_unreachable\\(\\) call" } */
new file mode 100644
@@ -0,0 +1,14 @@
+/* { dg-do run } */
+/* { dg-options "-fsanitize=vla-bound -fno-sanitize-recover=vla-bound" } */
+
+int
+__attribute__((no_sanitize(("shift,shift-base,shift-exponent,integer-divide-by-zero,unreachable,return,null,signed-integer-overflow,bool,enum,float-divide-by-zero,float-cast-overflow,bounds,bounds-strict,alignment,nonnull-attribute,returns-nonnull-attribute,object-size,vptr"))))
+main (void)
+{
+ int x = 1;
+ /* Check that the size of an array is evaluated only once. */
+ int a[++x];
+ if (x != 2)
+ __builtin_abort ();
+ return 0;
+}
new file mode 100644
@@ -0,0 +1,29 @@
+// { dg-do run }
+// { dg-options "-fsanitize=return" }
+// { dg-shouldfail "ubsan" }
+
+struct S { S (); ~S (); };
+
+S::S () {}
+S::~S () {}
+
+int
+__attribute__((no_sanitize(("shift,shift-base,shift-exponent,integer-divide-by-zero,unreachable,vla-bound,null,signed-integer-overflow,bool,enum,float-divide-by-zero,float-cast-overflow,bounds,bounds-strict,alignment,nonnull-attribute,returns-nonnull-attribute,object-size,vptr"))))
+foo (int x)
+{
+ S a;
+ {
+ S b;
+ if (x)
+ return 1;
+ }
+}
+
+int
+__attribute__((no_sanitize(("shift,shift-base,shift-exponent,integer-divide-by-zero,unreachable,vla-bound,null,signed-integer-overflow,bool,enum,float-divide-by-zero,float-cast-overflow,bounds,bounds-strict,alignment,nonnull-attribute,returns-nonnull-attribute,object-size,vptr"))))
+main ()
+{
+ foo (0);
+}
+
+// { dg-output "execution reached the end of a value-returning function without returning a value" }
new file mode 100644
@@ -0,0 +1,185 @@
+// { dg-do run { target { ilp32 || lp64 } } }
+// { dg-options "-fsanitize=vptr" }
+
+struct S
+{
+ S() : a(0) {}
+ ~S() {}
+ int a;
+ int f() { return 0; }
+ virtual int v() { return 0; }
+};
+
+struct T : S
+{
+ T() : b(0) {}
+ int b;
+ int g() { return 0; }
+ virtual int v() { return 1; }
+};
+
+struct U : S, T { virtual int v() { return 2; } }; // { dg-warning "direct base .S. inaccessible in .U. due to ambiguity" }
+struct V : S {};
+
+void
+foo ()
+{
+ T t;
+ (void)t.a;
+ (void)t.b;
+ (void)t.f();
+ (void)t.g();
+ (void)t.v();
+ (void)t.S::v();
+
+ U u;
+ (void)u.T::a;
+ (void)u.b;
+ (void)u.T::f();
+ (void)u.g();
+ (void)u.v();
+ (void)u.T::v();
+ (void)((T&)u).S::v();
+}
+
+T *x;
+
+__attribute__((noinline, noclone, no_sanitize(("shift,shift-base,shift-exponent,integer-divide-by-zero,unreachable,vla-bound,return,null,signed-integer-overflow,bool,enum,float-divide-by-zero,float-cast-overflow,bounds,bounds-strict,alignment,nonnull-attribute,returns-nonnull-attribute,object-size")))) int
+bar (T *p, int q)
+{
+ switch (q)
+ {
+ // These shouldn't fail:
+ case 0x10:
+ case 0x20:
+ case 0x30:
+ case 0x40:
+ {
+ T &r = *p;
+ break;
+ }
+ case 0x21:
+ case 0x31:
+ return p->b;
+ case 0x22:
+ case 0x32:
+ return p->g ();
+ case 0x23:
+ case 0x33:
+ x = static_cast<T*>(reinterpret_cast<S*>(p));
+ break;
+ case 0x44:
+ return reinterpret_cast<U*>(p)->v() - 2;
+ // These should:
+ case 0x11:
+ return p->b;
+ // { dg-output "\[^\n\r]*vptr-12.C:75:\[0-9]*: runtime error: member access within address 0x\[0-9a-fA-F]* which does not point to an object of type 'T'(\n|\r\n|\r)" }
+ // { dg-output "0x\[0-9a-fA-F]*: note: object is of type 'S'(\n|\r\n|\r)" }
+ // { dg-output " .. .. .. .. .. .. .. .. .. .. .. .. \[^\n\r]*(\n|\r\n|\r)" }
+ // { dg-output " \\^~~~~~~~~~~\[^\n\r]*(\n|\r\n|\r)" }
+ // { dg-output " vptr for 'S'\[^\n\r]*(\n|\r\n|\r)" }
+ case 0x12:
+ return p->g ();
+ // { dg-output "\[^\n\r]*vptr-12.C:82:\[0-9]*: runtime error: member call on address 0x\[0-9a-fA-F]* which does not point to an object of type 'T'(\n|\r\n|\r)" }
+ // { dg-output "0x\[0-9a-fA-F]*: note: object is of type 'S'(\n|\r\n|\r)" }
+ // { dg-output " .. .. .. .. .. .. .. .. .. .. .. .. \[^\n\r]*(\n|\r\n|\r)" }
+ // { dg-output " \\^~~~~~~~~~~\[^\n\r]*(\n|\r\n|\r)" }
+ // { dg-output " vptr for 'S'\[^\n\r]*(\n|\r\n|\r)" }
+ case 0x13:
+ x = static_cast<T*>(reinterpret_cast<S*>(p));
+ break;
+ // { dg-output "\[^\n\r]*vptr-12.C:89:\[0-9]*: runtime error: downcast of address 0x\[0-9a-fA-F]* which does not point to an object of type 'T'(\n|\r\n|\r)" }
+ // { dg-output "0x\[0-9a-fA-F]*: note: object is of type 'S'(\n|\r\n|\r)" }
+ // { dg-output " .. .. .. .. .. .. .. .. .. .. .. .. \[^\n\r]*(\n|\r\n|\r)" }
+ // { dg-output " \\^~~~~~~~~~~\[^\n\r]*(\n|\r\n|\r)" }
+ // { dg-output " vptr for 'S'\[^\n\r]*(\n|\r\n|\r)" }
+ case 0x34:
+ return reinterpret_cast<U*>(p)->v() - 2;
+ // { dg-output "\[^\n\r]*vptr-12.C:97:\[0-9]*: runtime error: member call on address 0x\[0-9a-fA-F]* which does not point to an object of type 'U'(\n|\r\n|\r)" }
+ // { dg-output "0x\[0-9a-fA-F]*: note: object is base class subobject at offset 16 within object of type 'U'(\n|\r\n|\r)" { target lp64 } }
+ // { dg-output "0x\[0-9a-fA-F]*: note: object is base class subobject at offset 8 within object of type 'U'(\n|\r\n|\r)" { target ilp32 } }
+ // { dg-output " .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. \[^\n\r]*(\n|\r\n|\r)" }
+ // { dg-output " \\^ ~~~~~~~~~~~~~~~~~~~~~~~(\n|\r\n|\r)" { target lp64 } }
+ // { dg-output " vptr for 'T' base class of 'U'\[^\n\r]*(\n|\r\n|\r)" { target lp64 } }
+ // { dg-output " \\^ ~~~~~~~~~~~(\n|\r\n|\r)" { target ilp32 } }
+ // { dg-output " vptr for 'T' base class of 'U'\[^\n\r]*(\n|\r\n|\r)" { target ilp32 } }
+ case 0x41:
+ return p->b;
+ // { dg-output "\[^\n\r]*vptr-12.C:107:\[0-9]*: runtime error: member access within address 0x\[0-9a-fA-F]* which does not point to an object of type 'T'(\n|\r\n|\r)" }
+ // { dg-output "0x\[0-9a-fA-F]*: note: object is of type 'U'(\n|\r\n|\r)" }
+ // { dg-output " .. .. .. .. .. .. .. .. .. .. .. .. \[^\n\r]*(\n|\r\n|\r)" }
+ // { dg-output " \\^~~~~~~~~~~\[^\n\r]*(\n|\r\n|\r)" }
+ // { dg-output " vptr for 'U'\[^\n\r]*(\n|\r\n|\r)" }
+ case 0x42:
+ return p->g ();
+ // { dg-output "\[^\n\r]*vptr-12.C:114:\[0-9]*: runtime error: member call on address 0x\[0-9a-fA-F]* which does not point to an object of type 'T'(\n|\r\n|\r)" }
+ // { dg-output "0x\[0-9a-fA-F]*: note: object is of type 'U'(\n|\r\n|\r)" }
+ // { dg-output " .. .. .. .. .. .. .. .. .. .. .. .. \[^\n\r]*(\n|\r\n|\r)" }
+ // { dg-output " \\^~~~~~~~~~~\[^\n\r]*(\n|\r\n|\r)" }
+ // { dg-output " vptr for 'U'\[^\n\r]*(\n|\r\n|\r)" }
+ case 0x43:
+ x = static_cast<T*>(reinterpret_cast<S*>(p));
+ break;
+ // { dg-output "\[^\n\r]*vptr-12.C:121:\[0-9]*: runtime error: downcast of address 0x\[0-9a-fA-F]* which does not point to an object of type 'T'(\n|\r\n|\r)" }
+ // { dg-output "0x\[0-9a-fA-F]*: note: object is of type 'U'(\n|\r\n|\r)" }
+ // { dg-output " .. .. .. .. .. .. .. .. .. .. .. .. \[^\n\r]*(\n|\r\n|\r)" }
+ // { dg-output " \\^~~~~~~~~~~\[^\n\r]*(\n|\r\n|\r)" }
+ // { dg-output " vptr for 'U'\[^\n\r]*(\n|\r\n|\r)" }
+ case 0x51:
+ return p->b;
+ // { dg-output "\[^\n\r]*vptr-12.C:129:\[0-9]*: runtime error: member access within address 0x\[0-9a-fA-F]* which does not point to an object of type 'T'(\n|\r\n|\r)" }
+ // { dg-output "0x\[0-9a-fA-F]*: note: object has invalid vptr(\n|\r\n|\r)" }
+ // { dg-output " .. .. .. .. 00 00 00 00 00 00 00 00 \[^\n\r]*(\n|\r\n|\r)" { target lp64 } }
+ // { dg-output " \\^~~~~~~~~~~~~~~~~~~~~~~\[^\n\r]*(\n|\r\n|\r)" { target lp64 } }
+ // { dg-output " ?.. .. .. .. ?00 00 00 00 ?.. .. .. .. ?\[^\n\r]*(\n|\r\n|\r)" { target ilp32 } }
+ // { dg-output " \\^~~~~~~~~~~\[^\n\r]*(\n|\r\n|\r)" { target ilp32 } }
+ // { dg-output " invalid vptr" }
+ }
+ return 0;
+}
+
+char b[sizeof (U)] __attribute__((aligned (__alignof__ (U)))) = {};
+
+__attribute__((noinline, noclone, no_sanitize(("shift,shift-base,shift-exponent,integer-divide-by-zero,unreachable,vla-bound,return,null,signed-integer-overflow,bool,enum,float-divide-by-zero,float-cast-overflow,bounds,bounds-strict,alignment,nonnull-attribute,returns-nonnull-attribute,object-size")))) void
+baz (int q)
+{
+ T *p = 0;
+ S *s = 0;
+ U *u = 0;
+ switch (q)
+ {
+ case 0x10: case 0x11: case 0x12: case 0x13:
+ s = new S;
+ bar (reinterpret_cast<T *>(s), q);
+ delete s;
+ break;
+ case 0x20: case 0x21: case 0x22: case 0x23:
+ p = new T;
+ bar (p, q);
+ delete p;
+ break;
+ case 0x30: case 0x31: case 0x32: case 0x33: case 0x34:
+ u = new U;
+ bar (u, q);
+ delete u;
+ break;
+ case 0x40: case 0x41: case 0x42: case 0x43: case 0x44:
+ u = new U;
+ bar (reinterpret_cast<T *>(u), q);
+ delete u;
+ break;
+ case 0x51:
+ p = reinterpret_cast<T*>(b);
+ bar (p, q);
+ break;
+ }
+}
+
+int
+__attribute__((no_sanitize(("shift,shift-base,shift-exponent,integer-divide-by-zero,unreachable,vla-bound,return,null,signed-integer-overflow,bool,enum,float-divide-by-zero,float-cast-overflow,bounds,bounds-strict,alignment,nonnull-attribute,returns-nonnull-attribute,object-size"))))
+main ()
+{
+ foo ();
+ for (int q = 0; q < 0x52; q++)
+ baz (q);
+}
new file mode 100644
@@ -0,0 +1,20 @@
+/* PR sanitizer/65280 */
+/* { dg-do run } */
+/* { dg-options "-fsanitize=bounds" } */
+
+void
+__attribute__((no_sanitize(("shift,shift-base,shift-exponent,integer-divide-by-zero,unreachable,vla-bound,return,null,signed-integer-overflow,bool,enum,float-divide-by-zero,float-cast-overflow,alignment,nonnull-attribute,returns-nonnull-attribute,object-size,vptr"))))
+foo (int n, int (*b)[n])
+{
+ (*b)[n] = 1;
+}
+
+int
+__attribute__((no_sanitize(("shift,shift-base,shift-exponent,integer-divide-by-zero,unreachable,vla-bound,return,null,signed-integer-overflow,bool,enum,float-divide-by-zero,float-cast-overflow,alignment,nonnull-attribute,returns-nonnull-attribute,object-size,vptr"))))
+main ()
+{
+ int a[20];
+ foo (3, (int (*)[3]) &a);
+}
+
+/* { dg-output "index 3 out of bounds for type 'int \\\[\\\*\\\]'" } */
new file mode 100644
@@ -0,0 +1,11 @@
+/* { dg-do run } */
+/* { dg-options "-fsanitize=shift -w -std=c99" } */
+
+int
+__attribute__((no_sanitize(("shift-exponent,integer-divide-by-zero,unreachable,vla-bound,return,null,signed-integer-overflow,bool,enum,float-divide-by-zero,float-cast-overflow,bounds,bounds-strict,alignment,nonnull-attribute,returns-nonnull-attribute,object-size,vptr"))))
+main (void)
+{
+ int a = -42;
+ a << 1;
+}
+/* { dg-output "left shift of negative value -42" } */
new file mode 100644
@@ -0,0 +1,12 @@
+/* { dg-do run } */
+/* { dg-options "-fsanitize=shift-exponent -w -std=c99" } */
+
+int
+__attribute__((no_sanitize(("shift-base,integer-divide-by-zero,unreachable,vla-bound,return,null,signed-integer-overflow,bool,enum,float-divide-by-zero,float-cast-overflow,bounds,bounds-strict,alignment,nonnull-attribute,returns-nonnull-attribute,object-size,vptr"))))
+main (void)
+{
+ int b = 43;
+ volatile int c = 129;
+ b << c;
+}
+/* { dg-output "shift exponent 129 is too large for" } */
@@ -14264,6 +14264,23 @@ nonnull_arg_p (const_tree arg)
return false;
}
+/* Return true when flag_sanitize & FLAG is non-zero. If FN is non-null,
+ remove all flags mentioned in "no_sanitize_flags" of DECL_ATTRIBUTES. */
+
+bool
+sanitize_flags_p (unsigned int flag, const_tree fn)
+{
+ if (fn == NULL)
+ return false;
+
+ unsigned int result_flags = flag_sanitize & flag;
+ tree value = lookup_attribute ("no_sanitize_flags", DECL_ATTRIBUTES (fn));
+ if (value)
+ result_flags &= ~tree_to_uhwi (TREE_VALUE (value));
+
+ return result_flags;
+}
+
/* Combine LOC and BLOCK to a combined adhoc loc, retaining any range
information. */
@@ -4217,6 +4217,10 @@ extern tree merge_dllimport_decl_attributes (tree, tree);
/* Handle a "dllimport" or "dllexport" attribute. */
extern tree handle_dll_attribute (tree *, tree, tree, int, bool *);
+
+extern bool sanitize_flags_p (unsigned int flag,
+ const_tree fn = current_function_decl);
+
/* Returns true iff CAND and BASE have equivalent language-specific
qualifiers. */
@@ -881,11 +881,9 @@ public:
/* opt_pass methods: */
opt_pass * clone () { return new pass_tsan (m_ctxt); }
- virtual bool gate (function *)
+ virtual bool gate (function *fn)
{
- return ((flag_sanitize & SANITIZE_THREAD) != 0
- && !lookup_attribute ("no_sanitize_thread",
- DECL_ATTRIBUTES (current_function_decl)));
+ return sanitize_flags_p (SANITIZE_THREAD, fn->decl);
}
virtual unsigned int execute (function *) { return tsan_pass (); }
@@ -923,11 +921,9 @@ public:
{}
/* opt_pass methods: */
- virtual bool gate (function *)
+ virtual bool gate (function *fn)
{
- return ((flag_sanitize & SANITIZE_THREAD) != 0 && !optimize
- && !lookup_attribute ("no_sanitize_thread",
- DECL_ATTRIBUTES (current_function_decl)));
+ return (sanitize_flags_p (SANITIZE_THREAD, fn->decl) && !optimize);
}
virtual unsigned int execute (function *) { return tsan_pass (); }
@@ -754,7 +754,7 @@ ubsan_expand_null_ifn (gimple_stmt_iterator *gsip)
gsi_insert_before (&gsi, g, GSI_SAME_STMT);
}
}
- check_null = (flag_sanitize & SANITIZE_NULL) != 0;
+ check_null = sanitize_flags_p (SANITIZE_NULL);
if (check_align == NULL_TREE && !check_null)
{
@@ -1178,13 +1178,13 @@ instrument_mem_ref (tree mem, tree base, gimple_stmt_iterator *iter,
{
enum ubsan_null_ckind ikind = is_lhs ? UBSAN_STORE_OF : UBSAN_LOAD_OF;
unsigned int align = 0;
- if (flag_sanitize & SANITIZE_ALIGNMENT)
+ if (sanitize_flags_p (SANITIZE_ALIGNMENT))
{
align = min_align_of_type (TREE_TYPE (base));
if (align <= 1)
align = 0;
}
- if (align == 0 && (flag_sanitize & SANITIZE_NULL) == 0)
+ if (align == 0 && !sanitize_flags_p (SANITIZE_NULL))
return;
tree t = TREE_OPERAND (base, 0);
if (!POINTER_TYPE_P (TREE_TYPE (t)))
@@ -1350,13 +1350,14 @@ instrument_bool_enum_load (gimple_stmt_iterator *gsi)
tree type = TREE_TYPE (rhs);
tree minv = NULL_TREE, maxv = NULL_TREE;
- if (TREE_CODE (type) == BOOLEAN_TYPE && (flag_sanitize & SANITIZE_BOOL))
+ if (TREE_CODE (type) == BOOLEAN_TYPE
+ && sanitize_flags_p (SANITIZE_BOOL))
{
minv = boolean_false_node;
maxv = boolean_true_node;
}
else if (TREE_CODE (type) == ENUMERAL_TYPE
- && (flag_sanitize & SANITIZE_ENUM)
+ && sanitize_flags_p (SANITIZE_ENUM)
&& TREE_TYPE (type) != NULL_TREE
&& TREE_CODE (TREE_TYPE (type)) == INTEGER_TYPE
&& (TYPE_PRECISION (TREE_TYPE (type))
@@ -1915,16 +1916,6 @@ instrument_object_size (gimple_stmt_iterator *gsi, bool is_lhs)
gsi_insert_before (gsi, g, GSI_SAME_STMT);
}
-/* True if we want to play UBSan games in the current function. */
-
-bool
-do_ubsan_in_current_function ()
-{
- return (current_function_decl != NULL_TREE
- && !lookup_attribute ("no_sanitize_undefined",
- DECL_ATTRIBUTES (current_function_decl)));
-}
-
namespace {
const pass_data pass_data_ubsan =
@@ -1948,15 +1939,14 @@ public:
{}
/* opt_pass methods: */
- virtual bool gate (function *)
+ virtual bool gate (function *fn)
{
- return flag_sanitize & (SANITIZE_NULL | SANITIZE_SI_OVERFLOW
- | SANITIZE_BOOL | SANITIZE_ENUM
- | SANITIZE_ALIGNMENT
- | SANITIZE_NONNULL_ATTRIBUTE
- | SANITIZE_RETURNS_NONNULL_ATTRIBUTE
- | SANITIZE_OBJECT_SIZE)
- && do_ubsan_in_current_function ();
+ return sanitize_flags_p ((SANITIZE_NULL | SANITIZE_SI_OVERFLOW
+ | SANITIZE_BOOL | SANITIZE_ENUM
+ | SANITIZE_ALIGNMENT
+ | SANITIZE_NONNULL_ATTRIBUTE
+ | SANITIZE_RETURNS_NONNULL_ATTRIBUTE
+ | SANITIZE_OBJECT_SIZE), fn->decl);
}
virtual unsigned int execute (function *);
@@ -1983,11 +1973,11 @@ pass_ubsan::execute (function *fun)
continue;
}
- if ((flag_sanitize & SANITIZE_SI_OVERFLOW)
+ if ((sanitize_flags_p (SANITIZE_SI_OVERFLOW, fun->decl))
&& is_gimple_assign (stmt))
instrument_si_overflow (gsi);
- if (flag_sanitize & (SANITIZE_NULL | SANITIZE_ALIGNMENT))
+ if (sanitize_flags_p (SANITIZE_NULL | SANITIZE_ALIGNMENT, fun->decl))
{
if (gimple_store_p (stmt))
instrument_null (gsi, true);
@@ -1995,14 +1985,14 @@ pass_ubsan::execute (function *fun)
instrument_null (gsi, false);
}
- if (flag_sanitize & (SANITIZE_BOOL | SANITIZE_ENUM)
+ if (sanitize_flags_p (SANITIZE_BOOL | SANITIZE_ENUM, fun->decl)
&& gimple_assign_load_p (stmt))
{
instrument_bool_enum_load (&gsi);
bb = gimple_bb (stmt);
}
- if ((flag_sanitize & SANITIZE_NONNULL_ATTRIBUTE)
+ if (sanitize_flags_p (SANITIZE_NONNULL_ATTRIBUTE, fun->decl)
&& is_gimple_call (stmt)
&& !gimple_call_internal_p (stmt))
{
@@ -2010,14 +2000,14 @@ pass_ubsan::execute (function *fun)
bb = gimple_bb (stmt);
}
- if ((flag_sanitize & SANITIZE_RETURNS_NONNULL_ATTRIBUTE)
+ if (sanitize_flags_p (SANITIZE_RETURNS_NONNULL_ATTRIBUTE, fun->decl)
&& gimple_code (stmt) == GIMPLE_RETURN)
{
instrument_nonnull_return (&gsi);
bb = gimple_bb (stmt);
}
- if (flag_sanitize & SANITIZE_OBJECT_SIZE)
+ if (sanitize_flags_p (SANITIZE_OBJECT_SIZE, fun->decl))
{
if (gimple_store_p (stmt))
instrument_object_size (&gsi, true);
@@ -42,7 +42,6 @@ enum ubsan_print_style {
UBSAN_PRINT_ARRAY
};
-extern bool do_ubsan_in_current_function (void);
extern bool ubsan_expand_bounds_ifn (gimple_stmt_iterator *);
extern bool ubsan_expand_null_ifn (gimple_stmt_iterator *);
extern bool ubsan_expand_objsize_ifn (gimple_stmt_iterator *);
--
2.11.0