From patchwork Thu Feb 16 23:16:27 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: David Malcolm X-Patchwork-Id: 1744006 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=gcc.gnu.org (client-ip=2620:52:3:1:0:246e:9693:128c; helo=sourceware.org; envelope-from=gcc-patches-bounces+incoming=patchwork.ozlabs.org@gcc.gnu.org; receiver=) Authentication-Results: legolas.ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=gcc.gnu.org header.i=@gcc.gnu.org header.a=rsa-sha256 header.s=default header.b=Wh+ikVdj; dkim-atps=neutral Received: from sourceware.org (server2.sourceware.org [IPv6:2620:52:3:1:0:246e:9693:128c]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-384) server-digest SHA384) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4PHrSG0Py7z23r4 for ; Fri, 17 Feb 2023 10:17:01 +1100 (AEDT) Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 20CEA3858D33 for ; Thu, 16 Feb 2023 23:16:56 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 20CEA3858D33 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gcc.gnu.org; s=default; t=1676589416; bh=BhcdOaUwsO/C3e0MeyAjsiY+Rbx/Mnv3xiFcLaObRVY=; h=To:Cc:Subject:Date:List-Id:List-Unsubscribe:List-Archive: List-Post:List-Help:List-Subscribe:From:Reply-To:From; b=Wh+ikVdjpmFdIk1uDvv4rmEPF4rlYbFSwZ3oq1dTP4fGXZfZ9IMTc/T6ep8DIw5Tu n2GFRxaIbKCYI08PFh8ezpE0YOl/VbQB897V1qtmbuQAKzUVj8OrbJT4bswEA7dEED QV/O50jTYwLsPBmS0cOE+yd2NMQ0wlSgvvtE1/f4= 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 C0AA83858C78 for ; Thu, 16 Feb 2023 23:16:32 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org C0AA83858C78 Received: from mimecast-mx02.redhat.com (mimecast-mx02.redhat.com [66.187.233.88]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id us-mta-14-iAT5ia44NkOmoBVlxetmPw-1; Thu, 16 Feb 2023 18:16:29 -0500 X-MC-Unique: iAT5ia44NkOmoBVlxetmPw-1 Received: from smtp.corp.redhat.com (int-mx05.intmail.prod.int.rdu2.redhat.com [10.11.54.5]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id F308B101A55E for ; Thu, 16 Feb 2023 23:16:28 +0000 (UTC) Received: from t14s.localdomain.com (unknown [10.2.17.94]) by smtp.corp.redhat.com (Postfix) with ESMTP id BA9CF175AD; Thu, 16 Feb 2023 23:16:28 +0000 (UTC) To: gcc-patches@gcc.gnu.org Cc: David Malcolm Subject: [pushed] analyzer: respect some conditions from bit masks [PR108806] Date: Thu, 16 Feb 2023 18:16:27 -0500 Message-Id: <20230216231627.1748333-1-dmalcolm@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.1 on 10.11.54.5 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com X-Spam-Status: No, score=-11.5 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_H2, 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.29 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+incoming=patchwork.ozlabs.org@gcc.gnu.org Sender: "Gcc-patches" PR analyzer/108806 reports false +ves seen from -fanalyzer on code like this in qemu-7.2.0's hw/intc/omap_intc.c: [...snip...] struct omap_intr_handler_bank_s* bank = NULL; if ((offset & 0xf80) == 0x80) { [...set "bank" to non-NULL...] } switch (offset) { [...snip various cases that don't deref "bank"...] case 0x80: return bank->inputs; case 0x84: return bank->mask; [...etc...] } where the analyzer falsely complains about execution paths in which "(offset & 0xf80) == 0x80" was false (leaving "bank" as NULL), but then in which "switch (offset)" goes to a case for which "(offset & 0xf80) == 0x80" is true and dereferences NULL "bank", i.e. paths in which "(offset & 0xf80) == 0x80" is both true *and* false. This patch adds enough logic to constraint_manager for -fanalyzer to reject such execution paths as impossible, fixing the false +ves. Integration testing shows this eliminates 20 probable false positives: Comparison: 9.08% -> 9.34% GOOD: 66 BAD: 661 -> 641 (-20) where the affected warnings/projects are: -Wanalyzer-null-dereference: 0.00% GOOD: 0 BAD: 279 -> 269 (-10) qemu-7.2.0: 175 -> 165 (-10) -Wanalyzer-use-of-uninitialized-value: 0.00% GOOD: 0 BAD: 153 -> 143 (-10) coreutils-9.1: 18 -> 14 (-4) qemu-7.2.0: 54 -> 48 (-6) Successfully bootstrapped & regrtested on x86_64-pc-linux-gnu. Pushed to trunk as r13-6101-g4d3b7be281e73e. gcc/analyzer/ChangeLog: PR analyzer/108806 * constraint-manager.cc (bounded_range::dump_to_pp): Use bounded_range::singleton_p. (constraint_manager::add_bounded_ranges): Handle singleton ranges by adding an EQ_EXPR constraint. (constraint_manager::impossible_derived_conditions_p): New. (constraint_manager::eval_condition): Reject EQ_EXPR when it would imply impossible derived conditions. (selftest::test_bits): New. (selftest::run_constraint_manager_tests): Run it. * constraint-manager.h (bounded_range::singleton_p): New. (constraint_manager::impossible_derived_conditions_p): New decl. * region-model.cc (region_model::get_rvalue_1): Handle BIT_AND_EXPR, BIT_IOR_EXPR, and BIT_XOR_EXPR. gcc/testsuite/ChangeLog: PR analyzer/108806 * gcc.dg/analyzer/null-deref-pr108806-qemu.c: New test. * gcc.dg/analyzer/pr103217.c: Add -Wno-analyzer-too-complex. * gcc.dg/analyzer/switch.c (test_bitmask_1): New. (test_bitmask_2): New. * gcc.dg/analyzer/uninit-pr108806-qemu.c: New test. Signed-off-by: David Malcolm --- gcc/analyzer/constraint-manager.cc | 166 +++++++++++++++++- gcc/analyzer/constraint-manager.h | 7 + gcc/analyzer/region-model.cc | 3 + .../analyzer/null-deref-pr108806-qemu.c | 105 +++++++++++ gcc/testsuite/gcc.dg/analyzer/pr103217.c | 2 + gcc/testsuite/gcc.dg/analyzer/switch.c | 76 ++++++++ .../gcc.dg/analyzer/uninit-pr108806-qemu.c | 108 ++++++++++++ 7 files changed, 466 insertions(+), 1 deletion(-) create mode 100644 gcc/testsuite/gcc.dg/analyzer/null-deref-pr108806-qemu.c create mode 100644 gcc/testsuite/gcc.dg/analyzer/uninit-pr108806-qemu.c diff --git a/gcc/analyzer/constraint-manager.cc b/gcc/analyzer/constraint-manager.cc index 5a859c6c0f7..2c9c435527e 100644 --- a/gcc/analyzer/constraint-manager.cc +++ b/gcc/analyzer/constraint-manager.cc @@ -421,7 +421,7 @@ dump_cst (pretty_printer *pp, tree cst, bool show_types) void bounded_range::dump_to_pp (pretty_printer *pp, bool show_types) const { - if (tree_int_cst_equal (m_lower, m_upper)) + if (singleton_p ()) dump_cst (pp, m_lower, show_types); else { @@ -2118,6 +2118,17 @@ bool constraint_manager::add_bounded_ranges (const svalue *sval, const bounded_ranges *ranges) { + /* If RANGES is just a singleton, convert this to adding the constraint: + "SVAL == {the singleton}". */ + if (ranges->get_count () == 1 + && ranges->get_range (0).singleton_p ()) + { + tree range_cst = ranges->get_range (0).m_lower; + const svalue *range_sval + = m_mgr->get_or_create_constant_svalue (range_cst); + return add_constraint (sval, EQ_EXPR, range_sval); + } + sval = sval->unwrap_any_unmergeable (); /* Nothing can be known about unknown/poisoned values. */ @@ -2466,6 +2477,66 @@ constraint_manager::eval_condition (equiv_class_id lhs_ec, return tristate::unknown (); } +/* Return true iff "LHS == RHS" is known to be impossible due to + derived conditions. + + Look for an EC containing an EC_VAL of the form (LHS OP CST). + If found, see if (LHS OP CST) == EC_VAL is false. + If so, we know this condition is false. + + For example, if we already know that + (X & CST_MASK) == Y + and we're evaluating X == Z, we can test to see if + (Z & CST_MASK) == EC_VAL + and thus if: + (Z & CST_MASK) == Y + and reject this if we know that's false. */ + +bool +constraint_manager::impossible_derived_conditions_p (const svalue *lhs, + const svalue *rhs) const +{ + int i; + equiv_class *ec; + FOR_EACH_VEC_ELT (m_equiv_classes, i, ec) + { + for (const svalue *ec_sval : ec->m_vars) + switch (ec_sval->get_kind ()) + { + default: + break; + case SK_BINOP: + { + const binop_svalue *iter_binop + = as_a (ec_sval); + if (lhs == iter_binop->get_arg0 () + && iter_binop->get_type ()) + if (iter_binop->get_arg1 ()->get_kind () == SK_CONSTANT) + { + /* Try evalating EC_SVAL with LHS + as the value of EC_SVAL's lhs, and see if it's + consistent with existing knowledge. */ + const svalue *subst_bin_op + = m_mgr->get_or_create_binop + (iter_binop->get_type (), + iter_binop->get_op (), + rhs, + iter_binop->get_arg1 ()); + tristate t = eval_condition (subst_bin_op, + EQ_EXPR, + ec_sval); + if (t.is_false ()) + return true; /* Impossible. */ + } + } + break; + } + } + /* Not known to be impossible. */ + return false; +} + + /* Evaluate the condition LHS OP RHS, without modifying this constraint_manager (avoiding the creation of equiv_class instances). */ @@ -2516,6 +2587,10 @@ constraint_manager::eval_condition (const svalue *lhs, return result_for_ecs; } + if (op == EQ_EXPR + && impossible_derived_conditions_p (lhs, rhs)) + return false; + /* If at least one is not in an EC, we have no constraints comparing LHS and RHS yet. They might still be comparable if one (or both) is a constant. @@ -4435,6 +4510,94 @@ test_bounded_ranges () mgr.get_or_create_point (ch1)); } +/* Verify that we can handle sufficiently simple bitmasking operations. */ + +static void +test_bits (void) +{ + region_model_manager mgr; + + tree int_0 = build_int_cst (integer_type_node, 0); + tree int_0x80 = build_int_cst (integer_type_node, 0x80); + tree int_0xff = build_int_cst (integer_type_node, 0xff); + tree x = build_global_decl ("x", integer_type_node); + + tree x_bit_and_0x80 = build2 (BIT_AND_EXPR, integer_type_node, x, int_0x80); + tree x_bit_and_0xff = build2 (BIT_AND_EXPR, integer_type_node, x, int_0xff); + + /* "x & 0x80 == 0x80". */ + { + region_model model (&mgr); + ADD_SAT_CONSTRAINT (model, x_bit_and_0x80, EQ_EXPR, int_0x80); + ASSERT_CONDITION_FALSE (model, x, EQ_EXPR, int_0); + ASSERT_CONDITION_UNKNOWN (model, x, EQ_EXPR, int_0x80); + } + + /* "x & 0x80 != 0x80". */ + { + region_model model (&mgr); + ADD_SAT_CONSTRAINT (model, x_bit_and_0x80, NE_EXPR, int_0x80); + ASSERT_CONDITION_UNKNOWN (model, x, EQ_EXPR, int_0); + ASSERT_CONDITION_FALSE (model, x, EQ_EXPR, int_0x80); + } + + /* "x & 0x80 == 0". */ + { + region_model model (&mgr); + + ADD_SAT_CONSTRAINT (model, x_bit_and_0x80, EQ_EXPR, int_0); + ASSERT_CONDITION_UNKNOWN (model, x, EQ_EXPR, int_0); + ASSERT_CONDITION_FALSE (model, x, EQ_EXPR, int_0x80); + } + + /* "x & 0x80 != 0". */ + { + region_model model (&mgr); + ADD_SAT_CONSTRAINT (model, x_bit_and_0x80, NE_EXPR, int_0); + ASSERT_CONDITION_FALSE (model, x, EQ_EXPR, int_0); + ASSERT_CONDITION_UNKNOWN (model, x, EQ_EXPR, int_0x80); + } + + /* More that one bit in the mask. */ + + /* "x & 0xff == 0x80". */ + { + region_model model (&mgr); + ADD_SAT_CONSTRAINT (model, x_bit_and_0xff, EQ_EXPR, int_0x80); + ASSERT_CONDITION_FALSE (model, x, EQ_EXPR, int_0); + ASSERT_CONDITION_UNKNOWN (model, x, EQ_EXPR, int_0x80); + ASSERT_CONDITION_FALSE (model, x, EQ_EXPR, int_0xff); + } + + /* "x & 0xff != 0x80". */ + { + region_model model (&mgr); + ADD_SAT_CONSTRAINT (model, x_bit_and_0xff, NE_EXPR, int_0x80); + ASSERT_CONDITION_UNKNOWN (model, x, EQ_EXPR, int_0); + ASSERT_CONDITION_FALSE (model, x, EQ_EXPR, int_0x80); + ASSERT_CONDITION_UNKNOWN (model, x, EQ_EXPR, int_0xff); + } + + /* "x & 0xff == 0". */ + { + region_model model (&mgr); + + ADD_SAT_CONSTRAINT (model, x_bit_and_0xff, EQ_EXPR, int_0); + ASSERT_CONDITION_UNKNOWN (model, x, EQ_EXPR, int_0); + ASSERT_CONDITION_FALSE (model, x, EQ_EXPR, int_0x80); + ASSERT_CONDITION_FALSE (model, x, EQ_EXPR, int_0xff); + } + + /* "x & 0xff != 0". */ + { + region_model model (&mgr); + ADD_SAT_CONSTRAINT (model, x_bit_and_0xff, NE_EXPR, int_0); + ASSERT_CONDITION_FALSE (model, x, EQ_EXPR, int_0); + ASSERT_CONDITION_UNKNOWN (model, x, EQ_EXPR, int_0x80); + ASSERT_CONDITION_UNKNOWN (model, x, EQ_EXPR, int_0xff); + } +} + /* Run the selftests in this file, temporarily overriding flag_analyzer_transitivity with TRANSITIVITY. */ @@ -4458,6 +4621,7 @@ run_constraint_manager_tests (bool transitivity) test_purging (); test_bounded_range (); test_bounded_ranges (); + test_bits (); flag_analyzer_transitivity = saved_flag_analyzer_transitivity; } diff --git a/gcc/analyzer/constraint-manager.h b/gcc/analyzer/constraint-manager.h index 2d82bc9656c..3afbc7f848e 100644 --- a/gcc/analyzer/constraint-manager.h +++ b/gcc/analyzer/constraint-manager.h @@ -100,6 +100,11 @@ struct bounded_range static int cmp (const bounded_range &a, const bounded_range &b); + bool singleton_p () const + { + return tree_int_cst_equal (m_lower, m_upper); + } + tree m_lower; tree m_upper; @@ -498,6 +503,8 @@ public: void add_constraint_internal (equiv_class_id lhs_id, enum constraint_op c_op, equiv_class_id rhs_id); + bool impossible_derived_conditions_p (const svalue *lhs, + const svalue *rhs) const; region_model_manager *m_mgr; }; diff --git a/gcc/analyzer/region-model.cc b/gcc/analyzer/region-model.cc index 424d83c191f..e3de74bbf45 100644 --- a/gcc/analyzer/region-model.cc +++ b/gcc/analyzer/region-model.cc @@ -2253,6 +2253,9 @@ region_model::get_rvalue_1 (path_var pv, region_model_context *ctxt) const /* Binary ops. */ case PLUS_EXPR: case MULT_EXPR: + case BIT_AND_EXPR: + case BIT_IOR_EXPR: + case BIT_XOR_EXPR: { tree expr = pv.m_tree; tree arg0 = TREE_OPERAND (expr, 0); diff --git a/gcc/testsuite/gcc.dg/analyzer/null-deref-pr108806-qemu.c b/gcc/testsuite/gcc.dg/analyzer/null-deref-pr108806-qemu.c new file mode 100644 index 00000000000..3ab72c053af --- /dev/null +++ b/gcc/testsuite/gcc.dg/analyzer/null-deref-pr108806-qemu.c @@ -0,0 +1,105 @@ +/* Reduced from qemu-7.2.0's hw/intc/omap_intc.c */ + +#define NULL ((void*)0) + +typedef unsigned char __uint8_t; +typedef unsigned int __uint32_t; +typedef unsigned long int __uint64_t; +typedef __uint8_t uint8_t; +typedef __uint32_t uint32_t; +typedef __uint64_t uint64_t; +typedef uint64_t hwaddr; +typedef struct omap_intr_handler_s omap_intr_handler; + +struct omap_intr_handler_bank_s +{ + uint32_t irqs; + uint32_t inputs; + uint32_t mask; + uint32_t fiq; + uint32_t sens_edge; + uint32_t swi; + unsigned char priority[32]; +}; + +struct omap_intr_handler_s +{ + /* [...snip...] */ + unsigned char nbanks; + /* [...snip...] */ + int sir_intr[2]; + int autoidle; + uint32_t mask; + struct omap_intr_handler_bank_s bank[3]; +}; + +uint64_t +omap2_inth_read(struct omap_intr_handler_s* s, int offset) +{ + int bank_no, line_no; + struct omap_intr_handler_bank_s* bank = NULL; + + if ((offset & 0xf80) == 0x80) { + bank_no = (offset & 0x60) >> 5; + if (bank_no < s->nbanks) { + offset &= ~0x60; + bank = &s->bank[bank_no]; + } else { + return 0; + } + } + + switch (offset) { + case 0x10: + return (s->autoidle >> 2) & 1; + + case 0x14: + return 1; + + case 0x40: + return s->sir_intr[0]; + + case 0x44: + return s->sir_intr[1]; + + case 0x48: + return (!s->mask) << 2; + + case 0x4c: + return 0; + + case 0x50: + return s->autoidle & 3; + + case 0x80: + return bank->inputs; /* { dg-bogus "dereference of NULL 'bank'" "PR analyzer/108806" } */ + + case 0x84: + return bank->mask; /* { dg-bogus "dereference of NULL 'bank'" "PR analyzer/108806" } */ + + case 0x88: + case 0x8c: + return 0; + + case 0x90: + return bank->swi; /* { dg-bogus "dereference of NULL 'bank'" "PR analyzer/108806" } */ + + case 0x94: + return 0; + + case 0x98: + return bank->irqs & ~bank->mask & ~bank->fiq; /* { dg-bogus "dereference of NULL 'bank'" "PR analyzer/108806" } */ + + case 0x9c: + return bank->irqs & ~bank->mask & bank->fiq; /* { dg-bogus "dereference of NULL 'bank'" "PR analyzer/108806" } */ + + case 0x100 ... 0x300: + bank_no = (offset - 0x100) >> 7; + if (bank_no > s->nbanks) + break; + bank = &s->bank[bank_no]; + line_no = (offset & 0x7f) >> 2; + return (bank->priority[line_no] << 2) | ((bank->fiq >> line_no) & 1); + } + return 0; +} diff --git a/gcc/testsuite/gcc.dg/analyzer/pr103217.c b/gcc/testsuite/gcc.dg/analyzer/pr103217.c index a0ef8bf3210..08889acb2c9 100644 --- a/gcc/testsuite/gcc.dg/analyzer/pr103217.c +++ b/gcc/testsuite/gcc.dg/analyzer/pr103217.c @@ -1,3 +1,5 @@ +/* { dg-additional-options "-Wno-analyzer-too-complex" } */ + extern char *strdup (const char *__s) __attribute__ ((__nothrow__ , __leaf__, __malloc__, __nonnull__ (1))); diff --git a/gcc/testsuite/gcc.dg/analyzer/switch.c b/gcc/testsuite/gcc.dg/analyzer/switch.c index 0b9e7e3b869..5f42e7f21db 100644 --- a/gcc/testsuite/gcc.dg/analyzer/switch.c +++ b/gcc/testsuite/gcc.dg/analyzer/switch.c @@ -161,3 +161,79 @@ int test_7 () } return 0; } + +int test_bitmask_1 (int x) +{ + int flag = 0; + if (x & 0x80) + flag = 1; + + switch (x) + { + case 0: + if (flag) + __analyzer_dump_path (); /* { dg-bogus "path" } */ + else + __analyzer_dump_path (); /* { dg-message "path" } */ + break; + + case 0x80: + if (flag) + __analyzer_dump_path (); /* { dg-message "path" } */ + else + __analyzer_dump_path (); /* { dg-bogus "path" } */ + break; + + case 0x81: + if (flag) + __analyzer_dump_path (); /* { dg-message "path" } */ + else + __analyzer_dump_path (); /* { dg-bogus "path" } */ + break; + } +} + +int test_bitmask_2 (int x) +{ + int flag = 0; + if ((x & 0xf80) == 0x80) + flag = 1; + + switch (x) + { + case 0: + if (flag) + __analyzer_dump_path (); /* { dg-bogus "path" } */ + else + __analyzer_dump_path (); /* { dg-message "path" } */ + break; + + case 0x80: + if (flag) + __analyzer_dump_path (); /* { dg-message "path" } */ + else + __analyzer_dump_path (); /* { dg-bogus "path" } */ + break; + + case 0x81: + if (flag) + __analyzer_dump_path (); /* { dg-message "path" } */ + else + __analyzer_dump_path (); /* { dg-bogus "path" } */ + break; + + case 0x180: + if (flag) + __analyzer_dump_path (); /* { dg-bogus "path" } */ + else + __analyzer_dump_path (); /* { dg-message "path" } */ + break; + + case 0xf80: + if (flag) + __analyzer_dump_path (); /* { dg-bogus "path" } */ + else + __analyzer_dump_path (); /* { dg-message "path" } */ + break; + } +} diff --git a/gcc/testsuite/gcc.dg/analyzer/uninit-pr108806-qemu.c b/gcc/testsuite/gcc.dg/analyzer/uninit-pr108806-qemu.c new file mode 100644 index 00000000000..34fe802f495 --- /dev/null +++ b/gcc/testsuite/gcc.dg/analyzer/uninit-pr108806-qemu.c @@ -0,0 +1,108 @@ +/* Reduced from qemu-7.2.0's hw/intc/omap_intc.c as per + null-deref-pr108806.c, but with the: + struct omap_intr_handler_bank_s* bank = NULL; + converted to: + struct omap_intr_handler_bank_s* bank; + */ + +typedef unsigned char __uint8_t; +typedef unsigned int __uint32_t; +typedef unsigned long int __uint64_t; +typedef __uint8_t uint8_t; +typedef __uint32_t uint32_t; +typedef __uint64_t uint64_t; +typedef uint64_t hwaddr; +typedef struct omap_intr_handler_s omap_intr_handler; + +struct omap_intr_handler_bank_s +{ + uint32_t irqs; + uint32_t inputs; + uint32_t mask; + uint32_t fiq; + uint32_t sens_edge; + uint32_t swi; + unsigned char priority[32]; +}; + +struct omap_intr_handler_s +{ + /* [...snip...] */ + unsigned char nbanks; + /* [...snip...] */ + int sir_intr[2]; + int autoidle; + uint32_t mask; + struct omap_intr_handler_bank_s bank[3]; +}; + +uint64_t +omap2_inth_read(struct omap_intr_handler_s* s, int offset) +{ + int bank_no, line_no; + struct omap_intr_handler_bank_s* bank; + + if ((offset & 0xf80) == 0x80) { + bank_no = (offset & 0x60) >> 5; + if (bank_no < s->nbanks) { + offset &= ~0x60; + bank = &s->bank[bank_no]; + } else { + return 0; + } + } + + switch (offset) { + case 0x10: + return (s->autoidle >> 2) & 1; + + case 0x14: + return 1; + + case 0x40: + return s->sir_intr[0]; + + case 0x44: + return s->sir_intr[1]; + + case 0x48: + return (!s->mask) << 2; + + case 0x4c: + return 0; + + case 0x50: + return s->autoidle & 3; + + case 0x80: + return bank->inputs; /* { dg-bogus "use of uninitialized value 'bank'" "PR analyzer/108806" } */ + + case 0x84: + return bank->mask; /* { dg-bogus "use of uninitialized value 'bank'" "PR analyzer/108806" } */ + + case 0x88: + case 0x8c: + return 0; + + case 0x90: + return bank->swi; /* { dg-bogus "use of uninitialized value 'bank'" "PR analyzer/108806" } */ + + case 0x94: + return 0; + + case 0x98: + return bank->irqs & ~bank->mask & ~bank->fiq; /* { dg-bogus "use of uninitialized value 'bank'" "PR analyzer/108806" } */ + + case 0x9c: + return bank->irqs & ~bank->mask & bank->fiq; /* { dg-bogus "use of uninitialized value 'bank'" "PR analyzer/108806" } */ + + case 0x100 ... 0x300: + bank_no = (offset - 0x100) >> 7; + if (bank_no > s->nbanks) + break; + bank = &s->bank[bank_no]; + line_no = (offset & 0x7f) >> 2; + return (bank->priority[line_no] << 2) | ((bank->fiq >> line_no) & 1); + } + return 0; +}