From patchwork Wed May 11 12:54:01 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Martin_Li=C5=A1ka?= X-Patchwork-Id: 621026 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 3r4bfq1B18z9vK1 for ; Wed, 11 May 2016 22:54:26 +1000 (AEST) Authentication-Results: ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=gcc.gnu.org header.i=@gcc.gnu.org header.b=KO7tInoi; 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:references:cc:from:message-id:date:mime-version :in-reply-to:content-type; q=dns; s=default; b=n2L6nZojaBwHEHpJM fJz2gwCaBmbcbv0+UuGAPNHcXjDlsXiGAE8/uP1tAlSFh/hoYaYRzX0Dt/ikwVF6 8xn0UCmUSJq/VIa2a8q7ZfLZMgxyfjnt/pnCWCcChGAHr29NJpcpAzMPbs5LtTLz wp8OF2iraOAu5FpH7l9sZmZLlY= 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:references:cc:from:message-id:date:mime-version :in-reply-to:content-type; s=default; bh=p4enXBwLEWPf0w26rwJ1TAq CjSM=; b=KO7tInoimdMd5m9SMStJHi4qD4FqT6GvZqI0JZ1jJ+UvXoSTWxScih3 sahbnfo4KVHO/Un5JhDZoWPr0CNmHDW1dSYPb0GWEEn/MnxrJIjsEX3+qEfOmUog Qk+ipNt51C+yUuHbz5cBz8vZZ04J/OLc61PvnEOLNhN4jYASm6PU= Received: (qmail 60327 invoked by alias); 11 May 2016 12:54:17 -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 60295 invoked by uid 89); 11 May 2016 12:54:16 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=0.8 required=5.0 tests=BAYES_50, SPF_PASS autolearn=ham version=3.3.2 spammy=traits, Automatic, voidmode, VOIDmode X-HELO: mx2.suse.de Received: from mx2.suse.de (HELO mx2.suse.de) (195.135.220.15) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with (CAMELLIA256-SHA encrypted) ESMTPS; Wed, 11 May 2016 12:54:05 +0000 Received: from relay1.suse.de (charybdis-ext.suse.de [195.135.220.254]) by mx2.suse.de (Postfix) with ESMTP id 8806AAC59; Wed, 11 May 2016 12:54:01 +0000 (UTC) Subject: Re: [PATCH, RFC] Introduce -fsanitize=use-after-scope To: Jakub Jelinek References: <572C7A3E.4000905@suse.cz> <20160506122225.GH26501@tucnak.zalov.cz> Cc: GCC Patches From: =?UTF-8?Q?Martin_Li=c5=a1ka?= Message-ID: <57332B69.4040001@suse.cz> Date: Wed, 11 May 2016 14:54:01 +0200 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:38.0) Gecko/20100101 Thunderbird/38.7.2 MIME-Version: 1.0 In-Reply-To: <20160506122225.GH26501@tucnak.zalov.cz> X-IsSubscribed: yes On 05/06/2016 02:22 PM, Jakub Jelinek wrote: > On Fri, May 06, 2016 at 01:04:30PM +0200, Martin Liška wrote: >> I've started working on the patch couple of month go, basically after >> a brief discussion with Jakub on IRC. >> >> I'm sending the initial version which can successfully run instrumented >> tramp3d, postgresql server and Inkscape. It catches the basic set of >> examples which are added in following patch. >> >> The implementation is quite straightforward as works in following steps: >> >> 1) Every local variable stack slot is poisoned at the very beginning of a function (RTL emission) >> 2) In gimplifier, once we spot a DECL_EXPR, a variable is unpoisoned (by emitting ASAN_MARK builtin) >> and the variable is marked as addressable > > Not all vars have DECL_EXPRs though. Yeah, I've spotted one interesting example which is part of LLVM's testsuite: struct IntHolder { int val; }; const IntHolder *saved; void save(const IntHolder &holder) { saved = &holder; } int main(int argc, char *argv[]) { save({10}); int x = saved->val; // BOOM return x; } It would be also good to handle such temporaries. Any suggestions how to handle that in gimplifier? > >> 3) Similarly, BIND_EXPR is the place where we poison the variable (scope exit) >> 4) At the very end of the function, we clean up the poisoned memory >> 5) The builtins are expanded to call to libsanitizer run-time library (__asan_poison_stack_memory, __asan_unpoison_stack_memory) >> 6) As the use-after-scope stuff is already included in libsanitizer, no change is needed for the library > >> As mentioned, it's request for comment as it still has couple of limitations: >> a) VLA are not supported, which should make sense as we are unable to allocate a stack slot for that >> b) we can possibly strip some instrumentation in situations where a variable is introduced in a very first BB (RTL poisoning is superfluous). >> Similarly for a very last BB of a function, we can strip end of scope poisoning (and RTL unpoisoning). I'll do that incrementally. > > Yeah. > >> c) We require -fstack-reuse=none option, maybe it worth to warn a user if -fsanitize=use-after-scope is provided without the option? > > This should be implicitly set by -fsanitize=use-after-scope. Only if some > other -fstack-reuse= option is explicitly set together with > -fsanitize=use-after-scope, we should warn and reset it anyway. Handled in v2 of the patch. > >> d) An instrumented binary is quite slow (~20x for tramp3d) as every function call produces many memory read/writes. I'm wondering whether >> we should provide a faster alternative (like instrument just variables that have address taken) ? > > I don't see any point in instrumenting !needs_to_live_in_memory vars, > at least not those that don't need to live in memory at gimplification time. > How could one use those after scope? They can't be accessed by > dereferencing some pointer, and the symbol itself should be unavailable for > symbol lookup after the symbol goes out of scope. > Plus obviously ~20x slowdown isn't acceptable. > > Another thing is what to do with variables that are addressable at > gimplification time, but generally are made non-addressable afterwards, > such as due to optimizing away the taking of their address, inlining, etc. > > Perhaps depending on how big slowdown you get after just instrumenting > needs_to_live_in_memory vars from ~ gimplification time and/or with the > possible inlining of the poisoning/unpoisoning (again, should be another > knob), at least with small sized vars, there might be another knob, > which would tell if vars that are made non-addressable during optimizations > later on should be instrumented or not. > E.g. if you ASAN_MARK all needs_to_live_in_memory vars early, you could > during the addressable determination when the knob says stuff should be > faster, but less precise, ignore the vars that are addressable just because > of the ASAN_MARK calls, and if they'd then turn to be non-addressable, > remove the corresponding ASAN_MARK calls. Following the aforementioned instrumentation and utilizing direct shadow memory instruction emission, I was able to reduce tramp3d slowdown to 3x and postgresql server test-suite runs 2x slower. Apart from that, second version of the patch changes: + fixed issues with missing stack unpoisoning; currently, I mark all VAR_DECLs that are in ASAN_MARK internal fns and stack prologue/epilogue is emitted just for these vars + removed unneeded hunks (tree-vect-patterns.c and asan_poisoning.cc) + LABEL unpoisoning code makes stable sort for variables that were already used in the context + stack poisoning hasn't worked for -O1+ due to following guard in asan.c /* Automatic vars in the current function will be always accessible. */ + direct shadow memory poisoning/unpoisoning code is introduced - in both scenarios (RTL and GIMPLE), I would appreciate feedback if storing multiple bytes is fine? What is the maximum memory wide store mode supported by a target? How can I get such information? + the maximum object size handled by a direct emission is guarded by use-after-scope-direct-emission-threshold parameter; initial value (256B) should maximally emit store of 32B > >> 2016-05-04 Martin Liska >> >> * asan/asan_poisoning.cc: Do not call PoisonShadow in case >> of zero size of aligned size. > > Generally, libsanitizer changes would need to go through upstream. Sure, in fact the hunk looks unneeded. > >> --- a/gcc/asan.c >> +++ b/gcc/asan.c >> @@ -45,6 +45,7 @@ along with GCC; see the file COPYING3. If not see >> #include "varasm.h" >> #include "stor-layout.h" >> #include "tree-iterator.h" >> +#include "params.h" >> #include "asan.h" >> #include "dojump.h" >> #include "explow.h" >> @@ -54,7 +55,6 @@ along with GCC; see the file COPYING3. If not see >> #include "cfgloop.h" >> #include "gimple-builder.h" >> #include "ubsan.h" >> -#include "params.h" >> #include "builtins.h" >> #include "fnmatch.h" > > Why do you need to move params.h around? Does asan.h now depend on > params.h? Yeah, depends because of: static inline bool asan_sanitize_use_after_scope (void) { return ((flag_sanitize & SANITIZE_ADDRESS_USE_AFTER_SCOPE) == SANITIZE_ADDRESS_USE_AFTER_SCOPE && flag_stack_reuse == SR_NONE && ASAN_STACK); } Where ASAN_STACK comes from params.h. > >> + gimplify_seq_add_stmt >> + (seq_p, gimple_build_call_internal (IFN_ASAN_MARK, 3, >> + build_int_cst (integer_type_node, >> + flags), >> + base, unit_size)); > > Formatting, better introduce some temporary variables, like > gimple *g = gimple_build_call_internal (...); > gimplify_seq_add_stmt (seq_p, g); > Done. >> --- a/gcc/tree-vect-patterns.c >> +++ b/gcc/tree-vect-patterns.c >> @@ -3570,7 +3570,8 @@ vect_recog_mask_conversion_pattern (vec *stmts, tree *type_in, >> { >> gimple *last_stmt = stmts->pop (); >> enum tree_code rhs_code; >> - tree lhs, rhs1, rhs2, tmp, rhs1_type, rhs2_type, vectype1, vectype2; >> + tree lhs = NULL_TREE, rhs1, rhs2, tmp, rhs1_type, rhs2_type; >> + tree vectype1, vectype2; >> stmt_vec_info stmt_vinfo = vinfo_for_stmt (last_stmt); >> stmt_vec_info pattern_stmt_info; >> vec_info *vinfo = stmt_vinfo->vinfo; > > How is the above related to this patch? Done. > >> +/* Return TRUE if we should instrument for use-after-scope sanity checking. */ >> + >> +static inline bool >> +asan_sanitize_use_after_scope (void) >> +{ >> + return (flag_sanitize & SANITIZE_ADDRESS_USE_AFTER_SCOPE) >> + == SANITIZE_ADDRESS_USE_AFTER_SCOPE >> + && flag_stack_reuse == SR_NONE >> + && ASAN_STACK; >> +} > > Formatting, there should be ()s around the whole return expression as it > spans multiple lines, and it should be indented properly. > Plus IMHO flag_stack_reuse should be dealt with during option handling. > > Jakub > Also done. Thanks, Martin From 98b3e4fa69221f3c4539c2fe521deb45658c97aa Mon Sep 17 00:00:00 2001 From: marxin Date: Tue, 3 May 2016 15:35:22 +0200 Subject: [PATCH 1/2] Introduce -fsanitize=use-after-scope gcc/ChangeLog: 2016-05-10 Martin Liska * asan.c (enum asan_check_flags): Enum is moved to a header file. (asan_init_shadow_ptr_types): Add new shadow_ptr_type. (get_shadow_memory_size): New function. (asan_poison_stack_variables): Likewise. (asan_emit_stack_protection): Poison and unpoison stack variables. (build_shadow_mem_access): New arguments is added. (instrument_derefs): Do not skip automatic variables if we instrument for use-after-scope. (asan_store_shadow_bytes): New function. (asan_expand_mark_ifn): Likewise. * asan.h (enum asan_mark_flags): Move from the source file. (asan_sanitize_use_after_scope): New function. (asan_no_sanitize_address_p): Likewise. * builtins.c: Include asan.h file. * cfgexpand.c (asan_sanitize_stack_p): Use asan_no_sanitize_address_p. * flag-types.h (enum sanitize_code): Add SANITIZE_ADDRESS_USE_AFTER_SCOPE enum value. * gimplify.c (asan_poison_variable): New function. (gimplify_bind_expr): Unpoison stack variables. (gimplify_decl_expr): Poison stack variables. (gimplify_expr): Unpoison stack variables that precede a label. (gimplify_function_tree): Guard that all local variables (sort_by_decl_uid): New function. are properly unpoisoned. * internal-fn.c (expand_ASAN_MARK): New function. * internal-fn.def: Declare ASAN_MARK. * opts-global.c: Include asan.h header file. * opts.c (finish_options): Handle interaction between -fstack-reuse and -fsanitize=use-after-scope. * params.def: Add new param use-after-scope-direct-emission-threshold. * params.h: Define the param. * sancov.c: Include asan.h header file. * sanitizer.def: Define __asan_poison_stack_memory and __asan_unpoison_stack_memory. * sanopt.c (pass_sanopt::execute): Expand ASAN_MARK internal fns. * tree-streamer-in.c: Include asan.h header file. * tsan.c: Likewise. * ubsan.c: Likewise. * varasm.c: Likewise. * hash-set.h (hash_set::empty): New function. --- gcc/asan.c | 258 ++++++++++++++++++++++++++++++++++++++++++++----- gcc/asan.h | 52 +++++++++- gcc/builtins.c | 1 + gcc/c-family/c-ubsan.c | 1 + gcc/cfgexpand.c | 3 +- gcc/cp/decl2.c | 1 + gcc/flag-types.h | 5 +- gcc/gimplify.c | 118 ++++++++++++++++++++-- gcc/hash-set.h | 7 ++ gcc/internal-fn.c | 9 ++ gcc/internal-fn.def | 1 + gcc/opts-global.c | 1 + gcc/opts.c | 14 +++ gcc/params.def | 6 ++ gcc/params.h | 2 + gcc/sancov.c | 1 + gcc/sanitizer.def | 4 + gcc/sanopt.c | 5 +- gcc/tree-streamer-in.c | 1 + gcc/tsan.c | 1 + gcc/ubsan.c | 1 + gcc/varasm.c | 1 + 22 files changed, 449 insertions(+), 44 deletions(-) diff --git a/gcc/asan.c b/gcc/asan.c index 71095fb..537d6c8 100644 --- a/gcc/asan.c +++ b/gcc/asan.c @@ -45,6 +45,7 @@ along with GCC; see the file COPYING3. If not see #include "varasm.h" #include "stor-layout.h" #include "tree-iterator.h" +#include "params.h" #include "asan.h" #include "dojump.h" #include "explow.h" @@ -54,7 +55,6 @@ along with GCC; see the file COPYING3. If not see #include "cfgloop.h" #include "gimple-builder.h" #include "ubsan.h" -#include "params.h" #include "builtins.h" #include "fnmatch.h" @@ -243,6 +243,11 @@ static unsigned HOST_WIDE_INT asan_shadow_offset_value; static bool asan_shadow_offset_computed; static vec sanitized_sections; +/* Set of variable declarations that are going to be guarded by + use-after-scope sanitizer. */ + +static hash_set asan_handled_variables(13); + /* Sets shadow offset to value in string VAL. */ bool @@ -313,22 +318,13 @@ asan_shadow_offset () alias_set_type asan_shadow_set = -1; -/* Pointer types to 1 resp. 2 byte integers in shadow memory. A separate +/* Pointer types to 1, 2 or 4 byte integers in shadow memory. A separate alias set is used for all shadow memory accesses. */ -static GTY(()) tree shadow_ptr_types[2]; +static GTY(()) tree shadow_ptr_types[3]; /* Decl for __asan_option_detect_stack_use_after_return. */ static GTY(()) tree asan_detect_stack_use_after_return; -/* Various flags for Asan builtins. */ -enum asan_check_flags -{ - ASAN_CHECK_STORE = 1 << 0, - ASAN_CHECK_SCALAR_ACCESS = 1 << 1, - ASAN_CHECK_NON_ZERO_LEN = 1 << 2, - ASAN_CHECK_LAST = 1 << 3 -}; - /* Hashtable support for memory references used by gimple statements. */ @@ -931,12 +927,16 @@ static void asan_init_shadow_ptr_types (void) { asan_shadow_set = new_alias_set (); - shadow_ptr_types[0] = build_distinct_type_copy (signed_char_type_node); - TYPE_ALIAS_SET (shadow_ptr_types[0]) = asan_shadow_set; - shadow_ptr_types[0] = build_pointer_type (shadow_ptr_types[0]); - shadow_ptr_types[1] = build_distinct_type_copy (short_integer_type_node); - TYPE_ALIAS_SET (shadow_ptr_types[1]) = asan_shadow_set; - shadow_ptr_types[1] = build_pointer_type (shadow_ptr_types[1]); + tree types[3] = { signed_char_type_node, short_integer_type_node, + integer_type_node }; + + for (unsigned i = 0; i < 3; i++) + { + shadow_ptr_types[i] = build_distinct_type_copy (types[i]); + TYPE_ALIAS_SET (shadow_ptr_types[i]) = asan_shadow_set; + shadow_ptr_types[i] = build_pointer_type (shadow_ptr_types[i]); + } + initialize_sanitizer_builtins (); } @@ -1020,6 +1020,91 @@ asan_function_start (void) current_function_funcdef_no); } +/* Return number of shadow bytes that are occupied by a local variable + of SIZE bytes. */ + +static unsigned HOST_WIDE_INT +get_shadow_memory_size (unsigned HOST_WIDE_INT size) +{ + /* Round up size of object. */ + unsigned HOST_WIDE_INT r; + if ((r = size % BITS_PER_UNIT) != 0) + size += BITS_PER_UNIT - r; + + return size / BITS_PER_UNIT; +} + +/* Depending on POISON flag, emit a call to poison (or unpoison) stack memory + allocated for local variables, localted in OFFSETS. LENGTH is number + of OFFSETS, BASE is the register holding the stack base, + against which OFFSETS array offsets are relative to. BASE_OFFSET represents + an offset requested by alignment and similar stuff. */ + +static void +asan_poison_stack_variables (rtx shadow_base, rtx base, + HOST_WIDE_INT base_offset, + HOST_WIDE_INT *offsets, int length, + tree *decls, bool poison) +{ + if (asan_sanitize_use_after_scope ()) + for (int l = length - 2; l > 0; l -= 2) + { + tree decl = decls[l / 2 - 1]; + HOST_WIDE_INT var_offset = offsets[l]; + HOST_WIDE_INT var_end_offset = offsets[l - 1]; + if (!asan_handled_variables.contains (decl)) + { + if (dump_file && (dump_flags & TDF_DETAILS)) + fprintf (dump_file, "Skipping stack emission for variable: %s " + "(%ldB)\n", + IDENTIFIER_POINTER (DECL_NAME (decl)), + var_end_offset - var_offset); + continue; + } + + rtx source = expand_binop (Pmode, add_optab, base, + gen_int_mode + (var_offset - base_offset, Pmode), + NULL_RTX, 1, OPTAB_DIRECT); + + HOST_WIDE_INT size = var_end_offset - var_offset; + if (size <= ASAN_PARAM_USE_AFTER_SCOPE_DIRECT_EMISSION_THRESHOLD) + { + unsigned HOST_WIDE_INT shadow_size + = get_shadow_memory_size (size); + + rtx shadow_mem = gen_rtx_MEM (SImode, shadow_base); + rtx var_mem = adjust_address (shadow_mem, QImode, + (var_offset - base_offset) + >> ASAN_SHADOW_SHIFT); + + char c = poison ? ASAN_STACK_MAGIC_USE_AFTER_SCOPE : 0; + for (unsigned i = 0; i < shadow_size; ++i) + { + emit_move_insn (var_mem, gen_int_mode (c, QImode)); + var_mem = adjust_address (var_mem, QImode, 1); + } + } + else + { + rtx size_rtx = GEN_INT (size); + const char *fname = poison ? "__asan_poison_stack_memory" + :"__asan_unpoison_stack_memory"; + rtx ret = init_one_libfunc (fname); + emit_library_call (ret, LCT_NORMAL, VOIDmode, 2, source, ptr_mode, + size_rtx, TYPE_MODE (pointer_sized_int_node)); + } + + if (dump_file && (dump_flags & TDF_DETAILS)) + fprintf (dump_file, "Emitting stack %s for variable: %s" + "(%ldB)\n", + poison ? "poisoning" : "unpoisoning", + IDENTIFIER_POINTER (DECL_NAME (decl)), + var_end_offset - var_offset); + } +} + + /* Insert code to protect stack vars. The prologue sequence should be emitted directly, epilogue sequence returned. BASE is the register holding the stack base, against which OFFSETS array offsets are relative to, OFFSETS @@ -1228,6 +1313,11 @@ asan_emit_stack_protection (rtx base, rtx pbase, unsigned int alignb, } cur_shadow_byte = ASAN_STACK_MAGIC_MIDDLE; } + + /* Poison stack variables at the very beginning of a function. */ + asan_poison_stack_variables (shadow_base, base, base_offset, offsets, length, + decls, true); + do_pending_stack_adjust (); /* Construct epilogue sequence. */ @@ -1309,6 +1399,14 @@ asan_emit_stack_protection (rtx base, rtx pbase, unsigned int alignb, asan_clear_shadow (shadow_mem, last_size >> ASAN_SHADOW_SHIFT); } + /* Unpoison stack variables at the end of a function. As the former + stack memory can be reused, we have to unpoison the memory. */ + asan_poison_stack_variables (shadow_base, base, base_offset, offsets, length, + decls, false); + + /* Clean-up set with instrumented stack variables. */ + asan_handled_variables.empty (); + do_pending_stack_adjust (); if (lab) emit_label (lab); @@ -1593,7 +1691,8 @@ insert_if_then_before_iter (gcond *cond, static tree build_shadow_mem_access (gimple_stmt_iterator *gsi, location_t location, - tree base_addr, tree shadow_ptr_type) + tree base_addr, tree shadow_ptr_type, + bool return_ptr = false) { tree t, uintptr_type = TREE_TYPE (base_addr); tree shadow_type = TREE_TYPE (shadow_ptr_type); @@ -1616,11 +1715,15 @@ build_shadow_mem_access (gimple_stmt_iterator *gsi, location_t location, gimple_set_location (g, location); gsi_insert_after (gsi, g, GSI_NEW_STMT); - t = build2 (MEM_REF, shadow_type, gimple_assign_lhs (g), - build_int_cst (shadow_ptr_type, 0)); - g = gimple_build_assign (make_ssa_name (shadow_type), MEM_REF, t); - gimple_set_location (g, location); - gsi_insert_after (gsi, g, GSI_NEW_STMT); + if (!return_ptr) + { + t = build2 (MEM_REF, shadow_type, gimple_assign_lhs (g), + build_int_cst (shadow_ptr_type, 0)); + g = gimple_build_assign (make_ssa_name (shadow_type), MEM_REF, t); + gimple_set_location (g, location); + gsi_insert_after (gsi, g, GSI_NEW_STMT); + } + return gimple_assign_lhs (g); } @@ -1824,7 +1927,8 @@ instrument_derefs (gimple_stmt_iterator *iter, tree t, { /* Automatic vars in the current function will be always accessible. */ - if (decl_function_context (inner) == current_function_decl) + if (decl_function_context (inner) == current_function_decl + && !asan_sanitize_use_after_scope ()) return; } /* Always instrument external vars, they might be dynamically @@ -2573,6 +2677,110 @@ asan_finish_file (void) flag_sanitize |= SANITIZE_ADDRESS; } +static void +asan_store_shadow_bytes (gimple_stmt_iterator *iter, location_t loc, + tree shadow, + unsigned HOST_WIDE_INT base_addr_offset, + unsigned char value, unsigned bytes) +{ + tree shadow_ptr_type; + + switch (bytes) + { + case 1: + shadow_ptr_type = shadow_ptr_types[0]; + break; + case 2: + shadow_ptr_type = shadow_ptr_types[1]; + break; + case 4: + shadow_ptr_type = shadow_ptr_types[2]; + break; + default: + gcc_unreachable (); + } + + unsigned HOST_WIDE_INT val = 0; + for (unsigned i = 0; i < bytes; ++i) + val |= (unsigned HOST_WIDE_INT) value << (BITS_PER_UNIT * i); + + tree magic = build_int_cst (TREE_TYPE (shadow_ptr_type), val); + + tree dest = build2 (MEM_REF, TREE_TYPE (shadow_ptr_type), shadow, + build_int_cst (shadow_ptr_type, base_addr_offset)); + + gimple *g = gimple_build_assign (dest, magic); + gimple_set_location (g, loc); + gsi_insert_after (iter, g, GSI_NEW_STMT); +} + +/* Expand the ASAN_MARK builtins. */ + +bool +asan_expand_mark_ifn (gimple_stmt_iterator *iter) +{ + gimple *g = gsi_stmt (*iter); + location_t loc = gimple_location (g); + HOST_WIDE_INT flags = tree_to_shwi (gimple_call_arg (g, 0)); + gcc_assert (flags < ASAN_MARK_LAST); + bool is_clobber = (flags & ASAN_MARK_CLOBBER) != 0; + + tree base = gimple_call_arg (g, 1); + gcc_checking_assert (TREE_CODE (base) == ADDR_EXPR); + tree decl = TREE_OPERAND (base, 0); + gcc_checking_assert (TREE_CODE (decl) == VAR_DECL); + asan_handled_variables.add (decl); + tree len = gimple_call_arg (g, 2); + + gcc_assert (tree_fits_shwi_p (len)); + HOST_WIDE_INT size_in_bytes = tree_to_shwi (len); + gcc_assert (size_in_bytes); + + g = gimple_build_assign (make_ssa_name (pointer_sized_int_node), + NOP_EXPR, base); + gimple_set_location (g, loc); + gsi_replace (iter, g, false); + tree base_addr = gimple_assign_lhs (g); + + if (size_in_bytes <= ASAN_PARAM_USE_AFTER_SCOPE_DIRECT_EMISSION_THRESHOLD) + { + unsigned HOST_WIDE_INT shadow_size + = get_shadow_memory_size (size_in_bytes); + char c = (char) is_clobber ? ASAN_STACK_MAGIC_USE_AFTER_SCOPE : 0; + + tree shadow = build_shadow_mem_access (iter, loc, base_addr, + shadow_ptr_types[0], true); + + for (unsigned HOST_WIDE_INT offset = 0; offset < shadow_size;) + { + unsigned size = 1; + if (shadow_size - offset >= 4) + size = 4; + else if (shadow_size - offset >= 2) + size = 2; + + asan_store_shadow_bytes (iter, loc, shadow, offset, c, size); + offset += size; + } + } + else + { + g = gimple_build_assign (make_ssa_name (pointer_sized_int_node), + NOP_EXPR, len); + gimple_set_location (g, loc); + gsi_insert_before (iter, g, GSI_SAME_STMT); + tree sz_arg = gimple_assign_lhs (g); + + tree fun = builtin_decl_implicit (is_clobber ? BUILT_IN_ASAN_CLOBBER_N + : BUILT_IN_ASAN_UNCLOBBER_N); + g = gimple_build_call (fun, 2, base_addr, sz_arg); + gimple_set_location (g, loc); + gsi_insert_after (iter, g, GSI_NEW_STMT); + } + + return false; +} + /* Expand the ASAN_{LOAD,STORE} builtins. */ bool diff --git a/gcc/asan.h b/gcc/asan.h index 7ec693f..7155334 100644 --- a/gcc/asan.h +++ b/gcc/asan.h @@ -29,6 +29,7 @@ extern bool asan_protect_global (tree); extern void initialize_sanitizer_builtins (void); extern tree asan_dynamic_init_call (bool); extern bool asan_expand_check_ifn (gimple_stmt_iterator *, bool); +extern bool asan_expand_mark_ifn (gimple_stmt_iterator *); extern gimple_stmt_iterator create_cond_insert_point (gimple_stmt_iterator *, bool, bool, bool, basic_block *, basic_block *); @@ -36,6 +37,10 @@ extern gimple_stmt_iterator create_cond_insert_point /* Alias set for accessing the shadow memory. */ extern alias_set_type asan_shadow_set; +/* Hash set of inlined variables that cannot be poisoned by use-after-cope + sanitizer. */ +extern hash_set asan_inlined_variables; + /* Shadow memory is found at (address >> ASAN_SHADOW_SHIFT) + asan_shadow_offset (). */ #define ASAN_SHADOW_SHIFT 3 @@ -50,15 +55,33 @@ extern alias_set_type asan_shadow_set; the frame. Middle is for padding in between variables, right is above the last protected variable and partial immediately after variables up to ASAN_RED_ZONE_SIZE alignment. */ -#define ASAN_STACK_MAGIC_LEFT 0xf1 -#define ASAN_STACK_MAGIC_MIDDLE 0xf2 -#define ASAN_STACK_MAGIC_RIGHT 0xf3 -#define ASAN_STACK_MAGIC_PARTIAL 0xf4 -#define ASAN_STACK_MAGIC_USE_AFTER_RET 0xf5 +#define ASAN_STACK_MAGIC_LEFT 0xf1 +#define ASAN_STACK_MAGIC_MIDDLE 0xf2 +#define ASAN_STACK_MAGIC_RIGHT 0xf3 +#define ASAN_STACK_MAGIC_PARTIAL 0xf4 +#define ASAN_STACK_MAGIC_USE_AFTER_RET 0xf5 +#define ASAN_STACK_MAGIC_USE_AFTER_SCOPE 0xf8 #define ASAN_STACK_FRAME_MAGIC 0x41b58ab3 #define ASAN_STACK_RETIRED_MAGIC 0x45e0360e +/* Various flags for Asan builtins. */ +enum asan_check_flags +{ + ASAN_CHECK_STORE = 1 << 0, + ASAN_CHECK_SCALAR_ACCESS = 1 << 1, + ASAN_CHECK_NON_ZERO_LEN = 1 << 2, + ASAN_CHECK_LAST = 1 << 3 +}; + +/* Flags for Asan check builtins. */ +enum asan_mark_flags +{ + ASAN_MARK_CLOBBER = 1 << 0, + ASAN_MARK_UNCLOBBER = 1 << 1, + ASAN_MARK_LAST = 1 << 2 +}; + /* Return true if DECL should be guarded on the stack. */ static inline bool @@ -105,4 +128,23 @@ asan_intercepted_p (enum built_in_function fcode) || fcode == BUILT_IN_STRNCMP || fcode == BUILT_IN_STRNCPY; } + +/* Return TRUE if we should instrument for use-after-scope sanity checking. */ + +static inline bool +asan_sanitize_use_after_scope (void) +{ + return ((flag_sanitize & SANITIZE_ADDRESS_USE_AFTER_SCOPE) + == SANITIZE_ADDRESS_USE_AFTER_SCOPE + && flag_stack_reuse == SR_NONE + && ASAN_STACK); +} + +static inline bool +asan_no_sanitize_address_p (void) +{ + return lookup_attribute ("no_sanitize_address", + DECL_ATTRIBUTES (current_function_decl)); +} + #endif /* TREE_ASAN */ diff --git a/gcc/builtins.c b/gcc/builtins.c index 476feb1..ee4379e 100644 --- a/gcc/builtins.c +++ b/gcc/builtins.c @@ -58,6 +58,7 @@ along with GCC; see the file COPYING3. If not see #include "langhooks.h" #include "value-prof.h" #include "builtins.h" +#include "params.h" #include "asan.h" #include "cilk.h" #include "tree-chkp.h" diff --git a/gcc/c-family/c-ubsan.c b/gcc/c-family/c-ubsan.c index 4022bdf..1a49e58 100644 --- a/gcc/c-family/c-ubsan.c +++ b/gcc/c-family/c-ubsan.c @@ -25,6 +25,7 @@ along with GCC; see the file COPYING3. If not see #include "c-family/c-common.h" #include "ubsan.h" #include "c-family/c-ubsan.h" +#include "params.h" #include "asan.h" #include "stor-layout.h" #include "builtins.h" diff --git a/gcc/cfgexpand.c b/gcc/cfgexpand.c index 77a1964..cbb30d5 100644 --- a/gcc/cfgexpand.c +++ b/gcc/cfgexpand.c @@ -876,8 +876,7 @@ asan_sanitize_stack_p (void) { return ((flag_sanitize & SANITIZE_ADDRESS) && ASAN_STACK - && !lookup_attribute ("no_sanitize_address", - DECL_ATTRIBUTES (current_function_decl))); + && !asan_no_sanitize_address_p ()); } /* A subroutine of expand_used_vars. Binpack the variables into diff --git a/gcc/cp/decl2.c b/gcc/cp/decl2.c index 0ea326d..d341478 100644 --- a/gcc/cp/decl2.c +++ b/gcc/cp/decl2.c @@ -46,6 +46,7 @@ along with GCC; see the file COPYING3. If not see #include "dumpfile.h" #include "intl.h" #include "c-family/c-ada-spec.h" +#include "params.h" #include "asan.h" extern cpp_reader *parse_in; diff --git a/gcc/flag-types.h b/gcc/flag-types.h index dd57e16..ca1399d 100644 --- a/gcc/flag-types.h +++ b/gcc/flag-types.h @@ -229,6 +229,7 @@ enum sanitize_code { SANITIZE_OBJECT_SIZE = 1UL << 20, SANITIZE_VPTR = 1UL << 21, SANITIZE_BOUNDS_STRICT = 1UL << 22, + SANITIZE_USE_AFTER_SCOPE = 1UL << 23, SANITIZE_UNDEFINED = SANITIZE_SHIFT | SANITIZE_DIVIDE | SANITIZE_UNREACHABLE | SANITIZE_VLA | SANITIZE_NULL | SANITIZE_RETURN | SANITIZE_SI_OVERFLOW | SANITIZE_BOOL | SANITIZE_ENUM @@ -237,7 +238,9 @@ enum sanitize_code { | SANITIZE_RETURNS_NONNULL_ATTRIBUTE | SANITIZE_OBJECT_SIZE | SANITIZE_VPTR, SANITIZE_NONDEFAULT = SANITIZE_FLOAT_DIVIDE | SANITIZE_FLOAT_CAST - | SANITIZE_BOUNDS_STRICT + | SANITIZE_BOUNDS_STRICT, + SANITIZE_ADDRESS_USE_AFTER_SCOPE = SANITIZE_ADDRESS + | SANITIZE_USE_AFTER_SCOPE }; /* flag_vtable_verify initialization levels. */ diff --git a/gcc/gimplify.c b/gcc/gimplify.c index f13980d..cd26f79 100644 --- a/gcc/gimplify.c +++ b/gcc/gimplify.c @@ -59,6 +59,11 @@ along with GCC; see the file COPYING3. If not see #include "gimple-walk.h" #include "langhooks-def.h" /* FIXME: for lhd_set_decl_assembler_name */ #include "builtins.h" +#include "params.h" +#include "asan.h" + +/* Hash set of poisoned variables in a bind expr. */ +static hash_set asan_poisoned_variables (13); enum gimplify_omp_var_data { @@ -1087,6 +1092,29 @@ build_stack_save_restore (gcall **save, gcall **restore) 1, tmp_var); } +/* Generate IFN_ASAN_MARK internal call that depending on POISON flag + either poisons or unpoisons a DECL. Created statement is appended + to SEQ_P gimple sequence. */ + +static void +asan_poison_variable (tree decl, bool poison, gimple_seq *seq_p) +{ + /* When within an OMP context, do not emit ASAN_MARK internal fns. */ + if (gimplify_omp_ctxp) + return; + + tree unit_size = DECL_SIZE_UNIT (decl); + tree base = build_fold_addr_expr (decl); + + HOST_WIDE_INT flags = poison ? ASAN_MARK_CLOBBER : ASAN_MARK_UNCLOBBER; + + gimple *g + = gimple_build_call_internal (IFN_ASAN_MARK, 3, + build_int_cst (integer_type_node, flags), + base, unit_size); + gimplify_seq_add_stmt (seq_p, g); +} + /* Gimplify a BIND_EXPR. Just voidify and recurse. */ static enum gimplify_status @@ -1189,6 +1217,11 @@ gimplify_bind_expr (tree *expr_p, gimple_seq *pre_p) /* Add clobbers for all variables that go out of scope. */ for (t = BIND_EXPR_VARS (bind_expr); t ; t = DECL_CHAIN (t)) { + bool unpoison_var = asan_poisoned_variables.contains (t); + if (asan_sanitize_use_after_scope () + && unpoison_var) + asan_poisoned_variables.remove (t); + if (TREE_CODE (t) == VAR_DECL && !is_global_var (t) && DECL_CONTEXT (t) == current_function_decl @@ -1197,17 +1230,26 @@ gimplify_bind_expr (tree *expr_p, gimple_seq *pre_p) && !DECL_HAS_VALUE_EXPR_P (t) /* Only care for variables that have to be in memory. Others will be rewritten into SSA names, hence moved to the top-level. */ - && !is_gimple_reg (t) - && flag_stack_reuse != SR_NONE) + && !is_gimple_reg (t)) { - tree clobber = build_constructor (TREE_TYPE (t), NULL); - gimple *clobber_stmt; - TREE_THIS_VOLATILE (clobber) = 1; - clobber_stmt = gimple_build_assign (t, clobber); - gimple_set_location (clobber_stmt, end_locus); - gimplify_seq_add_stmt (&cleanup, clobber_stmt); - - if (flag_openacc && oacc_declare_returns != NULL) + if (flag_stack_reuse != SR_NONE) + { + tree clobber = build_constructor (TREE_TYPE (t), NULL); + gimple *clobber_stmt; + TREE_THIS_VOLATILE (clobber) = 1; + clobber_stmt = gimple_build_assign (t, clobber); + gimple_set_location (clobber_stmt, end_locus); + gimplify_seq_add_stmt (&cleanup, clobber_stmt); + } + + if (asan_sanitize_use_after_scope () + && !asan_no_sanitize_address_p () + && unpoison_var) + asan_poison_variable (t, true, &cleanup); + + if (flag_stack_reuse != SR_NONE + && flag_openacc + && oacc_declare_returns != NULL) { tree *c = oacc_declare_returns->get (t); if (c != NULL) @@ -1479,6 +1521,22 @@ gimplify_decl_expr (tree *stmt_p, gimple_seq *seq_p) STACK_CHECK_MAX_VAR_SIZE) > 0)) gimplify_vla_decl (decl, seq_p); + tree unit_size = DECL_SIZE_UNIT (decl); + if (asan_sanitize_use_after_scope () + && !asan_no_sanitize_address_p () + && TREE_CODE (unit_size) == INTEGER_CST + && needs_to_live_in_memory (decl) + && DECL_NAME (decl) != NULL + && IDENTIFIER_POINTER (DECL_NAME (decl)) != NULL + && !TREE_STATIC (decl)) + { + TREE_ADDRESSABLE (decl) = 1; + DECL_GIMPLE_REG_P (decl) = 0; + + asan_poisoned_variables.add (decl); + asan_poison_variable (decl, false, seq_p); + } + /* Some front ends do not explicitly declare all anonymous artificial variables. We compensate here by declaring the variables, though it would be better if the front ends would @@ -10030,6 +10088,25 @@ gimplify_omp_ordered (tree expr, gimple_seq body) return gimple_build_omp_ordered (body, OMP_ORDERED_CLAUSES (expr)); } +/* Sort pair of VAR_DECLs A and B by DECL_UID. */ + +static int +sort_by_decl_uid (const void *a, const void *b) +{ + const tree *t1 = (const tree *)a; + const tree *t2 = (const tree *)b; + + int uid1 = DECL_UID (*t1); + int uid2 = DECL_UID (*t2); + + if (uid1 < uid2) + return -1; + else if (uid1 > uid2) + return 1; + else + return 0; +} + /* Convert the GENERIC expression tree *EXPR_P to GIMPLE. If the expression produces a value to be used as an operand inside a GIMPLE statement, the value will be stored back in *EXPR_P. This value will @@ -10540,6 +10617,23 @@ gimplify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p, == current_function_decl); gimplify_seq_add_stmt (pre_p, gimple_build_label (LABEL_EXPR_LABEL (*expr_p))); + + if (asan_sanitize_use_after_scope () + && !asan_no_sanitize_address_p ()) + { + unsigned c = asan_poisoned_variables.elements (); + auto_vec sorted_variables (c); + + for (hash_set ::iterator it + = asan_poisoned_variables.begin (); + it != asan_poisoned_variables.end (); ++it) + sorted_variables.safe_push (*it); + + sorted_variables.qsort (sort_by_decl_uid); + + for (unsigned i = 0; i < sorted_variables.length (); ++i) + asan_poison_variable (sorted_variables[i], false, pre_p); + } break; case CASE_LABEL_EXPR: @@ -11633,7 +11727,11 @@ gimplify_function_tree (tree fndecl) && !needs_to_live_in_memory (ret)) DECL_GIMPLE_REG_P (ret) = 1; + gcc_checking_assert (!asan_sanitize_use_after_scope () + || asan_poisoned_variables.elements () == 0); bind = gimplify_body (fndecl, true); + gcc_checking_assert (!asan_sanitize_use_after_scope () + || asan_poisoned_variables.elements () == 0); /* The tree body of the function is no longer needed, replace it with the new GIMPLE body. */ diff --git a/gcc/hash-set.h b/gcc/hash-set.h index 4ef4eba..05b2a98 100644 --- a/gcc/hash-set.h +++ b/gcc/hash-set.h @@ -65,6 +65,13 @@ public: m_table.remove_elt_with_hash (k, Traits::hash (k)); } + /* Clear all elements of the hash set. */ + + void empty () + { + m_table.empty (); + } + /* Call the call back on each pair of key and value with the passed in arg. */ diff --git a/gcc/internal-fn.c b/gcc/internal-fn.c index c867ddc..680a2d3 100644 --- a/gcc/internal-fn.c +++ b/gcc/internal-fn.c @@ -235,6 +235,15 @@ expand_ASAN_CHECK (internal_fn, gcall *) gcc_unreachable (); } +/* This should get expanded in the sanopt pass. */ + +static void +expand_ASAN_MARK (internal_fn, gcall *) +{ + gcc_unreachable (); +} + + /* This should get expanded in the tsan pass. */ static void diff --git a/gcc/internal-fn.def b/gcc/internal-fn.def index e729d85..81492ad 100644 --- a/gcc/internal-fn.def +++ b/gcc/internal-fn.def @@ -158,6 +158,7 @@ DEF_INTERNAL_FN (UBSAN_OBJECT_SIZE, ECF_LEAF | ECF_NOTHROW, NULL) DEF_INTERNAL_FN (ABNORMAL_DISPATCHER, ECF_NORETURN, NULL) DEF_INTERNAL_FN (BUILTIN_EXPECT, ECF_CONST | ECF_LEAF | ECF_NOTHROW, NULL) DEF_INTERNAL_FN (ASAN_CHECK, ECF_TM_PURE | ECF_LEAF | ECF_NOTHROW, ".R...") +DEF_INTERNAL_FN (ASAN_MARK, ECF_TM_PURE | ECF_LEAF | ECF_NOTHROW, ".R..") DEF_INTERNAL_FN (ADD_OVERFLOW, ECF_CONST | ECF_LEAF | ECF_NOTHROW, NULL) DEF_INTERNAL_FN (SUB_OVERFLOW, ECF_CONST | ECF_LEAF | ECF_NOTHROW, NULL) DEF_INTERNAL_FN (MUL_OVERFLOW, ECF_CONST | ECF_LEAF | ECF_NOTHROW, NULL) diff --git a/gcc/opts-global.c b/gcc/opts-global.c index b7e5232..963b542 100644 --- a/gcc/opts-global.c +++ b/gcc/opts-global.c @@ -35,6 +35,7 @@ along with GCC; see the file COPYING3. If not see #include "plugin.h" #include "toplev.h" #include "context.h" +#include "params.h" #include "asan.h" typedef const char *const_char_p; /* For DEF_VEC_P. */ diff --git a/gcc/opts.c b/gcc/opts.c index 0f9431a..c037a1f 100644 --- a/gcc/opts.c +++ b/gcc/opts.c @@ -972,6 +972,18 @@ finish_options (struct gcc_options *opts, struct gcc_options *opts_set, opts->x_flag_aggressive_loop_optimizations = 0; opts->x_flag_strict_overflow = 0; } + + /* Force -fstack-reuse=none in case -fsanitize=use-after-scope is enabled. */ + if (opts->x_flag_sanitize & SANITIZE_USE_AFTER_SCOPE) + { + if (opts->x_flag_stack_reuse != SR_NONE + && opts_set->x_flag_stack_reuse != SR_NONE) + error_at (loc, + "-fsanitize=use-after-scope requires " + "-fstack-reuse=none option"); + + opts->x_flag_stack_reuse = SR_NONE; + } } #define LEFT_COLUMN 27 @@ -1443,6 +1455,8 @@ const struct sanitizer_opts_s sanitizer_opts[] = { #define SANITIZER_OPT(name, flags) { #name, flags, sizeof #name - 1 } SANITIZER_OPT (address, SANITIZE_ADDRESS | SANITIZE_USER_ADDRESS), + SANITIZER_OPT (use-after-scope, SANITIZE_ADDRESS | SANITIZE_USER_ADDRESS + | SANITIZE_USE_AFTER_SCOPE), SANITIZER_OPT (kernel-address, SANITIZE_ADDRESS | SANITIZE_KERNEL_ADDRESS), SANITIZER_OPT (thread, SANITIZE_THREAD), SANITIZER_OPT (leak, SANITIZE_LEAK), diff --git a/gcc/params.def b/gcc/params.def index 62a1e40..0c63989 100644 --- a/gcc/params.def +++ b/gcc/params.def @@ -1144,6 +1144,12 @@ DEFPARAM (PARAM_ASAN_INSTRUMENTATION_WITH_CALL_THRESHOLD, "in function becomes greater or equal to this number.", 7000, 0, INT_MAX) +DEFPARAM (PARAM_USE_AFTER_SCOPE_DIRECT_EMISSION_THRESHOLD, + "use-after-scope-direct-emission-threshold", + "Use direct poisoning/unpoisoning intructions for variables " + "smaller or equal to this number.", + 256, 0, INT_MAX) + DEFPARAM (PARAM_UNINIT_CONTROL_DEP_ATTEMPTS, "uninit-control-dep-attempts", "Maximum number of nested calls to search for control dependencies " diff --git a/gcc/params.h b/gcc/params.h index 7221ab6..f8bd022 100644 --- a/gcc/params.h +++ b/gcc/params.h @@ -243,5 +243,7 @@ extern void init_param_values (int *params); PARAM_VALUE (PARAM_ASAN_USE_AFTER_RETURN) #define ASAN_INSTRUMENTATION_WITH_CALL_THRESHOLD \ PARAM_VALUE (PARAM_ASAN_INSTRUMENTATION_WITH_CALL_THRESHOLD) +#define ASAN_PARAM_USE_AFTER_SCOPE_DIRECT_EMISSION_THRESHOLD \ + PARAM_VALUE (PARAM_USE_AFTER_SCOPE_DIRECT_EMISSION_THRESHOLD) #endif /* ! GCC_PARAMS_H */ diff --git a/gcc/sancov.c b/gcc/sancov.c index f3211dd..655ff64 100644 --- a/gcc/sancov.c +++ b/gcc/sancov.c @@ -32,6 +32,7 @@ along with GCC; see the file COPYING3. If not see #include "tree-cfg.h" #include "tree-pass.h" #include "tree-iterator.h" +#include "params.h" #include "asan.h" namespace { diff --git a/gcc/sanitizer.def b/gcc/sanitizer.def index 303c1e4..1c142e9 100644 --- a/gcc/sanitizer.def +++ b/gcc/sanitizer.def @@ -165,6 +165,10 @@ DEF_SANITIZER_BUILTIN(BUILT_IN_ASAN_BEFORE_DYNAMIC_INIT, DEF_SANITIZER_BUILTIN(BUILT_IN_ASAN_AFTER_DYNAMIC_INIT, "__asan_after_dynamic_init", BT_FN_VOID, ATTR_NOTHROW_LEAF_LIST) +DEF_SANITIZER_BUILTIN(BUILT_IN_ASAN_CLOBBER_N, "__asan_poison_stack_memory", + BT_FN_VOID_PTR_PTRMODE, 0) +DEF_SANITIZER_BUILTIN(BUILT_IN_ASAN_UNCLOBBER_N, "__asan_unpoison_stack_memory", + BT_FN_VOID_PTR_PTRMODE, 0) /* Thread Sanitizer */ DEF_SANITIZER_BUILTIN(BUILT_IN_TSAN_INIT, "__tsan_init", diff --git a/gcc/sanopt.c b/gcc/sanopt.c index 2660453..43488a9 100644 --- a/gcc/sanopt.c +++ b/gcc/sanopt.c @@ -29,9 +29,9 @@ along with GCC; see the file COPYING3. If not see #include "gimple-pretty-print.h" #include "fold-const.h" #include "gimple-iterator.h" +#include "params.h" #include "asan.h" #include "ubsan.h" -#include "params.h" #include "tree-hash-traits.h" @@ -704,6 +704,9 @@ pass_sanopt::execute (function *fun) case IFN_ASAN_CHECK: no_next = asan_expand_check_ifn (&gsi, use_calls); break; + case IFN_ASAN_MARK: + no_next = asan_expand_mark_ifn (&gsi); + break; default: break; } diff --git a/gcc/tree-streamer-in.c b/gcc/tree-streamer-in.c index 2ad2f92..99397eb 100644 --- a/gcc/tree-streamer-in.c +++ b/gcc/tree-streamer-in.c @@ -32,6 +32,7 @@ along with GCC; see the file COPYING3. If not see #include "builtins.h" #include "ipa-chkp.h" #include "gomp-constants.h" +#include "params.h" #include "asan.h" diff --git a/gcc/tsan.c b/gcc/tsan.c index 47764bc..bdd002b 100644 --- a/gcc/tsan.c +++ b/gcc/tsan.c @@ -37,6 +37,7 @@ along with GCC; see the file COPYING3. If not see #include "tree-iterator.h" #include "tree-ssa-propagate.h" #include "tree-ssa-loop-ivopts.h" +#include "params.h" #include "tsan.h" #include "asan.h" #include "builtins.h" diff --git a/gcc/ubsan.c b/gcc/ubsan.c index c5543f8..2b4cbee 100644 --- a/gcc/ubsan.c +++ b/gcc/ubsan.c @@ -38,6 +38,7 @@ along with GCC; see the file COPYING3. If not see #include "cfgloop.h" #include "ubsan.h" #include "expr.h" +#include "params.h" #include "asan.h" #include "gimplify-me.h" #include "dfp.h" diff --git a/gcc/varasm.c b/gcc/varasm.c index 4a7124e..47e5215 100644 --- a/gcc/varasm.c +++ b/gcc/varasm.c @@ -50,6 +50,7 @@ along with GCC; see the file COPYING3. If not see #include "langhooks.h" #include "debug.h" #include "common/common-target.h" +#include "params.h" #include "asan.h" #include "rtl-iter.h" -- 2.8.2