From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 128768 invoked by alias); 6 Feb 2020 20:27:45 -0000 Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Received: (qmail 128644 invoked by uid 89); 6 Feb 2020 20:27:44 -0000 Authentication-Results: sourceware.org; auth=none X-Spam-SWARE-Status: No, score=-23.5 required=5.0 tests=AWL,BAYES_00,GIT_PATCH_0,GIT_PATCH_1,GIT_PATCH_2,GIT_PATCH_3,RCVD_IN_DNSWL_NONE,SPF_PASS autolearn=ham version=3.3.1 spammy= X-HELO: us-smtp-1.mimecast.com Received: from us-smtp-1.mimecast.com (HELO us-smtp-1.mimecast.com) (207.211.31.81) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Thu, 06 Feb 2020 20:27:42 +0000 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1581020860; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=e04xALTOlSDa+H7uk6Fs0gVTWKLkiVg0qO2Qs3eJzbc=; b=PTMwUsCyo8bmBa6mcvkiuo89XL0DMrzjmVDE7dboMC3SHh2z90AtH/x/364TCucJRP880e Il+Xn7898t7m84Vc6snkKjQ7fPBw/eWKqfc9R8HpRD6uVt8Eb5MxoK8rggRxvXIr8YI0JQ W1K+tOp4uFJqMU4ilPndBXDiqGhj9EE= Received: from mimecast-mx01.redhat.com (mimecast-mx01.redhat.com [209.132.183.4]) (Using TLS) by relay.mimecast.com with ESMTP id us-mta-5-JtV8VF67MryOyBwIFWuqPA-1; Thu, 06 Feb 2020 15:27:34 -0500 Received: from smtp.corp.redhat.com (int-mx03.intmail.prod.int.phx2.redhat.com [10.5.11.13]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx01.redhat.com (Postfix) with ESMTPS id C50A18010EF for ; Thu, 6 Feb 2020 20:27:33 +0000 (UTC) Received: from t470.redhat.com (ovpn-116-56.phx2.redhat.com [10.3.116.56]) by smtp.corp.redhat.com (Postfix) with ESMTP id 3106A87B00; Thu, 6 Feb 2020 20:27:33 +0000 (UTC) From: David Malcolm To: gcc-patches@gcc.gnu.org Cc: David Malcolm Subject: [PATCH 2/2] analyzer: use ultimate alias target at calls (PR 93288) Date: Thu, 06 Feb 2020 20:27:00 -0000 Message-Id: <20200206202730.18584-2-dmalcolm@redhat.com> In-Reply-To: <20200206202730.18584-1-dmalcolm@redhat.com> References: <20200206202730.18584-1-dmalcolm@redhat.com> MIME-Version: 1.0 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com Content-Type: text/plain; charset=US-ASCII Content-Transfer-Encoding: quoted-printable X-IsSubscribed: yes X-SW-Source: 2020-02/txt/msg00398.txt.bz2 PR analyzer/93288 reports an ICE in a C++ testcase when calling a constructor. The issue is that when building the supergraph, we encounter the cgraph edge to "__ct_comp ", the DECL_COMPLETE_CONSTRUCTOR_P, and this node's DECL_STRUCT_FUNCTION has a NULL CFG, which the analyzer reads through, leading to the ICE. This patch reworks function and fndecl lookup at calls throughout the analyzer so that it looks for the ultimate_alias_target of the callee. In the case above, this means using the "__ct_base " for the ctor, which has a CFG, fixing the ICE. Getting this right allows for some simple C++ cases involving ctors to work, so the patch also adds some test coverage for that. Successfully bootstrapped & regrtested on x86_64-pc-linux-gnu. gcc/analyzer/ChangeLog: PR analyzer/93288 * analysis-plan.cc (analysis_plan::use_summary_p): Look through the ultimate_alias_target when getting the called function. * engine.cc (exploded_node::on_stmt): Rename second "ctxt" to "sm_ctxt". Use the region_model's get_fndecl_for_call rather than gimple_call_fndecl. * region-model.cc (region_model::get_fndecl_for_call): Use ultimate_alias_target on fndecl. * supergraph.cc (get_ultimate_function_for_cgraph_edge): New function. (supergraph_call_edge): Use it when rejecting edges without functions. (supergraph::supergraph): Use it to get the function for the cgraph_edge when building interprocedural superedges. (callgraph_superedge::get_callee_function): Use it. * supergraph.h (supergraph::get_num_snodes): Make param const. (supergraph::function_to_num_snodes_t): Make first type param const. gcc/testsuite/ChangeLog: PR analyzer/93288 * g++.dg/analyzer/malloc.C: Add test coverage for a double-free called in a constructor. * g++.dg/analyzer/pr93288.C: New test. --- gcc/analyzer/analysis-plan.cc | 6 +++++- gcc/analyzer/engine.cc | 12 +++++------ gcc/analyzer/region-model.cc | 5 ++++- gcc/analyzer/supergraph.cc | 28 +++++++++++++++++++------ gcc/analyzer/supergraph.h | 4 ++-- gcc/testsuite/g++.dg/analyzer/malloc.C | 16 ++++++++++++++ gcc/testsuite/g++.dg/analyzer/pr93288.C | 8 +++++++ 7 files changed, 63 insertions(+), 16 deletions(-) create mode 100644 gcc/testsuite/g++.dg/analyzer/pr93288.C diff --git a/gcc/analyzer/analysis-plan.cc b/gcc/analyzer/analysis-plan.cc index 8ad2fa2ebb4..3c8b10b3314 100644 --- a/gcc/analyzer/analysis-plan.cc +++ b/gcc/analyzer/analysis-plan.cc @@ -120,7 +120,11 @@ analysis_plan::use_summary_p (const cgraph_edge *edge)= const =20 /* Require the callee to be sufficiently complex to be worth summarizing. */ - if ((int)m_sg.get_num_snodes (callee->get_fun ()) + const function *fun + =3D const_cast (callee)->ultimate_alias_target ()->get= _fun (); + /* TODO(stage1): can ultimate_alias_target be made const? */ + + if ((int)m_sg.get_num_snodes (fun) < param_analyzer_min_snodes_for_call_summary) return false; =20 diff --git a/gcc/analyzer/engine.cc b/gcc/analyzer/engine.cc index 63579da953a..c4d7088d3e9 100644 --- a/gcc/analyzer/engine.cc +++ b/gcc/analyzer/engine.cc @@ -1044,19 +1044,19 @@ exploded_node::on_stmt (exploded_graph &eg, const sm_state_map *old_smap =3D old_state.m_checker_states[sm_idx]; sm_state_map *new_smap =3D state->m_checker_states[sm_idx]; - impl_sm_context ctxt (eg, sm_idx, sm, this, &old_state, state, - change, - old_smap, new_smap); + impl_sm_context sm_ctxt (eg, sm_idx, sm, this, &old_state, state, + change, + old_smap, new_smap); /* Allow the state_machine to handle the stmt. */ - if (sm.on_stmt (&ctxt, snode, stmt)) + if (sm.on_stmt (&sm_ctxt, snode, stmt)) unknown_side_effects =3D false; else { /* For those stmts that were not handled by the state machine. */ if (const gcall *call =3D dyn_cast (stmt)) { - tree callee_fndecl =3D gimple_call_fndecl (call); - // TODO: maybe we can be smarter about handling function pointers? + tree callee_fndecl + =3D state->m_region_model->get_fndecl_for_call (call, &ctxt); =20 if (!fndecl_has_gimple_body_p (callee_fndecl)) new_smap->purge_for_unknown_fncall (eg, sm, call, callee_fndecl, diff --git a/gcc/analyzer/region-model.cc b/gcc/analyzer/region-model.cc index 61390aa4cd1..0ae7536a032 100644 --- a/gcc/analyzer/region-model.cc +++ b/gcc/analyzer/region-model.cc @@ -6665,7 +6665,10 @@ region_model::get_fndecl_for_call (const gcall *call, if (code) { tree fn_decl =3D code->get_tree_for_child_region (fn_rid); - return fn_decl; + const cgraph_node *ultimate_node + =3D cgraph_node::get (fn_decl)->ultimate_alias_target (); + if (ultimate_node) + return ultimate_node->decl; } } =20 diff --git a/gcc/analyzer/supergraph.cc b/gcc/analyzer/supergraph.cc index b20daa081d2..fb4dbdfd8b9 100644 --- a/gcc/analyzer/supergraph.cc +++ b/gcc/analyzer/supergraph.cc @@ -56,6 +56,18 @@ along with GCC; see the file COPYING3. If not see =20 namespace ana { =20 +/* Get the function of the ultimate alias target being called at EDGE, + if any. */ + +static function * +get_ultimate_function_for_cgraph_edge (cgraph_edge *edge) +{ + cgraph_node *ultimate_node =3D edge->callee->ultimate_alias_target (); + if (!ultimate_node) + return NULL; + return ultimate_node->get_fun (); +} + /* Get the cgraph_edge, but only if there's an underlying function body. = */ =20 cgraph_edge * @@ -69,7 +81,7 @@ supergraph_call_edge (function *fun, gimple *stmt) return NULL; if (!edge->callee) return NULL; /* e.g. for a function pointer. */ - if (!edge->callee->get_fun ()) + if (!get_ultimate_function_for_cgraph_edge (edge)) return NULL; return edge; } @@ -178,8 +190,10 @@ supergraph::supergraph (logger *logger) { cgraph_edge *edge =3D (*iter).first; supernode *caller_prev_supernode =3D (*iter).second; - basic_block callee_cfg_block - =3D ENTRY_BLOCK_PTR_FOR_FN (edge->callee->get_fun ()); + function* callee_fn =3D get_ultimate_function_for_cgraph_edge (edge); + if (!callee_fn || !callee_fn->cfg) + continue; + basic_block callee_cfg_block =3D ENTRY_BLOCK_PTR_FOR_FN (callee_fn); supernode *callee_supernode =3D *m_bb_to_initial_node.get (callee_cfg_block); call_superedge *sedge @@ -199,8 +213,10 @@ supergraph::supergraph (logger *logger) { cgraph_edge *edge =3D (*iter).first; supernode *caller_next_supernode =3D (*iter).second; - basic_block callee_cfg_block - =3D EXIT_BLOCK_PTR_FOR_FN (edge->callee->get_fun ()); + function* callee_fn =3D get_ultimate_function_for_cgraph_edge (edge); + if (!callee_fn || !callee_fn->cfg) + continue; + basic_block callee_cfg_block =3D EXIT_BLOCK_PTR_FOR_FN (callee_fn); supernode *callee_supernode =3D *m_bb_to_initial_node.get (callee_cfg_block); return_superedge *sedge @@ -840,7 +856,7 @@ callgraph_superedge::dump_label_to_pp (pretty_printer *= pp, function * callgraph_superedge::get_callee_function () const { - return m_cedge->callee->get_fun (); + return get_ultimate_function_for_cgraph_edge (m_cedge); } =20 /* Get the calling function at this interprocedural call/return edge. */ diff --git a/gcc/analyzer/supergraph.h b/gcc/analyzer/supergraph.h index 0eac0b8bfc9..2c94f0544ce 100644 --- a/gcc/analyzer/supergraph.h +++ b/gcc/analyzer/supergraph.h @@ -156,7 +156,7 @@ public: return m_nodes[idx]; } =20 - unsigned get_num_snodes (function *fun) const + unsigned get_num_snodes (const function *fun) const { function_to_num_snodes_t &map =3D const_cast (m_function_to_num_snodes= ); @@ -201,7 +201,7 @@ private: typedef ordered_hash_map stmt_to_node_t; stmt_to_node_t m_stmt_to_node_t; =20 - typedef hash_map function_to_num_snodes_t; + typedef hash_map function_to_num_snodes_t; function_to_num_snodes_t m_function_to_num_snodes; }; =20 diff --git a/gcc/testsuite/g++.dg/analyzer/malloc.C b/gcc/testsuite/g++.dg/= analyzer/malloc.C index 0637295e1f2..76baab98222 100644 --- a/gcc/testsuite/g++.dg/analyzer/malloc.C +++ b/gcc/testsuite/g++.dg/analyzer/malloc.C @@ -7,3 +7,19 @@ void test_1 (void *ptr) free (ptr); free (ptr); /* { dg-warning "double-'free' of 'ptr'" } */ } + +/* Test of double-free in ctor. */ + +struct s2 +{ + s2 (void *v) + { + free (v); // { dg-warning "double-'free' of 'v'" } + } +}; + +void test_2 (void *ptr) +{ + free (ptr); // { dg-message "first 'free' here" } + s2 a (ptr); // { dg-message "passing freed pointer 'ptr' in call to 's2:= :s2' from 'test_2'" } +} diff --git a/gcc/testsuite/g++.dg/analyzer/pr93288.C b/gcc/testsuite/g++.dg= /analyzer/pr93288.C new file mode 100644 index 00000000000..1798fed805f --- /dev/null +++ b/gcc/testsuite/g++.dg/analyzer/pr93288.C @@ -0,0 +1,8 @@ +// { dg-do compile } + +struct a { + a(); +}; +class foo { + a b; +} c; --=20 2.21.0