From patchwork Tue Nov 22 11:55:37 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: 697661 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 3tNP7N3VJnz9sXx for ; Tue, 22 Nov 2016 22:56:00 +1100 (AEDT) Authentication-Results: ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=gcc.gnu.org header.i=@gcc.gnu.org header.b="Ed8qleLx"; 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=fI7780Q12TP3j1c7F NeF0086hyrwf9/6wilzb6+2/xZhh3xUvbYjP4mY0PHuLmSGLuLvAHMjTqYClQpfL M/FkFh71Of8acOW16u7SfWvsNYfNnpgQ0/GwLbig/9QFU1nb720ynOa1VNRcpxv2 rGDaCqD2QDVmYdT8U/eJlYnnMU= 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=LVzQloDVxpIcAsu41Vrqiru yp08=; b=Ed8qleLxX9Sdgt/93/8u8R27sQTdhQMiCLNghZBRNF5IOM3rgHDfnoB YMbJMG8ug3XoURI7B6Vv/8kQ+/cFaw2waOS4obuR9FDm238ufd6eMWDAMvmsfbd9 CMDSXgQVogBuAd8T/AQLlYfm/GedhXdRWsBXiAkOCKe2tCPqPRB4= Received: (qmail 1810 invoked by alias); 22 Nov 2016 11:55:51 -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 1796 invoked by uid 89); 22 Nov 2016 11:55:50 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-1.9 required=5.0 tests=BAYES_00, SPF_PASS autolearn=ham version=3.3.2 spammy=32, 8, 30, 6, sk:BUILT_I, unrestricted 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 ESMTP; Tue, 22 Nov 2016 11:55:40 +0000 Received: from relay1.suse.de (charybdis-ext.suse.de [195.135.220.254]) by mx2.suse.de (Postfix) with ESMTP id 0467BAC10; Tue, 22 Nov 2016 11:55:38 +0000 (UTC) Subject: Re: [RFC][PATCH] Speed-up use-after-scope (re-writing to SSA) To: Jakub Jelinek References: <20161102095202.GL3541@tucnak.redhat.com> <20161102125609.GQ3541@tucnak.redhat.com> <20161102130612.GR3541@tucnak.redhat.com> <774a5d54-30f6-3212-ea4c-21e751356055@suse.cz> <20161116130733.GT3541@tucnak.redhat.com> <469bf86a-e43c-c571-66e4-87db78b6fb11@suse.cz> <20161116162841.GX3541@tucnak.redhat.com> Cc: Richard Biener , GCC Patches From: =?UTF-8?Q?Martin_Li=c5=a1ka?= Message-ID: Date: Tue, 22 Nov 2016 12:55:37 +0100 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:45.0) Gecko/20100101 Thunderbird/45.4.0 MIME-Version: 1.0 In-Reply-To: <20161116162841.GX3541@tucnak.redhat.com> X-IsSubscribed: yes On 11/16/2016 05:28 PM, Jakub Jelinek wrote: > On Wed, Nov 16, 2016 at 05:01:31PM +0100, Martin Liška wrote: >> + use_operand_p use_p; >> + imm_use_iterator imm_iter; >> + FOR_EACH_IMM_USE_FAST (use_p, imm_iter, poisoned_var) >> + { >> + gimple *use = USE_STMT (use_p); >> + if (is_gimple_debug (use)) >> + continue; >> + >> + built_in_function b = (recover_p >> + ? BUILT_IN_ASAN_REPORT_USE_AFTER_SCOPE_NOABORT >> + : BUILT_IN_ASAN_REPORT_USE_AFTER_SCOPE); >> + tree fun = builtin_decl_implicit (b); >> + pretty_printer pp; >> + pp_tree_identifier (&pp, DECL_NAME (var_decl)); >> + >> + gcall *call = gimple_build_call (fun, 2, asan_pp_string (&pp), >> + DECL_SIZE_UNIT (var_decl)); >> + gimple_set_location (call, gimple_location (use)); >> + >> + /* The USE can be a gimple PHI node. If so, insert the call on >> + all edges leading to the PHI node. */ >> + if (is_a (use)) >> + { >> + gphi * phi = dyn_cast (use); > > No space after *. Done. > >> + for (unsigned i = 0; i < gimple_phi_num_args (phi); ++i) >> + if (gimple_phi_arg_def (phi, i) == poisoned_var) >> + { >> + edge e = gimple_phi_arg_edge (phi, i); >> + gsi_insert_seq_on_edge (e, call); >> + *need_commit_edge_insert = true; > > You clearly don't have a sufficient testsuite coverage for this, > because this won't really work if you have more than one phi > argument equal to poisoned_var. Inserting the same gimple stmt > into multiple places can't really work. I bet you want to set > call to NULL after the gsi_insert_seq_on_edge and before that > call if (call == NULL) { call = gimple_build_call (...); gimple_set_location (...); } > Or maybe gimple_copy for the 2nd etc. would work too, dunno. I see, fixed by using gimple_copy functionality. > >> + } >> + } >> + else >> + { >> + gimple_stmt_iterator gsi = gsi_for_stmt (use); >> + gsi_insert_before (&gsi, call, GSI_NEW_STMT); >> + } >> + } >> + >> + gimple *nop = gimple_build_nop (); >> + SSA_NAME_IS_DEFAULT_DEF (poisoned_var) = true; >> + SSA_NAME_DEF_STMT (poisoned_var) = nop; >> + gsi_replace (iter, nop, GSI_NEW_STMT); > > The last argument of gsi_replace is a bool, not GSI_*. > But not sure how this will work anyway, I think SSA_NAME_IS_DEFAULT_DEF > are supposed to have SSA_NAME_DEF_STMT a GIMPLE_NOP that doesn't > have bb set, while you are putting it into the stmt sequence. > Shouldn't you just gsi_remove iter instead? gsi_remove does not work as a SSA name would lost a defining statement. However setting SSA_NAME_DEF_STMT (poisoned_var) = gimple_build_nop () and removing the stmt works fine. I haven't known that it can't belong to a BB. Maybe we can add a verifier for that? That can be eventually done independently. > > Otherwise LGTM, but please post the asan patch to llvm-commits > or through their web review interface. Good, I'm going to insert the patch to the tool. Thanks, Martin > > Jakub > From da190584d091eaaa509067918de4f1f77e887484 Mon Sep 17 00:00:00 2001 From: marxin Date: Mon, 14 Nov 2016 16:49:05 +0100 Subject: [PATCH] use-after-scope: introduce ASAN_POISON internal fn gcc/ChangeLog: 2016-11-16 Martin Liska * asan.c (asan_expand_poison_ifn): New function. * asan.h (asan_expand_poison_ifn): Declare the function. * internal-fn.c (expand_ASAN_POISON): New function. * internal-fn.def (ASAN_POISON): New internal fn. * sanitizer.def (BUILT_IN_ASAN_REPORT_USE_AFTER_SCOPE_NOABORT): New built-in. (BUILT_IN_ASAN_REPORT_USE_AFTER_SCOPE): Likewise. * sanopt.c (pass_sanopt::execute): Expand IFN_ASAN_POISON. * tree-ssa.c (is_asan_mark_p): New function. (execute_update_addresses_taken): Make local variables as not addressable if address of these varibles is just taken by ASAN_MARK. gcc/testsuite/ChangeLog: 2016-11-16 Martin Liska * gcc.dg/asan/use-after-scope-3.c: Run just with -O0. * gcc.dg/asan/use-after-scope-9.c: Run just with -O2 and change expected output. --- gcc/asan.c | 77 ++++++++++++++++++++++++++- gcc/asan.h | 1 + gcc/internal-fn.c | 7 +++ gcc/internal-fn.def | 1 + gcc/sanitizer.def | 8 +++ gcc/sanopt.c | 9 ++++ gcc/testsuite/gcc.dg/asan/use-after-scope-3.c | 1 + gcc/testsuite/gcc.dg/asan/use-after-scope-9.c | 6 +-- gcc/tree-ssa.c | 71 ++++++++++++++++++++---- libsanitizer/asan/asan_errors.cc | 21 ++++++++ libsanitizer/asan/asan_errors.h | 19 +++++++ libsanitizer/asan/asan_report.cc | 10 ++++ libsanitizer/asan/asan_report.h | 3 ++ libsanitizer/asan/asan_rtl.cc | 16 ++++++ 14 files changed, 236 insertions(+), 14 deletions(-) diff --git a/gcc/asan.c b/gcc/asan.c index 6e93ea3..5bf8052 100644 --- a/gcc/asan.c +++ b/gcc/asan.c @@ -32,8 +32,8 @@ along with GCC; see the file COPYING3. If not see #include "tree-pass.h" #include "memmodel.h" #include "tm_p.h" +#include "ssa.h" #include "stringpool.h" -#include "tree-vrp.h" #include "tree-ssanames.h" #include "optabs.h" #include "emit-rtl.h" @@ -2979,6 +2979,81 @@ asan_expand_check_ifn (gimple_stmt_iterator *iter, bool use_calls) return true; } + +/* Expand the ASAN_POISON builtins. */ + +bool +asan_expand_poison_ifn (gimple_stmt_iterator *iter, + bool *need_commit_edge_insert) +{ + gimple *g = gsi_stmt (*iter); + tree poisoned_var = gimple_call_lhs (g); + if (!poisoned_var) + { + gsi_remove (iter, true); + return true; + } + + tree var_decl = SSA_NAME_VAR (poisoned_var); + + bool recover_p; + if (flag_sanitize & SANITIZE_USER_ADDRESS) + recover_p = (flag_sanitize_recover & SANITIZE_USER_ADDRESS) != 0; + else + recover_p = (flag_sanitize_recover & SANITIZE_KERNEL_ADDRESS) != 0; + + use_operand_p use_p; + imm_use_iterator imm_iter; + FOR_EACH_IMM_USE_FAST (use_p, imm_iter, poisoned_var) + { + gimple *use = USE_STMT (use_p); + if (is_gimple_debug (use)) + continue; + + built_in_function b = (recover_p + ? BUILT_IN_ASAN_REPORT_USE_AFTER_SCOPE_NOABORT + : BUILT_IN_ASAN_REPORT_USE_AFTER_SCOPE); + tree fun = builtin_decl_implicit (b); + pretty_printer pp; + pp_tree_identifier (&pp, DECL_NAME (var_decl)); + + gcall *call = gimple_build_call (fun, 2, asan_pp_string (&pp), + DECL_SIZE_UNIT (var_decl)); + gimple_set_location (call, gimple_location (use)); + gimple *call_to_insert = call; + + /* The USE can be a gimple PHI node. If so, insert the call on + all edges leading to the PHI node. */ + if (is_a (use)) + { + gphi *phi = dyn_cast (use); + for (unsigned i = 0; i < gimple_phi_num_args (phi); ++i) + if (gimple_phi_arg_def (phi, i) == poisoned_var) + { + edge e = gimple_phi_arg_edge (phi, i); + + if (call_to_insert == NULL) + call_to_insert = gimple_copy (call); + + gsi_insert_seq_on_edge (e, call_to_insert); + *need_commit_edge_insert = true; + call_to_insert = NULL; + } + } + else + { + gimple_stmt_iterator gsi = gsi_for_stmt (use); + gsi_insert_before (&gsi, call, GSI_NEW_STMT); + } + } + + SSA_NAME_IS_DEFAULT_DEF (poisoned_var) = true; + SSA_NAME_DEF_STMT (poisoned_var) = gimple_build_nop (); + gsi_remove (iter, true); + + return false; +} + /* Instrument the current function. */ static unsigned int diff --git a/gcc/asan.h b/gcc/asan.h index 9cf5904..6c25955 100644 --- a/gcc/asan.h +++ b/gcc/asan.h @@ -30,6 +30,7 @@ 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 bool asan_expand_poison_ifn (gimple_stmt_iterator *, bool *); extern gimple_stmt_iterator create_cond_insert_point (gimple_stmt_iterator *, bool, bool, bool, basic_block *, basic_block *); diff --git a/gcc/internal-fn.c b/gcc/internal-fn.c index ca347c5..17624e8 100644 --- a/gcc/internal-fn.c +++ b/gcc/internal-fn.c @@ -246,6 +246,13 @@ expand_ASAN_MARK (internal_fn, gcall *) gcc_unreachable (); } +/* This should get expanded in the sanopt pass. */ + +static void +expand_ASAN_POISON (internal_fn, gcall *) +{ + gcc_unreachable (); +} /* This should get expanded in the tsan pass. */ diff --git a/gcc/internal-fn.def b/gcc/internal-fn.def index d1cd1a5..9454afd 100644 --- a/gcc/internal-fn.def +++ b/gcc/internal-fn.def @@ -159,6 +159,7 @@ 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_LEAF | ECF_NOTHROW, ".R..") +DEF_INTERNAL_FN (ASAN_POISON, ECF_LEAF | ECF_NOTHROW | ECF_NOVOPS, NULL) 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/sanitizer.def b/gcc/sanitizer.def index 3db08a7..068c55b 100644 --- a/gcc/sanitizer.def +++ b/gcc/sanitizer.def @@ -102,6 +102,14 @@ DEF_SANITIZER_BUILTIN(BUILT_IN_ASAN_REPORT_STORE_N_NOABORT, "__asan_report_store_n_noabort", BT_FN_VOID_PTR_PTRMODE, ATTR_TMPURE_NOTHROW_LEAF_LIST) +DEF_SANITIZER_BUILTIN(BUILT_IN_ASAN_REPORT_USE_AFTER_SCOPE, + "__asan_report_use_after_scope", + BT_FN_VOID_PTR_PTRMODE, + ATTR_TMPURE_NOTHROW_LEAF_LIST) +DEF_SANITIZER_BUILTIN(BUILT_IN_ASAN_REPORT_USE_AFTER_SCOPE_NOABORT, + "__asan_report_use_after_scope_noabort", + BT_FN_VOID_PTR_PTRMODE, + ATTR_TMPURE_NOTHROW_LEAF_LIST) DEF_SANITIZER_BUILTIN(BUILT_IN_ASAN_LOAD1, "__asan_load1", BT_FN_VOID_PTR, ATTR_TMPURE_NOTHROW_LEAF_LIST) DEF_SANITIZER_BUILTIN(BUILT_IN_ASAN_LOAD2, "__asan_load2", diff --git a/gcc/sanopt.c b/gcc/sanopt.c index 320e14e..77307d9 100644 --- a/gcc/sanopt.c +++ b/gcc/sanopt.c @@ -698,6 +698,7 @@ pass_sanopt::execute (function *fun) bool use_calls = ASAN_INSTRUMENTATION_WITH_CALL_THRESHOLD < INT_MAX && asan_num_accesses >= ASAN_INSTRUMENTATION_WITH_CALL_THRESHOLD; + bool need_commit_edge_insert = false; FOR_EACH_BB_FN (bb, fun) { gimple_stmt_iterator gsi; @@ -735,6 +736,10 @@ pass_sanopt::execute (function *fun) case IFN_ASAN_MARK: no_next = asan_expand_mark_ifn (&gsi); break; + case IFN_ASAN_POISON: + no_next = asan_expand_poison_ifn (&gsi, + &need_commit_edge_insert); + break; default: break; } @@ -766,6 +771,10 @@ pass_sanopt::execute (function *fun) gsi_next (&gsi); } } + + if (need_commit_edge_insert) + gsi_commit_edge_inserts (); + return 0; } diff --git a/gcc/testsuite/gcc.dg/asan/use-after-scope-3.c b/gcc/testsuite/gcc.dg/asan/use-after-scope-3.c index 9aeed51..8b11bea 100644 --- a/gcc/testsuite/gcc.dg/asan/use-after-scope-3.c +++ b/gcc/testsuite/gcc.dg/asan/use-after-scope-3.c @@ -1,5 +1,6 @@ // { dg-do run } // { dg-shouldfail "asan" } +// { dg-additional-options "-O0" } int main (void) diff --git a/gcc/testsuite/gcc.dg/asan/use-after-scope-9.c b/gcc/testsuite/gcc.dg/asan/use-after-scope-9.c index 2e30def..10d7fb5 100644 --- a/gcc/testsuite/gcc.dg/asan/use-after-scope-9.c +++ b/gcc/testsuite/gcc.dg/asan/use-after-scope-9.c @@ -1,5 +1,6 @@ // { dg-do run } // { dg-shouldfail "asan" } +// { dg-additional-options "-O2" } int main (int argc, char **argv) @@ -15,6 +16,5 @@ main (int argc, char **argv) return *ptr; } -// { dg-output "ERROR: AddressSanitizer: stack-use-after-scope on address.*(\n|\r\n|\r)" } -// { dg-output "READ of size .*" } -// { dg-output ".*'a' <== Memory access at offset \[0-9\]* is inside this variable.*" } +// { dg-output "ERROR: AddressSanitizer: stack-use-after-scope at pc.*(\n|\r\n|\r)" } +// { dg-output "ACCESS of size .* for variable 'a'" } diff --git a/gcc/tree-ssa.c b/gcc/tree-ssa.c index 62eea8b..2d9c62d 100644 --- a/gcc/tree-ssa.c +++ b/gcc/tree-ssa.c @@ -41,6 +41,7 @@ along with GCC; see the file COPYING3. If not see #include "cfgexpand.h" #include "tree-cfg.h" #include "tree-dfa.h" +#include "asan.h" /* Pointer map of variable mappings, keyed by edge. */ static hash_map > *edge_var_maps; @@ -1550,6 +1551,30 @@ maybe_optimize_var (tree var, bitmap addresses_taken, bitmap not_reg_needs, } } +/* Return true when STMT is ASAN mark where second argument is an address + of a local variable. */ + +static bool +is_asan_mark_p (gimple *stmt) +{ + if (!gimple_call_internal_p (stmt, IFN_ASAN_MARK)) + return false; + + tree addr = get_base_address (gimple_call_arg (stmt, 1)); + if (TREE_CODE (addr) == ADDR_EXPR + && VAR_P (TREE_OPERAND (addr, 0))) + { + tree var = TREE_OPERAND (addr, 0); + unsigned addressable = TREE_ADDRESSABLE (var); + TREE_ADDRESSABLE (var) = 0; + bool r = is_gimple_reg (var); + TREE_ADDRESSABLE (var) = addressable; + return r; + } + + return false; +} + /* Compute TREE_ADDRESSABLE and DECL_GIMPLE_REG_P for local variables. */ void @@ -1575,17 +1600,23 @@ execute_update_addresses_taken (void) enum gimple_code code = gimple_code (stmt); tree decl; - if (code == GIMPLE_CALL - && optimize_atomic_compare_exchange_p (stmt)) + if (code == GIMPLE_CALL) { - /* For __atomic_compare_exchange_N if the second argument - is &var, don't mark var addressable; - if it becomes non-addressable, we'll rewrite it into - ATOMIC_COMPARE_EXCHANGE call. */ - tree arg = gimple_call_arg (stmt, 1); - gimple_call_set_arg (stmt, 1, null_pointer_node); - gimple_ior_addresses_taken (addresses_taken, stmt); - gimple_call_set_arg (stmt, 1, arg); + if (optimize_atomic_compare_exchange_p (stmt)) + { + /* For __atomic_compare_exchange_N if the second argument + is &var, don't mark var addressable; + if it becomes non-addressable, we'll rewrite it into + ATOMIC_COMPARE_EXCHANGE call. */ + tree arg = gimple_call_arg (stmt, 1); + gimple_call_set_arg (stmt, 1, null_pointer_node); + gimple_ior_addresses_taken (addresses_taken, stmt); + gimple_call_set_arg (stmt, 1, arg); + } + else if (is_asan_mark_p (stmt)) + ; + else + gimple_ior_addresses_taken (addresses_taken, stmt); } else /* Note all addresses taken by the stmt. */ @@ -1841,6 +1872,26 @@ execute_update_addresses_taken (void) continue; } } + else if (is_asan_mark_p (stmt)) + { + tree var = TREE_OPERAND (gimple_call_arg (stmt, 1), 0); + if (bitmap_bit_p (suitable_for_renaming, DECL_UID (var))) + { + HOST_WIDE_INT flags + = tree_to_shwi (gimple_call_arg (stmt, 0)); + unlink_stmt_vdef (stmt); + if (flags & ASAN_MARK_CLOBBER) + { + gcall *call + = gimple_build_call_internal (IFN_ASAN_POISON, 0); + gimple_call_set_lhs (call, var); + gsi_replace (&gsi, call, GSI_SAME_STMT); + } + else + gsi_remove (&gsi, true); + continue; + } + } for (i = 0; i < gimple_call_num_args (stmt); ++i) { tree *argp = gimple_call_arg_ptr (stmt, i); diff --git a/libsanitizer/asan/asan_errors.cc b/libsanitizer/asan/asan_errors.cc index 73c4cca..f17c9b7 100644 --- a/libsanitizer/asan/asan_errors.cc +++ b/libsanitizer/asan/asan_errors.cc @@ -279,6 +279,27 @@ void ErrorInvalidPointerPair::Print() { ReportErrorSummary(bug_type, &stack); } +void ErrorUseAfterScope::Print() { + const char *bug_type = "stack-use-after-scope"; + Decorator d; + Printf("%s", d.Warning()); + + Report("ERROR: AddressSanitizer: stack-use-after-scope at pc %p bp %p sp %p\n", + variable_name, variable_size, pc, bp, sp); + Printf("%s", d.EndWarning()); + scariness.Print(); + + char tname[128]; + Printf("ACCESS of size %zu for variable '%s' thread T%d%s%s\n", + variable_size, variable_name, tid, + ThreadNameWithParenthesis(tid, tname, sizeof(tname)), d.EndAccess()); + + GET_STACK_TRACE_FATAL(pc, bp); + stack.Print(); + ReportErrorSummary(bug_type, &stack); +} + + static bool AdjacentShadowValuesAreFullyPoisoned(u8 *s) { return s[-1] > 127 && s[1] > 127; } diff --git a/libsanitizer/asan/asan_errors.h b/libsanitizer/asan/asan_errors.h index 6262dcf..a843859 100644 --- a/libsanitizer/asan/asan_errors.h +++ b/libsanitizer/asan/asan_errors.h @@ -294,6 +294,24 @@ struct ErrorInvalidPointerPair : ErrorBase { void Print(); }; +struct ErrorUseAfterScope : ErrorBase { + uptr pc, bp, sp; + const char *variable_name; + uptr variable_size; + // VS2013 doesn't implement unrestricted unions, so we need a trivial default + // constructor + ErrorUseAfterScope() = default; + ErrorUseAfterScope(u32 tid, uptr pc_, uptr bp_, uptr sp_, + const char *variable_name_, uptr variable_size_) + : ErrorBase(tid), + pc(pc_), + bp(bp_), + sp(sp_), + variable_name(variable_name_), + variable_size(variable_size_) {} + void Print(); +}; + struct ErrorGeneric : ErrorBase { AddressDescription addr_description; uptr pc, bp, sp; @@ -324,6 +342,7 @@ struct ErrorGeneric : ErrorBase { macro(BadParamsToAnnotateContiguousContainer) \ macro(ODRViolation) \ macro(InvalidPointerPair) \ + macro(UseAfterScope) \ macro(Generic) // clang-format on diff --git a/libsanitizer/asan/asan_report.cc b/libsanitizer/asan/asan_report.cc index 84d6764..db39d42 100644 --- a/libsanitizer/asan/asan_report.cc +++ b/libsanitizer/asan/asan_report.cc @@ -353,6 +353,16 @@ static INLINE void CheckForInvalidPointerPair(void *p1, void *p2) { return ReportInvalidPointerPair(pc, bp, sp, a1, a2); } } +// ----------------------- ReportUseAfterScope ----------- {{{1 +void ReportUseAfterScope(const char *variable_name, uptr variable_size, + bool fatal) { + ScopedInErrorReport in_report (fatal); + GET_CALLER_PC_BP_SP; + ErrorUseAfterScope error(GetCurrentTidOrInvalid(), pc, bp, sp, variable_name, + variable_size); + in_report.ReportError(error); +} + // ----------------------- Mac-specific reports ----------------- {{{1 void ReportMacMzReallocUnknown(uptr addr, uptr zone_ptr, const char *zone_name, diff --git a/libsanitizer/asan/asan_report.h b/libsanitizer/asan/asan_report.h index 111b840..2fa158a 100644 --- a/libsanitizer/asan/asan_report.h +++ b/libsanitizer/asan/asan_report.h @@ -68,6 +68,9 @@ void ReportBadParamsToAnnotateContiguousContainer(uptr beg, uptr end, void ReportODRViolation(const __asan_global *g1, u32 stack_id1, const __asan_global *g2, u32 stack_id2); +void ReportUseAfterScope(const char *variable_name, uptr variable_size, + bool fatal); + // Mac-specific errors and warnings. void ReportMacMzReallocUnknown(uptr addr, uptr zone_ptr, const char *zone_name, diff --git a/libsanitizer/asan/asan_rtl.cc b/libsanitizer/asan/asan_rtl.cc index 38009d2..f637d71 100644 --- a/libsanitizer/asan/asan_rtl.cc +++ b/libsanitizer/asan/asan_rtl.cc @@ -253,6 +253,22 @@ void __asan_storeN_noabort(uptr addr, uptr size) { } } +#include + +extern "C" +NOINLINE INTERFACE_ATTRIBUTE +void __asan_report_use_after_scope(const char *variable_name, + uptr variable_size) { + ReportUseAfterScope(variable_name, variable_size, true); +} + +extern "C" +NOINLINE INTERFACE_ATTRIBUTE +void __asan_report_use_after_scope_noabort(const char *variable_name, + uptr variable_size) { + ReportUseAfterScope(variable_name, variable_size, false); +} + // Force the linker to keep the symbols for various ASan interface functions. // We want to keep those in the executable in order to let the instrumented // dynamic libraries access the symbol even if it is not used by the executable -- 2.10.2