From patchwork Tue Jun 13 11:09:54 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: =?utf-8?q?Martin_Li=C5=A1ka?= X-Patchwork-Id: 775085 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 3wn6W173cnz9rxl for ; Tue, 13 Jun 2017 21:10:21 +1000 (AEST) Authentication-Results: ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=gcc.gnu.org header.i=@gcc.gnu.org header.b="ia91iZ7y"; dkim-atps=neutral DomainKey-Signature: a=rsa-sha1; c=nofws; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender :subject:to:cc:references:from:message-id:date:mime-version :in-reply-to:content-type; q=dns; s=default; b=Mwem8x4JanYYN9Hza iY9jmDwooV0l7VrpJZrtxd0sWYtmXGcqIcelEHUdb8WTV1bCQyn6XlX6JDNYHrtQ faC/oQyZeQrGJaOFEbGDBtsbrBsTsRbpRTloFjFzx8Ors0wg/iCKw1roT8AL/1Rl vwGfcfN45tx5irDrIIehCNBWi4= DKIM-Signature: v=1; a=rsa-sha1; c=relaxed; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender :subject:to:cc:references:from:message-id:date:mime-version :in-reply-to:content-type; s=default; bh=ZG3UxMsvlTKsxRFXMSQ1FVJ kSKo=; b=ia91iZ7yG69ssR9fOx2543a2gyf/MDRx4r/uGKgmuRiAYt2a24h8jOu 15sNpi4I/4lDlosal+RBAkjgfR1+dXkDWLM6tmewByUurwekjplpFvEYJqMLIf8c NRxyUilJXXBl3NaVF2jGJM2opX1kSYtzDjeiqZftN4DT4N13hdzo= Received: (qmail 37321 invoked by alias); 13 Jun 2017 11:10:01 -0000 Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Delivered-To: mailing list gcc-patches@gcc.gnu.org Received: (qmail 37271 invoked by uid 89); 13 Jun 2017 11:10:00 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-26.9 required=5.0 tests=BAYES_00, GIT_PATCH_0, GIT_PATCH_1, GIT_PATCH_2, GIT_PATCH_3, SPF_PASS autolearn=ham version=3.3.2 spammy=Flow, sk:stabili X-HELO: mx1.suse.de Received: from mx2.suse.de (HELO mx1.suse.de) (195.135.220.15) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Tue, 13 Jun 2017 11:09:53 +0000 Received: from relay2.suse.de (charybdis-ext.suse.de [195.135.220.254]) by mx1.suse.de (Postfix) with ESMTP id 51E81ADF1; Tue, 13 Jun 2017 11:09:55 +0000 (UTC) Subject: Re: [PATCH v2] Implement no_sanitize function attribute To: Richard Biener Cc: Jakub Jelinek , "Joseph S. Myers" , GCC Patches References: <83f8580a-03e1-81eb-3216-a1c998810b90@suse.cz> <878c99de-7ca3-c7c1-ff39-302d5d419fb4@suse.cz> <58587d2d-f61b-e6d5-2d59-8520ca0ce59f@suse.cz> <7a8c52c8-5547-e3f2-02d1-9bc00e69d313@suse.cz> <20170608134715.GV2154@tucnak> <6a27b454-a2a7-ff42-f5b3-93690ca0cf05@suse.cz> <827faf71-693f-cd1b-3e67-212d9048ed65@suse.cz> <2a875298-ecbc-8ef2-991c-7018b82a309a@suse.cz> <32e841e7-6b3e-5c48-3d83-e93150c4a71e@suse.cz> From: =?UTF-8?Q?Martin_Li=c5=a1ka?= Message-ID: Date: Tue, 13 Jun 2017 13:09:54 +0200 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:52.0) Gecko/20100101 Thunderbird/52.1.1 MIME-Version: 1.0 In-Reply-To: X-IsSubscribed: yes On 06/09/2017 03:35 PM, Richard Biener wrote: > You can directly transform to no_sanitize with integer mask, not sure why > you'd need an intermediate step with a string? Hello. Done in attached patch, I'm sending both incremental and final version (complete patch). I also decided to support no_sanitize attribute in pretty printer: __attribute__((no_sanitize (address | shift | shift-base | shift-exponent | integer-divide-by-zero | undefined | 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))) fn1 () { char my_char[9]; char * ptr2; char * ptr; .. Patch can bootstrap on ppc64le-redhat-linux and survives regression tests. Ready to be installed? Martin From 5f120c1b6545ef77e87c9c9a80c5dfd6a48e9d69 Mon Sep 17 00:00:00 2001 From: marxin Date: Thu, 1 Jun 2017 11:36:36 +0200 Subject: [PATCH] Implement no_sanitize function attribute gcc/testsuite/ChangeLog: 2017-06-01 Martin Liska * c-c++-common/ubsan/attrib-2.c (float_cast2): Enhance the test by adding no_sanitize attribute. * gcc.dg/asan/use-after-scope-4.c: Likewise. gcc/c-family/ChangeLog: 2017-06-01 Martin Liska * c-attribs.c (add_no_sanitize_value): New function. (handle_no_sanitize_attribute): Likewise. (handle_no_sanitize_address_attribute): Use the function. (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: Declare new functions. * 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. gcc/ChangeLog: 2017-06-01 Martin Liska * asan.c (asan_sanitize_stack_p): Use sanitize_flags_p. (gate_asan): Likewise. * asan.h (asan_no_sanitize_address_p): Remove the function. (sanitize_flags_p): New function. * builtins.def: Fix coding style. * common.opt: Use renamed enum value. * convert.c (convert_to_integer_1): Use sanitize_flags_p. * doc/extend.texi: Document no_sanitize attribute. * 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_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 renamed enum value. * opts.h (parse_no_sanitize_attribute): Declare. * tree.c (sanitize_flags_p): New function. * tree.h: Declared here. * tsan.c: 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 the function. (pass_ubsan::execute): Use sanitize_flags_p. * ubsan.h: Remove do_ubsan_in_current_function * tree-cfg.c (print_no_sanitize_attr_value): New function. (dump_function_to_file): Use it here. gcc/cp/ChangeLog: 2017-06-01 Martin Liska * class.c (build_base_path): Use sanitize_flags_p. * 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 (finish_length_check): Likewise. * lambda.c (maybe_add_lambda_conv_op): Likewise. * typeck.c (cp_build_binary_op): Likewise. (build_static_cast_1): Likewise. gcc/c/ChangeLog: 2017-06-01 Martin Liska * 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 | 8 +- gcc/asan.h | 27 +++++-- gcc/builtins.def | 3 +- gcc/c-family/c-attribs.c | 110 ++++++++++++++++++++++---- 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 | 6 +- gcc/c/c-decl.c | 6 +- gcc/c/c-typeck.c | 16 ++-- gcc/common.opt | 2 +- gcc/convert.c | 4 +- gcc/cp/class.c | 4 +- gcc/cp/cp-gimplify.c | 19 +++-- gcc/cp/cp-ubsan.c | 3 +- gcc/cp/decl.c | 6 +- gcc/cp/decl2.c | 2 +- gcc/cp/init.c | 4 +- gcc/cp/lambda.c | 4 +- gcc/cp/typeck.c | 16 ++-- gcc/doc/extend.texi | 12 +++ gcc/flag-types.h | 4 +- gcc/gcc.c | 3 +- gcc/gimple-fold.c | 3 +- gcc/gimplify.c | 5 +- gcc/ipa-inline.c | 11 +-- gcc/opts.c | 31 +++++++- gcc/opts.h | 2 + gcc/sanopt.c | 4 +- gcc/testsuite/c-c++-common/ubsan/attrib-2.c | 10 +++ gcc/testsuite/gcc.dg/asan/use-after-scope-4.c | 42 +++++++--- gcc/tree-cfg.c | 29 ++++++- gcc/tsan.c | 8 +- gcc/ubsan.c | 46 +++++------ gcc/ubsan.h | 1 - 35 files changed, 323 insertions(+), 154 deletions(-) diff --git a/gcc/asan.c b/gcc/asan.c index bf564a46b28..e730530930b 100644 --- a/gcc/asan.c +++ b/gcc/asan.c @@ -305,9 +305,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. */ @@ -3194,9 +3192,7 @@ asan_instrument (void) static bool gate_asan (void) { - return (flag_sanitize & SANITIZE_ADDRESS) != 0 - && !lookup_attribute ("no_sanitize_address", - DECL_ATTRIBUTES (current_function_decl)); + return sanitize_flags_p (SANITIZE_ADDRESS); } namespace { diff --git a/gcc/asan.h b/gcc/asan.h index 57663977603..95bb89e197c 100644 --- a/gcc/asan.h +++ b/gcc/asan.h @@ -144,13 +144,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 @@ -161,4 +154,24 @@ asan_protect_stack_decl (tree decl) || (asan_sanitize_use_after_scope () && TREE_ADDRESSABLE (decl))); } +/* Return true when flag_sanitize & FLAG is non-zero. If FN is non-null, + remove all flags mentioned in "no_sanitize" of DECL_ATTRIBUTES. */ + +static inline bool +sanitize_flags_p (unsigned int flag, const_tree fn = current_function_decl) +{ + unsigned int result_flags = flag_sanitize & flag; + if (result_flags == 0) + return false; + + if (fn != NULL_TREE) + { + tree value = lookup_attribute ("no_sanitize", DECL_ATTRIBUTES (fn)); + if (value) + result_flags &= ~tree_to_uhwi (TREE_VALUE (value)); + } + + return result_flags; +} + #endif /* TREE_ASAN */ diff --git a/gcc/builtins.def b/gcc/builtins.def index 1c887db7cb9..f242137a1cb 100644 --- a/gcc/builtins.def +++ b/gcc/builtins.def @@ -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 diff --git a/gcc/c-family/c-attribs.c b/gcc/c-family/c-attribs.c index 695c58c0a14..2b6845f2cbd 100644 --- a/gcc/c-family/c-attribs.c +++ b/gcc/c-family/c-attribs.c @@ -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,22 +553,98 @@ handle_cold_attribute (tree *node, tree name, tree ARG_UNUSED (args), return NULL_TREE; } -/* Handle a "no_sanitize_address" attribute; arguments as in +/* 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", DECL_ATTRIBUTES (node)); + if (attr) + { + unsigned int old_value = tree_to_uhwi (TREE_VALUE (attr)); + flags |= old_value; + + if (flags == old_value) + return; + + TREE_VALUE (attr) = build_int_cst (unsigned_type_node, flags); + } + else + DECL_ATTRIBUTES (node) + = tree_cons (get_identifier ("no_sanitize"), + build_int_cst (unsigned_type_node, flags), + DECL_ATTRIBUTES (node)); +} + +/* Handle a "no_sanitize" attribute; arguments as in struct attribute_spec.handler. */ static tree -handle_no_sanitize_address_attribute (tree *node, tree name, tree, int, - bool *no_add_attrs) +handle_no_sanitize_attribute (tree *node, tree name, tree args, int, + bool *no_add_attrs) { + *no_add_attrs = true; + 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. */ + +static tree +handle_no_sanitize_address_attribute (tree *node, tree name, tree, int, + bool *no_add_attrs) +{ + *no_add_attrs = true; + if (TREE_CODE (*node) != FUNCTION_DECL) + warning (OPT_Wattributes, "%qE attribute ignored", name); + 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) +{ + *no_add_attrs = true; + if (TREE_CODE (*node) != FUNCTION_DECL) + warning (OPT_Wattributes, "%qE attribute ignored", name); + 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. */ @@ -570,13 +652,12 @@ static tree handle_no_address_safety_analysis_attribute (tree *node, tree name, tree, int, bool *no_add_attrs) { + *no_add_attrs = true; 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; + else + add_no_sanitize_value (*node, SANITIZE_ADDRESS); + return NULL_TREE; } @@ -587,11 +668,12 @@ static tree handle_no_sanitize_undefined_attribute (tree *node, tree name, tree, int, bool *no_add_attrs) { + *no_add_attrs = true; if (TREE_CODE (*node) != FUNCTION_DECL) - { - warning (OPT_Wattributes, "%qE attribute ignored", name); - *no_add_attrs = true; - } + warning (OPT_Wattributes, "%qE attribute ignored", name); + else + add_no_sanitize_value (*node, + SANITIZE_UNDEFINED | SANITIZE_UNDEFINED_NONDEFAULT); return NULL_TREE; } diff --git a/gcc/c-family/c-common.h b/gcc/c-family/c-common.h index 79072e6a8b7..1748c1979aa 100644 --- a/gcc/c-family/c-common.h +++ b/gcc/c-family/c-common.h @@ -1552,6 +1552,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 { diff --git a/gcc/c-family/c-ubsan.c b/gcc/c-family/c-ubsan.c index e48841a334c..a072d19eda6 100644 --- a/gcc/c-family/c-ubsan.c +++ b/gcc/c-family/c-ubsan.c @@ -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: @@ -178,7 +178,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); @@ -301,7 +301,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)) { @@ -373,7 +373,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); @@ -393,7 +393,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); @@ -401,7 +401,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) @@ -419,7 +419,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 @@ -435,7 +435,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) { diff --git a/gcc/c-family/c-ubsan.h b/gcc/c-family/c-ubsan.h index 3c3ffc7f7a2..1e2d192bb31 100644 --- a/gcc/c-family/c-ubsan.h +++ b/gcc/c-family/c-ubsan.h @@ -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 */ diff --git a/gcc/c/c-convert.c b/gcc/c/c-convert.c index b8117b49ac9..33c9143e354 100644 --- a/gcc/c/c-convert.c +++ b/gcc/c/c-convert.c @@ -31,6 +31,7 @@ along with GCC; see the file COPYING3. If not see #include "convert.h" #include "langhooks.h" #include "ubsan.h" +#include "asan.h" /* Change of width--truncation and extension of integers or reals-- is represented with NOP_EXPR. Proper functioning of many things @@ -106,10 +107,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)) { expr = save_expr (expr); tree check = ubsan_instrument_float_cast (loc, type, expr); diff --git a/gcc/c/c-decl.c b/gcc/c/c-decl.c index 3a0a4f51737..317d5cdd099 100644 --- a/gcc/c/c-decl.c +++ b/gcc/c/c-decl.c @@ -53,6 +53,7 @@ along with GCC; see the file COPYING3. If not see #include "builtins.h" #include "spellcheck-tree.h" #include "gcc-rich-location.h" +#include "asan.h" /* In grokdeclarator, distinguish syntactic contexts of declarators. */ enum decl_context @@ -6044,9 +6045,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 = save_expr (size); diff --git a/gcc/c/c-typeck.c b/gcc/c/c-typeck.c index ba4440653ac..4d067e96dd3 100644 --- a/gcc/c/c-typeck.c +++ b/gcc/c/c-typeck.c @@ -50,6 +50,7 @@ along with GCC; see the file COPYING3. If not see #include "gomp-constants.h" #include "spellcheck-tree.h" #include "gcc-rich-location.h" +#include "asan.h" /* Possible cases of implicit bad conversions. Used to select diagnostic messages in convert_for_assignment. */ @@ -6378,7 +6379,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); @@ -9955,7 +9956,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; @@ -11835,9 +11836,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) { @@ -11846,10 +11846,10 @@ build_binary_op (location_t location, enum tree_code code, op1 = 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); } diff --git a/gcc/common.opt b/gcc/common.opt index 0a10511d468..4f9c3dcac3e 100644 --- a/gcc/common.opt +++ b/gcc/common.opt @@ -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) diff --git a/gcc/convert.c b/gcc/convert.c index af8dfda0eb4..429f988cbde 100644 --- a/gcc/convert.c +++ b/gcc/convert.c @@ -33,6 +33,7 @@ along with GCC; see the file COPYING3. If not see #include "langhooks.h" #include "builtins.h" #include "ubsan.h" +#include "asan.h" #define maybe_fold_build1_loc(FOLD_P, LOC, CODE, TYPE, EXPR) \ ((FOLD_P) ? fold_build1_loc (LOC, CODE, TYPE, EXPR) \ @@ -937,8 +938,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); diff --git a/gcc/cp/class.c b/gcc/cp/class.c index 66f42627715..dd1051e294b 100644 --- a/gcc/cp/class.c +++ b/gcc/cp/class.c @@ -36,6 +36,7 @@ along with GCC; see the file COPYING3. If not see #include "dumpfile.h" #include "gimplify.h" #include "intl.h" +#include "asan.h" /* Id for dumping the class hierarchy. */ int class_dump_id; @@ -462,7 +463,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); diff --git a/gcc/cp/cp-gimplify.c b/gcc/cp/cp-gimplify.c index e3802f1820b..3c8f4b041d2 100644 --- a/gcc/cp/cp-gimplify.c +++ b/gcc/cp/cp-gimplify.c @@ -33,6 +33,7 @@ along with GCC; see the file COPYING3. If not see #include "c-family/c-ubsan.h" #include "cilk.h" #include "cp-cilkplus.h" +#include "asan.h" /* Forward declarations. */ @@ -1262,8 +1263,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; @@ -1450,11 +1450,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_p); @@ -1470,9 +1470,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); } } @@ -1499,7 +1499,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); } @@ -1622,8 +1622,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. */ diff --git a/gcc/cp/cp-ubsan.c b/gcc/cp/cp-ubsan.c index 71d315ec2b4..f00f870bd3e 100644 --- a/gcc/cp/cp-ubsan.c +++ b/gcc/cp/cp-ubsan.c @@ -23,6 +23,7 @@ along with GCC; see the file COPYING3. If not see #include "coretypes.h" #include "cp-tree.h" #include "ubsan.h" +#include "asan.h" /* Test if we should instrument vptr access. */ @@ -32,7 +33,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) diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index b0df3c9835c..37114761be0 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -51,6 +51,7 @@ along with GCC; see the file COPYING3. If not see #include "cilk.h" #include "builtins.h" #include "gimplify.h" +#include "asan.h" /* Possible cases of bad specifiers type used by bad_specifiers. */ enum bad_spec_place { @@ -9524,8 +9525,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. */ @@ -15108,7 +15108,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); diff --git a/gcc/cp/decl2.c b/gcc/cp/decl2.c index d3d90020c05..ab32b717018 100644 --- a/gcc/cp/decl2.c +++ b/gcc/cp/decl2.c @@ -3737,7 +3737,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) diff --git a/gcc/cp/init.c b/gcc/cp/init.c index 4ad2cae541e..90abd23a267 100644 --- a/gcc/cp/init.c +++ b/gcc/cp/init.c @@ -30,6 +30,7 @@ along with GCC; see the file COPYING3. If not see #include "gimplify.h" #include "c-family/c-ubsan.h" #include "intl.h" +#include "asan.h" static bool begin_init_stmts (tree *, tree *); static tree finish_init_stmts (bool, tree, tree); @@ -3911,8 +3912,7 @@ finish_length_check (tree atype, tree iterator, tree obase, unsigned n) } /* 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 diff --git a/gcc/cp/lambda.c b/gcc/cp/lambda.c index 5587f6021ea..52e1fb78865 100644 --- a/gcc/cp/lambda.c +++ b/gcc/cp/lambda.c @@ -1150,9 +1150,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, false); diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c index 34d475b98f0..05b4fbb79d3 100644 --- a/gcc/cp/typeck.c +++ b/gcc/cp/typeck.c @@ -37,6 +37,7 @@ along with GCC; see the file COPYING3. If not see #include "c-family/c-ubsan.h" #include "params.h" #include "gcc-rich-location.h" +#include "asan.h" static tree cp_build_addr_expr_strict (tree, tsubst_flags_t); static tree cp_build_function_call (tree, tree, tsubst_flags_t); @@ -5253,10 +5254,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. */ @@ -5264,8 +5264,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 @@ -5278,7 +5278,7 @@ cp_build_binary_op (location_t location, cop1 = cp_convert (orig_type, op1, complain); 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); } @@ -6823,7 +6823,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, @@ -6967,7 +6967,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, diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi index d467a1652ee..3bad2401172 100644 --- a/gcc/doc/extend.texi +++ b/gcc/doc/extend.texi @@ -2901,6 +2901,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 diff --git a/gcc/flag-types.h b/gcc/flag-types.h index 27a38efdc8e..5faade53975 100644 --- a/gcc/flag-types.h +++ b/gcc/flag-types.h @@ -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. */ diff --git a/gcc/gcc.c b/gcc/gcc.c index 4724276a318..3292532996b 100644 --- a/gcc/gcc.c +++ b/gcc/gcc.c @@ -9398,7 +9398,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 diff --git a/gcc/gimple-fold.c b/gcc/gimple-fold.c index d12f9d053c9..0f8e326a0e8 100644 --- a/gcc/gimple-fold.c +++ b/gcc/gimple-fold.c @@ -56,6 +56,7 @@ along with GCC; see the file COPYING3. If not see #include "ipa-chkp.h" #include "tree-cfg.h" #include "fold-const-call.h" +#include "asan.h" /* Return true when DECL can be referenced from current unit. FROM_DECL (if non-null) specify constructor of variable DECL was taken from. @@ -3479,7 +3480,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)) diff --git a/gcc/gimplify.c b/gcc/gimplify.c index 653057fd543..9af95a28704 100644 --- a/gcc/gimplify.c +++ b/gcc/gimplify.c @@ -12647,7 +12647,7 @@ gimplify_function_tree (tree fndecl) && !needs_to_live_in_memory (ret)) DECL_GIMPLE_REG_P (ret) = 1; - if (asan_sanitize_use_after_scope () && !asan_no_sanitize_address_p ()) + if (asan_sanitize_use_after_scope () && sanitize_flags_p (SANITIZE_ADDRESS)) asan_poisoned_variables = new hash_set (); bind = gimplify_body (fndecl, true); if (asan_poisoned_variables) @@ -12714,8 +12714,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); diff --git a/gcc/ipa-inline.c b/gcc/ipa-inline.c index 8924f7eb15f..fb20d3723cc 100644 --- a/gcc/ipa-inline.c +++ b/gcc/ipa-inline.c @@ -117,6 +117,7 @@ along with GCC; see the file COPYING3. If not see #include "auto-profile.h" #include "builtins.h" #include "fibonacci_heap.h" +#include "asan.h" typedef fibonacci_heap edge_heap_t; typedef fibonacci_node edge_heap_node_t; @@ -257,17 +258,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 diff --git a/gcc/opts.c b/gcc/opts.c index 60ebe56c8a4..b870642f0ee 100644 --- a/gcc/opts.c +++ b/gcc/opts.c @@ -1656,6 +1656,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 @@ -1892,11 +1919,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: diff --git a/gcc/opts.h b/gcc/opts.h index eb626aa90ec..16371e8141f 100644 --- a/gcc/opts.h +++ b/gcc/opts.h @@ -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, diff --git a/gcc/sanopt.c b/gcc/sanopt.c index 70b7aeb80d3..16bdba76042 100644 --- a/gcc/sanopt.c +++ b/gcc/sanopt.c @@ -948,9 +948,7 @@ pass_sanopt::execute (function *fun) switch (DECL_FUNCTION_CODE (callee)) { case BUILT_IN_UNREACHABLE: - if (flag_sanitize & SANITIZE_UNREACHABLE - && !lookup_attribute ("no_sanitize_undefined", - DECL_ATTRIBUTES (fun->decl))) + if (sanitize_flags_p (SANITIZE_UNREACHABLE)) no_next = ubsan_instrument_unreachable (&gsi); break; default: diff --git a/gcc/testsuite/c-c++-common/ubsan/attrib-2.c b/gcc/testsuite/c-c++-common/ubsan/attrib-2.c index 71f2e58ea67..3f0a9c35d98 100644 --- a/gcc/testsuite/c-c++-common/ubsan/attrib-2.c +++ b/gcc/testsuite/c-c++-common/ubsan/attrib-2.c @@ -68,4 +68,14 @@ float_cast (void) c = d; } +__attribute__((no_sanitize(("undefined")))) +static void +float_cast2 (void) +{ + volatile double d = 300; + volatile signed char c; + c = d; +} + + /* { dg-final { scan-assembler-not "__ubsan_handle" } } */ diff --git a/gcc/testsuite/gcc.dg/asan/use-after-scope-4.c b/gcc/testsuite/gcc.dg/asan/use-after-scope-4.c index 77d7052bd19..44dc79535d2 100644 --- a/gcc/testsuite/gcc.dg/asan/use-after-scope-4.c +++ b/gcc/testsuite/gcc.dg/asan/use-after-scope-4.c @@ -1,16 +1,40 @@ // { dg-do run } -int +#define FN(NAME) \ +NAME (void) \ +{ \ + char *ptr; \ + char *ptr2; \ + { \ + char my_char[9]; \ + ptr = &my_char[0]; \ + __builtin_memcpy (&ptr2, &ptr, sizeof (ptr2)); \ + } \ + \ + *(ptr2+9) = 'c'; \ +} + +void +__attribute__((no_sanitize(("address")))) +__attribute__((no_sanitize(("undefined")))) +__attribute__((no_sanitize(("address")))) +__attribute__((no_sanitize(("null")))) +FN (fn1) + +void +__attribute__((no_sanitize(("all")))) +FN (fn2) + +void __attribute__((no_sanitize_address)) +FN (fn3) + +int main (void) { - char *ptr; - char *ptr2; - { - char my_char[9]; - ptr = &my_char[0]; - __builtin_memcpy (&ptr2, &ptr, sizeof (ptr2)); - } + fn1 (); + fn2 (); + fn3 (); - *(ptr2+9) = 'c'; + return 0; } diff --git a/gcc/tree-cfg.c b/gcc/tree-cfg.c index c84e99d0945..7df80f8ee8c 100644 --- a/gcc/tree-cfg.c +++ b/gcc/tree-cfg.c @@ -60,6 +60,7 @@ along with GCC; see the file COPYING3. If not see #include "gimplify.h" #include "attribs.h" #include "selftest.h" +#include "opts.h" /* This file contains functions for building the Control Flow Graph (CFG) for a function tree. */ @@ -7555,6 +7556,25 @@ dump_default_def (FILE *file, tree def, int spc, dump_flags_t flags) fprintf (file, ";\n"); } +/* Print no_sanitize attribute to FILE for a given attribute VALUE. */ + +static void +print_no_sanitize_attr_value (FILE *file, tree value) +{ + unsigned int flags = tree_to_uhwi (value); + bool first = true; + for (int i = 0; sanitizer_opts[i].name != NULL; ++i) + { + if ((sanitizer_opts[i].flag & flags) == sanitizer_opts[i].flag) + { + if (!first) + fprintf (file, " | "); + fprintf (file, "%s", sanitizer_opts[i].name); + first = false; + } + } +} + /* Dump FUNCTION_DECL FN to file FILE using FLAGS (see TDF_* in dumpfile.h) */ @@ -7582,11 +7602,16 @@ dump_function_to_file (tree fndecl, FILE *file, dump_flags_t flags) if (!first) fprintf (file, ", "); - print_generic_expr (file, get_attribute_name (chain), dump_flags); + tree name = get_attribute_name (chain); + print_generic_expr (file, name, dump_flags); if (TREE_VALUE (chain) != NULL_TREE) { fprintf (file, " ("); - print_generic_expr (file, TREE_VALUE (chain), dump_flags); + + if (strstr (IDENTIFIER_POINTER (name), "no_sanitize")) + print_no_sanitize_attr_value (file, TREE_VALUE (chain)); + else + print_generic_expr (file, TREE_VALUE (chain), dump_flags); fprintf (file, ")"); } } diff --git a/gcc/tsan.c b/gcc/tsan.c index dd8cd85647c..2f98b936c03 100644 --- a/gcc/tsan.c +++ b/gcc/tsan.c @@ -896,9 +896,7 @@ public: opt_pass * clone () { return new pass_tsan (m_ctxt); } virtual bool gate (function *) { - return ((flag_sanitize & SANITIZE_THREAD) != 0 - && !lookup_attribute ("no_sanitize_thread", - DECL_ATTRIBUTES (current_function_decl))); + return sanitize_flags_p (SANITIZE_THREAD); } virtual unsigned int execute (function *) { return tsan_pass (); } @@ -938,9 +936,7 @@ public: /* opt_pass methods: */ virtual bool gate (function *) { - return ((flag_sanitize & SANITIZE_THREAD) != 0 && !optimize - && !lookup_attribute ("no_sanitize_thread", - DECL_ATTRIBUTES (current_function_decl))); + return (sanitize_flags_p (SANITIZE_THREAD) && !optimize); } virtual unsigned int execute (function *) { return tsan_pass (); } diff --git a/gcc/ubsan.c b/gcc/ubsan.c index 133409a7813..cee525ccf98 100644 --- a/gcc/ubsan.c +++ b/gcc/ubsan.c @@ -757,7 +757,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) { @@ -1181,13 +1181,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))) @@ -1355,13 +1355,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)) @@ -1924,16 +1925,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 = @@ -1959,13 +1950,12 @@ public: /* opt_pass methods: */ virtual bool gate (function *) { - 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)); } virtual unsigned int execute (function *); @@ -1992,11 +1982,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); @@ -2018,14 +2008,14 @@ pass_ubsan::execute (function *fun) } } - 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)) { @@ -2033,14 +2023,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); diff --git a/gcc/ubsan.h b/gcc/ubsan.h index f04929d6678..fddd359ebc3 100644 --- a/gcc/ubsan.h +++ b/gcc/ubsan.h @@ -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.13.1