From patchwork Wed Oct 8 19:10:05 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ilya Enkovich X-Patchwork-Id: 397696 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 001251400D6 for ; Thu, 9 Oct 2014 06:10:22 +1100 (EST) DomainKey-Signature: a=rsa-sha1; c=nofws; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender:date :from:to:cc:subject:message-id:mime-version:content-type; q=dns; s=default; b=UGHsAYPYjx/sfjXbQ78XY2zNOXUeLe/VrKW2DJYjrTOpM5mE0K plef4Uju0TP7eheGV16n4dnXseq6mMDQKGvmNw8bWw07Z0Zt15TZ4Ou3pY6gA8BJ oEGViNKQYFmrDXLu14iGbbYJFs04UFq7++gmm2fcycZ+RauksIlXkJdIk= 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:date :from:to:cc:subject:message-id:mime-version:content-type; s= default; bh=vJfdEY8wacIhFgaot2lwDuOQriA=; b=HtSNfHVf6j/kMvs24rfC JICpKqbJIOYJNCAI9GMudDE5kLXPpHoteHQhBV62jLPvKGAgc59XO7EZoDW1o6Ng JYsxpNltA+dbCVWrO6jPz3CHJFpsqezMD831hxTJz8s0eO5SSAR51QWH0lr6Y2rv 3bsYrbxP3sDO+Wr4V20kH7E= Received: (qmail 8432 invoked by alias); 8 Oct 2014 19:10:15 -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 8412 invoked by uid 89); 8 Oct 2014 19:10:15 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-1.8 required=5.0 tests=AWL, BAYES_00, FREEMAIL_FROM, RCVD_IN_DNSWL_LOW, SPF_PASS autolearn=ham version=3.3.2 X-HELO: mail-pa0-f47.google.com Received: from mail-pa0-f47.google.com (HELO mail-pa0-f47.google.com) (209.85.220.47) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with (AES128-SHA encrypted) ESMTPS; Wed, 08 Oct 2014 19:10:13 +0000 Received: by mail-pa0-f47.google.com with SMTP id rd3so9612574pab.34 for ; Wed, 08 Oct 2014 12:10:11 -0700 (PDT) X-Received: by 10.70.88.78 with SMTP id be14mr6309763pdb.152.1412795411842; Wed, 08 Oct 2014 12:10:11 -0700 (PDT) Received: from msticlxl57.ims.intel.com (fmdmzpr03-ext.fm.intel.com. [192.55.54.38]) by mx.google.com with ESMTPSA id w4sm661745pdr.72.2014.10.08.12.10.09 for (version=TLSv1 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Wed, 08 Oct 2014 12:10:11 -0700 (PDT) Date: Wed, 8 Oct 2014 23:10:05 +0400 From: Ilya Enkovich To: gcc-patches@gcc.gnu.org Cc: Jeff Law Subject: [PATCH, Pointer Bounds Checker 14/x] Passes [9/n] Static constructors Message-ID: <20141008191005.GI13454@msticlxl57.ims.intel.com> MIME-Version: 1.0 Content-Disposition: inline User-Agent: Mutt/1.5.21 (2010-09-15) X-IsSubscribed: yes Hi, This patch introduces functions to handle static pointers and static bounds. Thanks, Ilya --- 2014-10-08 Ilya Enkovich * tree-chkp.c (MAX_STMTS_IN_STATIC_CHKP_CTOR): New. (chkp_ctor_stmt_list): New. (chkp_register_var_initializer): New. (chkp_add_modification_to_stmt_list): New. (chkp_output_static_bounds): New. (chkp_finish_file): New. (chkp_instrument_function): Remove useless statements from static bounds constructors. * tree-chkp.h (chkp_register_var_initializer): New. (chkp_finish_file): New. diff --git a/gcc/tree-chkp.c b/gcc/tree-chkp.c index b424af8..4b5a773 100644 --- a/gcc/tree-chkp.c +++ b/gcc/tree-chkp.c @@ -394,6 +394,27 @@ static bool in_chkp_pass; #define CHKP_ZERO_BOUNDS_VAR_NAME "__chkp_zero_bounds" #define CHKP_NONE_BOUNDS_VAR_NAME "__chkp_none_bounds" +/* Static checker constructors may become very large and their + compilation with optimization may take too much time. + Therefore we put a limit to number of statements in one + construcor. Tests with 100 000 statically initialized + pointers showed following compilation times on Sandy Bridge + server (used -O2): + limit 100 => ~18 sec. + limit 300 => ~22 sec. + limit 1000 => ~30 sec. + limit 3000 => ~49 sec. + limit 5000 => ~55 sec. + limit 10000 => ~76 sec. + limit 100000 => ~532 sec. */ +#define MAX_STMTS_IN_STATIC_CHKP_CTOR (optimize > 0 ? 5000 : 100000) + +struct chkp_ctor_stmt_list +{ + tree stmts; + int avail; +}; + /* Return 1 if function FNDECL is instrumented by Pointer Bounds Checker. */ bool @@ -871,6 +892,53 @@ chkp_set_bounds (tree node, tree val) chkp_bounds_map->put (node, val); } +/* Check if statically initialized variable VAR require + static bounds initilization. If VAR is added into + bounds initlization list then 1 is returned. Otherwise + return 0. */ +extern bool +chkp_register_var_initializer (tree var) +{ + if (!flag_check_pointer_bounds) + return false; + + gcc_assert (TREE_CODE (var) == VAR_DECL); + gcc_assert (DECL_INITIAL (var) + && DECL_INITIAL (var) != error_mark_node); + + if (TREE_STATIC (var) + && chkp_type_has_pointer (TREE_TYPE (var))) + { + varpool_node::get_create (var)->need_bounds_init = 1; + return true; + } + + return false; +} + +/* Helper function for chkp_finish_file. + + Add new modification statement (RHS is assigned to LHS) + into list of static initilizer statementes (passed in ARG). + If statements list becomes too big, emit checker constructor + and start the new one. */ +static void +chkp_add_modification_to_stmt_list (tree lhs, + tree rhs, + void *arg) +{ + struct chkp_ctor_stmt_list *stmts = (struct chkp_ctor_stmt_list *)arg; + tree modify; + + if (!useless_type_conversion_p (TREE_TYPE (lhs), TREE_TYPE (rhs))) + rhs = build1 (CONVERT_EXPR, TREE_TYPE (lhs), rhs); + + modify = build2 (MODIFY_EXPR, TREE_TYPE (lhs), lhs, rhs); + append_to_statement_list (modify, &stmts->stmts); + + stmts->avail--; +} + /* Build and return ADDR_EXPR for specified object OBJ. */ static tree chkp_build_addr_expr (tree obj) @@ -880,6 +948,64 @@ chkp_build_addr_expr (tree obj) : build_fold_addr_expr (obj); } +/* Helper function for chkp_finish_file. + Initialize bound variable BND_VAR with bounds of variable + VAR to statements list STMTS. If statements list becomes + too big, emit checker constructor and start the new one. */ +static void +chkp_output_static_bounds (tree bnd_var, tree var, + struct chkp_ctor_stmt_list *stmts) +{ + tree lb, ub, size; + + if (TREE_CODE (var) == STRING_CST) + { + lb = build1 (CONVERT_EXPR, size_type_node, chkp_build_addr_expr (var)); + size = build_int_cst (size_type_node, TREE_STRING_LENGTH (var) - 1); + } + else if (DECL_SIZE (var) + && !chkp_variable_size_type (TREE_TYPE (var))) + { + /* Compute bounds using statically known size. */ + lb = build1 (CONVERT_EXPR, size_type_node, chkp_build_addr_expr (var)); + size = size_binop (MINUS_EXPR, DECL_SIZE_UNIT (var), size_one_node); + } + else + { + /* Compute bounds using dynamic size. */ + tree call; + + lb = build1 (CONVERT_EXPR, size_type_node, chkp_build_addr_expr (var)); + call = build1 (ADDR_EXPR, + build_pointer_type (TREE_TYPE (chkp_sizeof_fndecl)), + chkp_sizeof_fndecl); + size = build_call_nary (TREE_TYPE (TREE_TYPE (chkp_sizeof_fndecl)), + call, 1, var); + + if (flag_chkp_zero_dynamic_size_as_infinite) + { + tree max_size, cond; + + max_size = build2 (MINUS_EXPR, size_type_node, size_zero_node, lb); + cond = build2 (NE_EXPR, boolean_type_node, size, size_zero_node); + size = build3 (COND_EXPR, size_type_node, cond, size, max_size); + } + + size = size_binop (MINUS_EXPR, size, size_one_node); + } + + ub = size_binop (PLUS_EXPR, lb, size); + stmts->avail -= targetm.chkp_initialize_bounds (bnd_var, lb, ub, + &stmts->stmts); + if (stmts->avail <= 0) + { + cgraph_build_static_cdtor ('B', stmts->stmts, + MAX_RESERVED_INIT_PRIORITY + 2); + stmts->avail = MAX_STMTS_IN_STATIC_CHKP_CTOR; + stmts->stmts = NULL; + } +} + /* Return entry block to be used for checker initilization code. Create new block if required. */ static basic_block @@ -3402,6 +3528,74 @@ chkp_copy_bounds_for_elem (tree lhs, tree rhs, void *arg) chkp_build_bndstx (addr, rhs, bounds, iter); } +/* Emit static bound initilizers and size vars. */ +void +chkp_finish_file (void) +{ + struct varpool_node *node; + struct chkp_ctor_stmt_list stmts; + + if (seen_error ()) + return; + + /* Iterate through varpool and generate bounds initialization + constructors for all statically initialized pointers. */ + stmts.avail = MAX_STMTS_IN_STATIC_CHKP_CTOR; + stmts.stmts = NULL; + FOR_EACH_VARIABLE (node) + /* Check that var is actually emitted and we need and may initialize + its bounds. */ + if (node->need_bounds_init + && !POINTER_BOUNDS_P (node->decl) + && DECL_RTL (node->decl) + && MEM_P (DECL_RTL (node->decl)) + && TREE_ASM_WRITTEN (node->decl)) + { + chkp_walk_pointer_assignments (node->decl, + DECL_INITIAL (node->decl), + &stmts, + chkp_add_modification_to_stmt_list); + + if (stmts.avail <= 0) + { + cgraph_build_static_cdtor ('P', stmts.stmts, + MAX_RESERVED_INIT_PRIORITY + 3); + stmts.avail = MAX_STMTS_IN_STATIC_CHKP_CTOR; + stmts.stmts = NULL; + } + } + + if (stmts.stmts) + cgraph_build_static_cdtor ('P', stmts.stmts, + MAX_RESERVED_INIT_PRIORITY + 3); + + /* Iterate through varpool and generate bounds initialization + constructors for all static bounds vars. */ + stmts.avail = MAX_STMTS_IN_STATIC_CHKP_CTOR; + stmts.stmts = NULL; + FOR_EACH_VARIABLE (node) + if (node->need_bounds_init + && POINTER_BOUNDS_P (node->decl) + && TREE_ASM_WRITTEN (node->decl)) + { + tree bnd = node->decl; + tree var; + + gcc_assert (DECL_INITIAL (bnd) + && TREE_CODE (DECL_INITIAL (bnd)) == ADDR_EXPR); + + var = TREE_OPERAND (DECL_INITIAL (bnd), 0); + chkp_output_static_bounds (bnd, var, &stmts); + } + + if (stmts.stmts) + cgraph_build_static_cdtor ('B', stmts.stmts, + MAX_RESERVED_INIT_PRIORITY + 2); + + delete chkp_static_var_bounds; + delete chkp_bounds_map; +} + /* An instrumentation function which is called for each statement having memory access we want to instrument. It inserts check code and bounds copy code. @@ -3689,7 +3883,9 @@ chkp_replace_function_pointers (gimple_stmt_iterator *gsi) } /* This function instruments all statements working with memory, - calls and rets. */ + calls and rets. + + It also removes excess statements from static initializers. */ static void chkp_instrument_function (void) { @@ -3754,6 +3950,18 @@ chkp_instrument_function (void) } gsi_next (&i); + + /* We do not need any actual pointer stores in checker + static initializer. */ + if (lookup_attribute ("chkp ctor", DECL_ATTRIBUTES (cfun->decl)) + && gimple_code (s) == GIMPLE_ASSIGN + && gimple_store_p (s)) + { + gimple_stmt_iterator del_iter = gsi_for_stmt (s); + gsi_remove (&del_iter, true); + unlink_stmt_vdef (s); + release_defs(s); + } } bb = next; } diff --git a/gcc/tree-chkp.h b/gcc/tree-chkp.h index 0357658..81306ba 100644 --- a/gcc/tree-chkp.h +++ b/gcc/tree-chkp.h @@ -30,6 +30,8 @@ along with GCC; see the file COPYING3. If not see extern tree chkp_get_bounds (tree node); extern void chkp_set_bounds (tree node, tree val); +extern bool chkp_register_var_initializer (tree var); +extern void chkp_finish_file (void); extern bool chkp_type_has_pointer (const_tree type); extern unsigned chkp_type_bounds_count (const_tree type); extern tree chkp_make_bounds_for_struct_addr (tree ptr);