From patchwork Thu Sep 7 22:49:35 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: David Malcolm X-Patchwork-Id: 137690 Return-Path: Delivered-To: ouuuleilei@gmail.com Received: by 2002:a59:ab0a:0:b0:3f2:4152:657d with SMTP id m10csp196231vqo; Thu, 7 Sep 2023 15:51:24 -0700 (PDT) X-Google-Smtp-Source: AGHT+IGip3hlc3aUtDJQXr08VYygJmPTkXBAlcU2RYDtQ7IFfcc5+YpmQ6288lQzRFZmTYP6xh/O X-Received: by 2002:a17:906:3113:b0:9a1:e395:2d10 with SMTP id 19-20020a170906311300b009a1e3952d10mr478448ejx.75.1694127083906; Thu, 07 Sep 2023 15:51:23 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1694127083; cv=none; d=google.com; s=arc-20160816; b=Q8nFAbG3sTGfANVzRT/3bdcDDubK8HAfQUE/FGX75pN668geXZ0sL790p+DW7/3QGI FrY0Iwegh6X9fUfrDK9xtUbfBq3UQthvKLwQTXNeDClCcTxICoD24Thq0pogWq2x0epf AeSfbyX7wDDWQI9cv/dP77gEGRgN8eVVE7b40h5nALdUaP7jBLWh+ZJFAijMV4WZZd5K LgGtIDiSv00ifgV0+lhGR8jibTI5TViwQcZprQDnH37W2vRoFOaf5WqirqAAA6dL3beu JNhomtiLCV9QsL+lorVYJoug3i2E1Rhog6UuQkxyxlybp1iKfZalnJ+LqPX6RlzMUNHi LlCA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=sender:errors-to:reply-to:from:list-subscribe:list-help:list-post :list-archive:list-unsubscribe:list-id:precedence :content-transfer-encoding:mime-version:message-id:date:subject:to :dmarc-filter:delivered-to:dkim-signature:dkim-filter; bh=CMZmeVaUFSS7G6z/jvK3qvI6LngoqRI50njvjRBeF+w=; fh=hPrbWPhweUx4V0GV9uXJqbyAzg2ABmTz7kczrAQqMmM=; b=T0iBEYr9SdvD1goSZGhbaYK8sA3xLr0SKqsu5AXBEnqN8AHuyzf0vezUPeetPqTRvE G4qrTgW1AKgsX1M59xR4UzmvR1272ZDJNyCl8g+en7gEt/YQeREkpcTF1BHjYp4B7HKF HxyO3FUSatyqF0pl6CTK7IIn65mRKJE/2iAvfwXhrGz2J8w6uGQbGuWMUg5OO18VdOtR FNJpm4ISzYm4007LcGVJ6yLJddTKtQnjaw0Fz9F/6guQltEI2dBrUj4/eEFK2BE8ynlA sWnf0VPflRxk6pyJnl7u2hyC6Q0+g2YwifE5aHNrAMoXs6stjSeFbl0+sP9PJUSDIs5g hN2Q== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@gcc.gnu.org header.s=default header.b=Wqbu7cWY; spf=pass (google.com: domain of gcc-patches-bounces+ouuuleilei=gmail.com@gcc.gnu.org designates 2620:52:3:1:0:246e:9693:128c as permitted sender) smtp.mailfrom="gcc-patches-bounces+ouuuleilei=gmail.com@gcc.gnu.org"; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=gnu.org Received: from server2.sourceware.org (server2.sourceware.org. [2620:52:3:1:0:246e:9693:128c]) by mx.google.com with ESMTPS id y5-20020a1709064b0500b009a1f53509adsi232905eju.27.2023.09.07.15.51.23 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 07 Sep 2023 15:51:23 -0700 (PDT) Received-SPF: pass (google.com: domain of gcc-patches-bounces+ouuuleilei=gmail.com@gcc.gnu.org designates 2620:52:3:1:0:246e:9693:128c as permitted sender) client-ip=2620:52:3:1:0:246e:9693:128c; Authentication-Results: mx.google.com; dkim=pass header.i=@gcc.gnu.org header.s=default header.b=Wqbu7cWY; spf=pass (google.com: domain of gcc-patches-bounces+ouuuleilei=gmail.com@gcc.gnu.org designates 2620:52:3:1:0:246e:9693:128c as permitted sender) smtp.mailfrom="gcc-patches-bounces+ouuuleilei=gmail.com@gcc.gnu.org"; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=gnu.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 9643D3858D35 for ; Thu, 7 Sep 2023 22:51:22 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 9643D3858D35 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gcc.gnu.org; s=default; t=1694127082; bh=CMZmeVaUFSS7G6z/jvK3qvI6LngoqRI50njvjRBeF+w=; h=To:Subject:Date:List-Id:List-Unsubscribe:List-Archive:List-Post: List-Help:List-Subscribe:From:Reply-To:From; b=Wqbu7cWYvtKPoEw1PfJlPFM2JS/DV9g/2DXUuPqwpMtDRfoi3PVV8k7wJQUITNz5K LDjS8V/aD7Lcry3cFWi1mp8PvlWWCWwG0gTdlArHLXd/wf6+XO4dlAqZRR8f4p4hjQ wDGuTOv1hF31zg7VMFeDCpECudyGymhODeik+nIg= X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) by sourceware.org (Postfix) with ESMTPS id 435913858D38 for ; Thu, 7 Sep 2023 22:49:38 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 435913858D38 Received: from mimecast-mx02.redhat.com (mx-ext.redhat.com [66.187.233.73]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id us-mta-618-HmP2Ok6GPzG__8ld3nr1cw-1; Thu, 07 Sep 2023 18:49:36 -0400 X-MC-Unique: HmP2Ok6GPzG__8ld3nr1cw-1 Received: from smtp.corp.redhat.com (int-mx06.intmail.prod.int.rdu2.redhat.com [10.11.54.6]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id 5D4E529ABA26 for ; Thu, 7 Sep 2023 22:49:36 +0000 (UTC) Received: from t14s.localdomain.com (unknown [10.22.34.57]) by smtp.corp.redhat.com (Postfix) with ESMTP id 19F0421EE566; Thu, 7 Sep 2023 22:49:36 +0000 (UTC) To: gcc-patches@gcc.gnu.org Subject: [pushed] analyzer: basic support for computed gotos (PR analyzer/110529) Date: Thu, 7 Sep 2023 18:49:35 -0400 Message-Id: <20230907224935.883935-1-dmalcolm@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.1 on 10.11.54.6 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com X-Spam-Status: No, score=-11.7 required=5.0 tests=BAYES_00, DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, RCVD_IN_DNSWL_NONE, RCVD_IN_MSPIKE_H3, RCVD_IN_MSPIKE_WL, SPF_HELO_NONE, SPF_NONE, TXREP autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org X-BeenThere: gcc-patches@gcc.gnu.org X-Mailman-Version: 2.1.30 Precedence: list List-Id: Gcc-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-Patchwork-Original-From: David Malcolm via Gcc-patches From: David Malcolm Reply-To: David Malcolm Errors-To: gcc-patches-bounces+ouuuleilei=gmail.com@gcc.gnu.org Sender: "Gcc-patches" X-getmail-retrieved-from-mailbox: INBOX X-GMAIL-THRID: 1776421001122255344 X-GMAIL-MSGID: 1776421001122255344 PR analyzer/110529 notes that -fanalyzer was giving up on execution paths that follow a computed goto, due to ignoring CFG edges with the flag EDGE_ABNORMAL set. This patch implements enough handling for them to allow analysis of such execution paths to continue. Successfully bootstrapped & regrtested on x86_64-pc-linux-gnu. Pushed to trunk as r14-3796-g1b761fede44afa. gcc/analyzer/ChangeLog: PR analyzer/110529 * program-point.cc (program_point::on_edge): Don't reject EDGE_ABNORMAL for computed gotos. * region-model.cc (region_model::maybe_update_for_edge): Handle computed goto statements. (region_model::apply_constraints_for_ggoto): New. * region-model.h (region_model::apply_constraints_for_ggoto): New decl. * supergraph.cc (supernode::get_label): New. * supergraph.h (supernode::get_label): New decl. gcc/testsuite/ChangeLog: PR analyzer/110529 * c-c++-common/analyzer/computed-goto-1.c: New test. * gcc.dg/analyzer/computed-goto-pr110529.c: New test. --- gcc/analyzer/program-point.cc | 17 +++++- gcc/analyzer/region-model.cc | 39 +++++++++++- gcc/analyzer/region-model.h | 3 + gcc/analyzer/supergraph.cc | 13 ++++ gcc/analyzer/supergraph.h | 2 + .../c-c++-common/analyzer/computed-goto-1.c | 60 +++++++++++++++++++ .../gcc.dg/analyzer/computed-goto-pr110529.c | 27 +++++++++ 7 files changed, 158 insertions(+), 3 deletions(-) create mode 100644 gcc/testsuite/c-c++-common/analyzer/computed-goto-1.c create mode 100644 gcc/testsuite/gcc.dg/analyzer/computed-goto-pr110529.c diff --git a/gcc/analyzer/program-point.cc b/gcc/analyzer/program-point.cc index f2d6490f0c04..d7db2f522394 100644 --- a/gcc/analyzer/program-point.cc +++ b/gcc/analyzer/program-point.cc @@ -426,9 +426,22 @@ program_point::on_edge (exploded_graph &eg, { const cfg_superedge *cfg_sedge = as_a (succ); - /* Reject abnormal edges; we special-case setjmp/longjmp. */ if (cfg_sedge->get_flags () & EDGE_ABNORMAL) - return false; + { + const supernode *src_snode = cfg_sedge->m_src; + if (gimple *last_stmt = src_snode->get_last_stmt ()) + if (last_stmt->code == GIMPLE_GOTO) + { + /* For the program_point aspect here, consider all + out-edges from goto stmts to be valid; we'll + consider state separately. */ + return true; + } + + /* Reject other kinds of abnormal edges; + we special-case setjmp/longjmp. */ + return false; + } } break; diff --git a/gcc/analyzer/region-model.cc b/gcc/analyzer/region-model.cc index 999480e55ef7..a351e5cd214b 100644 --- a/gcc/analyzer/region-model.cc +++ b/gcc/analyzer/region-model.cc @@ -4997,7 +4997,7 @@ region_model::maybe_update_for_edge (const superedge &edge, if (last_stmt == NULL) return true; - /* Apply any constraints for conditionals/switch statements. */ + /* Apply any constraints for conditionals/switch/computed-goto statements. */ if (const gcond *cond_stmt = dyn_cast (last_stmt)) { @@ -5013,6 +5013,12 @@ region_model::maybe_update_for_edge (const superedge &edge, ctxt, out); } + if (const ggoto *goto_stmt = dyn_cast (last_stmt)) + { + const cfg_superedge *cfg_sedge = as_a (&edge); + return apply_constraints_for_ggoto (*cfg_sedge, goto_stmt, ctxt); + } + /* Apply any constraints due to an exception being thrown. */ if (const cfg_superedge *cfg_sedge = dyn_cast (&edge)) if (cfg_sedge->get_flags () & EDGE_EH) @@ -5267,6 +5273,37 @@ region_model::apply_constraints_for_gswitch (const switch_cfg_superedge &edge, return sat; } +/* Given an edge reached by GOTO_STMT, determine appropriate constraints + for the edge to be taken. + + If they are feasible, add the constraints and return true. + + Return false if the constraints contradict existing knowledge + (and so the edge should not be taken). */ + +bool +region_model::apply_constraints_for_ggoto (const cfg_superedge &edge, + const ggoto *goto_stmt, + region_model_context *ctxt) +{ + tree dest = gimple_goto_dest (goto_stmt); + const svalue *dest_sval = get_rvalue (dest, ctxt); + + /* If we know we were jumping to a specific label. */ + if (tree dst_label = edge.m_dest->get_label ()) + { + const label_region *dst_label_reg + = m_mgr->get_region_for_label (dst_label); + const svalue *dst_label_ptr + = m_mgr->get_ptr_svalue (ptr_type_node, dst_label_reg); + + if (!add_constraint (dest_sval, EQ_EXPR, dst_label_ptr, ctxt)) + return false; + } + + return true; +} + /* Apply any constraints due to an exception being thrown at LAST_STMT. If they are feasible, add the constraints and return true. diff --git a/gcc/analyzer/region-model.h b/gcc/analyzer/region-model.h index 1ac3a32b7a41..62d463419d67 100644 --- a/gcc/analyzer/region-model.h +++ b/gcc/analyzer/region-model.h @@ -589,6 +589,9 @@ private: const gswitch *switch_stmt, region_model_context *ctxt, rejected_constraint **out); + bool apply_constraints_for_ggoto (const cfg_superedge &edge, + const ggoto *goto_stmt, + region_model_context *ctxt); bool apply_constraints_for_exception (const gimple *last_stmt, region_model_context *ctxt, rejected_constraint **out); diff --git a/gcc/analyzer/supergraph.cc b/gcc/analyzer/supergraph.cc index a23ff15ece45..31707e743a58 100644 --- a/gcc/analyzer/supergraph.cc +++ b/gcc/analyzer/supergraph.cc @@ -829,6 +829,19 @@ supernode::get_stmt_index (const gimple *stmt) const gcc_unreachable (); } +/* Get any label_decl for this supernode, or NULL_TREE if there isn't one. */ + +tree +supernode::get_label () const +{ + if (m_stmts.length () == 0) + return NULL_TREE; + const glabel *label_stmt = dyn_cast (m_stmts[0]); + if (!label_stmt) + return NULL_TREE; + return gimple_label_label (label_stmt); +} + /* Get a string for PK. */ static const char * diff --git a/gcc/analyzer/supergraph.h b/gcc/analyzer/supergraph.h index f8b36d789dc9..27ebd13feb2c 100644 --- a/gcc/analyzer/supergraph.h +++ b/gcc/analyzer/supergraph.h @@ -297,6 +297,8 @@ class supernode : public dnode unsigned int get_stmt_index (const gimple *stmt) const; + tree get_label () const; + function * const m_fun; // alternatively could be stored as runs of indices within the supergraph const basic_block m_bb; gcall * const m_returning_call; // for handling the result of a returned call diff --git a/gcc/testsuite/c-c++-common/analyzer/computed-goto-1.c b/gcc/testsuite/c-c++-common/analyzer/computed-goto-1.c new file mode 100644 index 000000000000..d6877d3959fe --- /dev/null +++ b/gcc/testsuite/c-c++-common/analyzer/computed-goto-1.c @@ -0,0 +1,60 @@ +#include "../../gcc.dg/analyzer/analyzer-decls.h" + +void test_1 (int pc) +{ + void *arr[2] = {&&x, &&y}; + + goto *arr[pc]; + +x: + __analyzer_dump_path (); /* { dg-message "path" } */ + __analyzer_eval (pc == 0); /* { dg-warning "TRUE" "true" { xfail *-*-* } .-1 } */ + /* { dg-bogus "UNKNOWN" "unknown" { xfail *-*-* } .-1 } */ + return; + + y: + __analyzer_dump_path (); /* { dg-message "path" } */ + __analyzer_eval (pc == 1); /* { dg-warning "TRUE" "" { xfail *-*-* } } */ + /* { dg-bogus "UNKNOWN" "unknown" { xfail *-*-* } .-1 } */ + return; +} + +void test_duplicates (int pc) +{ + void *arr[3] = {&&x, &&y, &&x}; + int var = 0; + + goto *arr[pc]; + + x: + __analyzer_dump_path (); /* { dg-message "path" } */ + __analyzer_eval (pc == 0); /* { dg-warning "UNKNOWN" } */ + return; + + y: + __analyzer_dump_path (); /* { dg-message "path" } */ + __analyzer_eval (pc == 1); /* { dg-warning "TRUE" "" { xfail *-*-* } } */ + /* { dg-bogus "UNKNOWN" "unknown" { xfail *-*-* } .-1 } */ + return; +} + +void test_multiple (int pc) +{ + void *arr[2] = {&&x, &&y}; + + goto *arr[pc]; + +x: + __analyzer_dump_path (); /* { dg-message "path" } */ + __analyzer_eval (pc == 0); /* { dg-warning "TRUE" "true" { xfail *-*-* } .-1 } */ + /* { dg-bogus "UNKNOWN" "unknown" { xfail *-*-* } .-1 } */ + + goto *arr[pc]; + + y: + __analyzer_dump_path (); /* { dg-message "path" } */ + __analyzer_eval (pc == 1); /* { dg-warning "TRUE" "" { xfail *-*-* } } */ + /* { dg-bogus "UNKNOWN" "unknown" { xfail *-*-* } .-1 } */ + + goto *arr[pc]; +} diff --git a/gcc/testsuite/gcc.dg/analyzer/computed-goto-pr110529.c b/gcc/testsuite/gcc.dg/analyzer/computed-goto-pr110529.c new file mode 100644 index 000000000000..988f94a0e819 --- /dev/null +++ b/gcc/testsuite/gcc.dg/analyzer/computed-goto-pr110529.c @@ -0,0 +1,27 @@ +/* C only: reuse of same array for int and label pointers. */ + +#include "../../gcc.dg/analyzer/analyzer-decls.h" + +void foo(int pc) { + int *arr[2] = {&&x, &&y}; + int var = 0; + __analyzer_dump_path (); /* { dg-message "path" } */ + + goto *arr[pc]; + +x: + __analyzer_dump_path (); /* { dg-message "path" } */ + __analyzer_eval (pc == 0); /* { dg-warning "TRUE" } */ + /* { dg-bogus "UNKNOWN" "unknown" { xfail *-*-* } .-1 } */ + arr[0] = (void *)0; + *arr[0] = 10086; /* { dg-warning "dereference of NULL" } */ + return; +y: + __analyzer_dump_path (); /* { dg-message "path" } */ + __analyzer_eval (pc == 1); /* { dg-warning "TRUE" "" { xfail *-*-* } } */ + /* { dg-bogus "FALSE" "" { target *-*-* } .-1 } */ + /* { dg-bogus "UNKNOWN" "unknown" { xfail *-*-* } .-2 } */ + return; +} + +int main() { foo(0); }