From patchwork Mon Aug 15 12:35:25 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Tim Lange X-Patchwork-Id: 529 Return-Path: Delivered-To: ouuuleilei@gmail.com Received: by 2002:a05:6a10:38f:b0:2d5:3c95:9e21 with SMTP id 15csp1337652pxh; Mon, 15 Aug 2022 05:36:31 -0700 (PDT) X-Google-Smtp-Source: AA6agR5AJ0xG2hK7sD2LahvldZ4P+qq9MqBoypJTO565IZYwu5nkIsc9qTwyOi7sA4DnyrwN5qLi X-Received: by 2002:a17:906:c150:b0:733:76b:c7a5 with SMTP id dp16-20020a170906c15000b00733076bc7a5mr10002959ejc.567.1660566990842; Mon, 15 Aug 2022 05:36:30 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1660566990; cv=none; d=google.com; s=arc-20160816; b=Jl1ZN39tul4rBFhqgNRcIG/kXzX+Gor+PKWMfMec8l3sRprC4vvWNMZZM+ApXCW38n /20jb42lR4qGEszYIcD1jMyDe77eZdNfZ6oGtly9vAjScPAWkb479B77UYxkuEIl0N3T qofPpWBEWH3jh3s6zrjKfB0aYcSEO0alAAkKaWCexS39faj2Z3wnuSJDsNcxuH/Cp5S/ Lz44zsbslDJfFfxWd9vt3ASFUJeplqEYiWEDEmImaOWk+Zc1Nvvazbgb0meGauAZlwYP M6q2iE5MOvVVGlbsm1sWXKN/lCX2VzafFwOWTeZYdrfJ5x9Fszx+eX0PMZ6xGUCqF7wg QbZw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=sender:errors-to:cc:list-subscribe:list-help:list-post:list-archive :list-unsubscribe:list-id:precedence:content-transfer-encoding :mime-version:message-id:date:subject:to:from:dkim-signature :dmarc-filter:delivered-to; bh=EfOxmtFXEhzuUzj5GGC0QiAJRg0Qh3O3IbccDPcmBNM=; b=KAN2cAX/s6VWJZyj22ZsxJpJcHwu9hSYSgv6/X71vrZpIWYHO4axjvELDmLd9nZeY/ Ri/7a2ARpw60z4hLW62ne1I6kkjeC3t8+PqMnWLZjEDy+A7rYKNoBysT4ZZOE1s9w2b3 n37LNXShxQ/G8yuGK/tkrMAwJDGTUSjNWM44uIyFJY3hIFqlns/AWP4r5BDnfqu/tziI x0ouCEZhekc8lztBjqsRlCO9TESLMoilEO6HIjFQtbdscY8kNYH7ZvFEIzTiKAroGfpi YH/4qOOxoQSeMavvVqkAhnKlYbJtqxCxQo51DJS0DunSVY//JNTZUB2WaSRcKvQi4m+u cruw== ARC-Authentication-Results: i=1; mx.google.com; dkim=fail header.i=@tim-lange.me header.s=default2108 header.b=PfDObaYl; 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" Received: from sourceware.org (server2.sourceware.org. [2620:52:3:1:0:246e:9693:128c]) by mx.google.com with ESMTPS id q20-20020a170906b29400b0072f1be0dff8si6164786ejz.133.2022.08.15.05.36.30 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 15 Aug 2022 05:36:30 -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=fail header.i=@tim-lange.me header.s=default2108 header.b=PfDObaYl; 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" Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 9E9C33857C5C for ; Mon, 15 Aug 2022 12:36:18 +0000 (GMT) X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from www523.your-server.de (www523.your-server.de [159.69.224.22]) by sourceware.org (Postfix) with ESMTPS id E432D3858C74 for ; Mon, 15 Aug 2022 12:35:51 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org E432D3858C74 Authentication-Results: sourceware.org; dmarc=none (p=none dis=none) header.from=tim-lange.me Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=tim-lange.me DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=tim-lange.me; s=default2108; h=Content-Transfer-Encoding:Content-Type: MIME-Version:Message-Id:Date:Subject:Cc:To:From:Sender:Reply-To:Content-ID: Content-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc :Resent-Message-ID:In-Reply-To:References; bh=EfOxmtFXEhzuUzj5GGC0QiAJRg0Qh3O3IbccDPcmBNM=; b=PfDObaYl+NsmxhtYMGiQN3xwLT /M6GmTFAXxFeLiAoZOGFQG6V/rRuaprQ80052T++USmakSjZ5+Hqd7Q32WKk7pB80ZUgiURls7cHB baZIYgZlZvXB4+6hGzns0VmaXqfyZcrKn8rvf021q7MWNrheiLhpMFKN6UEbViwObtC6QrsSVIqke OiEEL8laZTrrAK5ElMrhSSCJ1ubDFdetYdEui+7kXL/sgchHQQnSkuuXeImTw50RZDMMPRS5Gx9c2 8UZCz+jBQVaYpFstWw1Bzqu+UnSzLACU0uZN2yG51aV+N+WAGZAWWfc1U9KohIUCJq557GbOmlmkG 2fnsku8g==; Received: from sslproxy02.your-server.de ([78.47.166.47]) by www523.your-server.de with esmtpsa (TLSv1.3:TLS_AES_256_GCM_SHA384:256) (Exim 4.92.3) (envelope-from ) id 1oNZJu-0002NC-32; Mon, 15 Aug 2022 14:35:50 +0200 Received: from [2001:41b8:83c:fa00:6614:184a:362a:2909] (helo=fedora.tu-darmstadt.de) by sslproxy02.your-server.de with esmtpsa (TLSv1.3:TLS_AES_256_GCM_SHA384:256) (Exim 4.92) (envelope-from ) id 1oNZJt-000XdI-UK; Mon, 15 Aug 2022 14:35:49 +0200 From: Tim Lange To: gcc-patches@gcc.gnu.org Subject: [PATCH] analyzer: warn on the use of floating points in the size argument [PR106181] Date: Mon, 15 Aug 2022 14:35:25 +0200 Message-Id: <20220815123525.49172-1-mail@tim-lange.me> X-Mailer: git-send-email 2.37.2 MIME-Version: 1.0 X-Authenticated-Sender: mail@tim-lange.me X-Virus-Scanned: Clear (ClamAV 0.103.6/26628/Mon Aug 15 09:51:41 2022) X-Spam-Status: No, score=-11.4 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, KAM_INFOUSMEBIZ, SPF_HELO_NONE, SPF_PASS, TXREP, T_SCC_BODY_TEXT_LINE 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: , Cc: Tim Lange Errors-To: gcc-patches-bounces+ouuuleilei=gmail.com@gcc.gnu.org Sender: "Gcc-patches" X-getmail-retrieved-from-mailbox: =?utf-8?q?INBOX?= X-GMAIL-THRID: =?utf-8?q?1741230692585459893?= X-GMAIL-MSGID: =?utf-8?q?1741230692585459893?= This patch fixes the ICE reported in PR106181 and adds a new warning to the analyzer complaining about the use of floating point operands. I decided to move the warning for floats inside the size argument out of the allocation size checker code and toward the allocation such that the warning only appears once. I'm not sure about the wording of the diagnostic, my current wording feels a bit bulky. Here is how the diagnostics look like: /path/to/main.c: In function ‘test_1’: /path/to/main.c:10:14: warning: use of floating point arithmetic inside the size argument might yield unexpected results [-Wanalyzer-imprecise-floating-point-arithmetic] 10 | int *ptr = malloc (sizeof (int) * n); /* { dg-line test_1 } */ | ^~~~~~~~~~~~~~~~~~~~~~~~~ ‘test_1’: event 1 | | 10 | int *ptr = malloc (sizeof (int) * n); /* { dg-line test_1 } */ | | ^~~~~~~~~~~~~~~~~~~~~~~~~ | | | | | (1) operand ‘n’ is of type ‘float’ | /path/to/main.c:10:14: note: only use operands of a type that represents whole numbers inside the size argument /path/to/main.c: In function ‘test_2’: /path/to/main.c:20:14: warning: use of floating point arithmetic inside the size argument might yield unexpected results [-Wanalyzer-imprecise-floating-point-arithmetic] 20 | int *ptr = malloc (n * 3.1); /* { dg-line test_2 } */ | ^~~~~~~~~~~~~~~~ ‘test_2’: event 1 | | 20 | int *ptr = malloc (n * 3.1); /* { dg-line test_2 } */ | | ^~~~~~~~~~~~~~~~ | | | | | (1) operand ‘3.1000000000000001e+0’ is of type ‘double’ | /path/to/main.c:20:14: note: only use operands of a type that represents whole numbers inside the size argument Also, another point to discuss is the event note in case the expression is wrapped in a variable, such as in test_3: /path/to/main.c:30:10: warning: use of floating point arithmetic inside the size argument might yield unexpected results [-Wanalyzer-imprecise-floating-point-arithmetic] 30 | return malloc (size); /* { dg-line test_3 } */ | ^~~~~~~~~~~~~ ‘test_3’: events 1-2 | | 37 | void test_3 (float f) | | ^~~~~~ | | | | | (1) entry to ‘test_3’ | 38 | { | 39 | void *ptr = alloc_me (f); /* { dg-message "calling 'alloc_me' from 'test_3'" } */ | | ~~~~~~~~~~~~ | | | | | (2) calling ‘alloc_me’ from ‘test_3’ | +--> ‘alloc_me’: events 3-4 | | 28 | void *alloc_me (size_t size) | | ^~~~~~~~ | | | | | (3) entry to ‘alloc_me’ | 29 | { | 30 | return malloc (size); /* { dg-line test_3 } */ | | ~~~~~~~~~~~~~ | | | | | (4) operand ‘f’ is of type ‘float’ | I'm not sure if it is easily discoverable that event (4) does refer to 'size'. I thought about also printing get_representative_tree (capacity) in the event but that would clutter the event message if the argument does hold the full expression. I don't have any strong feelings about the decision here but if I had to decide I'd leave it as is (especially because the warning is probably quite unusual). The index of the argument would also be a possibility, but that would get tricky for calloc. Regrtested on Linux x86_64, ran the analyzer & analyzer-torture tests with the -m32 option enabled and had no false positives on coreutils, httpd, openssh and curl. 2022-08-15 Tim Lange gcc/analyzer/ChangeLog: PR analyzer/106181 * analyzer.opt: Add Wanalyzer-imprecise-floating-point-arithmetic. * region-model-impl-calls.cc (region_model::impl_call_alloca): Add call to region_model::check_region_capacity_for_floats. (region_model::impl_call_calloc): Add call to region_model::check_region_capacity_for_floats. (region_model::impl_call_malloc): Add call to region_model::check_region_capacity_for_floats. * region-model.cc (is_any_cast_p): Formatting. (region_model::check_region_size): Ensure precondition. (class imprecise_floating_point_arithmetic): New abstract diagnostic class for all floating point related warnings. (class float_as_size_arg): Concrete diagnostic class to complain about floating point operands inside the size argument. (class contains_floating_point_visitor): New visitor to find floating point operands inside svalues. (region_model::check_region_capacity_for_floats): New function. * region-model.h (class region_model): Add region_model::check_region_capacity_for_floats. gcc/ChangeLog: PR analyzer/106181 * doc/invoke.texi: Add Wanalyzer-imprecise-floating-point-arithmetic. gcc/testsuite/ChangeLog: PR analyzer/106181 * gcc.dg/analyzer/allocation-size-1.c: New test. * gcc.dg/analyzer/imprecise-floating-point-1.c: New test. * gcc.dg/analyzer/pr106181.c: New test. --- gcc/analyzer/analyzer.opt | 4 + gcc/analyzer/region-model-impl-calls.cc | 3 + gcc/analyzer/region-model.cc | 192 ++++++++++++++++-- gcc/analyzer/region-model.h | 2 + gcc/doc/invoke.texi | 14 ++ .../gcc.dg/analyzer/allocation-size-1.c | 10 + .../analyzer/imprecise-floating-point-1.c | 62 ++++++ gcc/testsuite/gcc.dg/analyzer/pr106181.c | 11 + 8 files changed, 277 insertions(+), 21 deletions(-) create mode 100644 gcc/testsuite/gcc.dg/analyzer/imprecise-floating-point-1.c create mode 100644 gcc/testsuite/gcc.dg/analyzer/pr106181.c diff --git a/gcc/analyzer/analyzer.opt b/gcc/analyzer/analyzer.opt index 61b58c575ff..bef15eae2c3 100644 --- a/gcc/analyzer/analyzer.opt +++ b/gcc/analyzer/analyzer.opt @@ -98,6 +98,10 @@ Wanalyzer-free-of-non-heap Common Var(warn_analyzer_free_of_non_heap) Init(1) Warning Warn about code paths in which a non-heap pointer is freed. +Wanalyzer-imprecise-floating-point-arithmetic +Common Var(warn_analyzer_imprecise_floating_point_arithmetic) Init(1) Warning +Warn about code paths in which floating point arithmetic is use in locations where precise computation is needed. + Wanalyzer-jump-through-null Common Var(warn_analyzer_jump_through_null) Init(1) Warning Warn about code paths in which a NULL function pointer is called. diff --git a/gcc/analyzer/region-model-impl-calls.cc b/gcc/analyzer/region-model-impl-calls.cc index 8eebd122d42..c4d7e186963 100644 --- a/gcc/analyzer/region-model-impl-calls.cc +++ b/gcc/analyzer/region-model-impl-calls.cc @@ -237,6 +237,7 @@ region_model::impl_call_alloca (const call_details &cd) const region *new_reg = create_region_for_alloca (size_sval, cd.get_ctxt ()); const svalue *ptr_sval = m_mgr->get_ptr_svalue (cd.get_lhs_type (), new_reg); + check_region_capacity_for_floats (ptr_sval, cd.get_ctxt ()); cd.maybe_set_lhs (ptr_sval); } @@ -393,6 +394,7 @@ region_model::impl_call_calloc (const call_details &cd) { const svalue *ptr_sval = m_mgr->get_ptr_svalue (cd.get_lhs_type (), new_reg); + check_region_capacity_for_floats (ptr_sval, cd.get_ctxt ()); cd.maybe_set_lhs (ptr_sval); } } @@ -497,6 +499,7 @@ region_model::impl_call_malloc (const call_details &cd) { const svalue *ptr_sval = m_mgr->get_ptr_svalue (cd.get_lhs_type (), new_reg); + check_region_capacity_for_floats (ptr_sval, cd.get_ctxt ()); cd.maybe_set_lhs (ptr_sval); } } diff --git a/gcc/analyzer/region-model.cc b/gcc/analyzer/region-model.cc index 7e7077696f7..1c23fb8c79e 100644 --- a/gcc/analyzer/region-model.cc +++ b/gcc/analyzer/region-model.cc @@ -3303,7 +3303,8 @@ public: m.add_cwe (131); return warning_meta (rich_loc, m, get_controlling_option (), - "allocated buffer size is not a multiple of the pointee's size"); + "allocated buffer size is not a multiple" + " of the pointee's size"); } label_text @@ -3398,21 +3399,20 @@ capacity_compatible_with_type (tree cst, tree pointee_size_tree) class size_visitor : public visitor { public: - size_visitor (tree size_cst, const svalue *sval, constraint_manager *cm) - : m_size_cst (size_cst), m_sval (sval), m_cm (cm) + size_visitor (tree size_cst, const svalue *root_sval, constraint_manager *cm) + : m_size_cst (size_cst), m_root_sval (root_sval), m_cm (cm) { - sval->accept (this); + m_root_sval->accept (this); } bool get_result () { - return result_set.contains (m_sval); + return result_set.contains (m_root_sval); } void visit_constant_svalue (const constant_svalue *sval) final override { - if (capacity_compatible_with_type (sval->get_constant (), m_size_cst)) - result_set.add (sval); + check_constant (sval->get_constant (), sval); } void visit_unknown_svalue (const unknown_svalue *sval ATTRIBUTE_UNUSED) @@ -3480,15 +3480,10 @@ public: equiv_class_id id (-1); if (m_cm->get_equiv_class_by_svalue (sval, &id)) { - if (tree cst_val = id.get_obj (*m_cm).get_any_constant ()) - { - if (capacity_compatible_with_type (cst_val, m_size_cst)) - result_set.add (sval); - } + if (tree cst = id.get_obj (*m_cm).get_any_constant ()) + check_constant (cst, sval); else - { - result_set.add (sval); - } + result_set.add (sval); } } @@ -3505,8 +3500,23 @@ public: } private: + void check_constant (tree cst, const svalue *sval) + { + switch (TREE_CODE (cst)) + { + default: + /* Assume all unhandled operands are compatible. */ + result_set.add (sval); + break; + case INTEGER_CST: + if (capacity_compatible_with_type (cst, m_size_cst)) + result_set.add (sval); + break; + } + } + tree m_size_cst; - const svalue *m_sval; + const svalue *m_root_sval; constraint_manager *m_cm; svalue_set result_set; /* Used as a mapping of svalue*->bool. */ }; @@ -3543,12 +3553,12 @@ struct_or_union_with_inheritance_p (tree struc) static bool is_any_cast_p (const gimple *stmt) { - if (const gassign *assign = dyn_cast(stmt)) + if (const gassign *assign = dyn_cast (stmt)) return gimple_assign_cast_p (assign) || !pending_diagnostic::same_tree_p ( TREE_TYPE (gimple_assign_lhs (assign)), TREE_TYPE (gimple_assign_rhs1 (assign))); - else if (const gcall *call = dyn_cast(stmt)) + else if (const gcall *call = dyn_cast (stmt)) { tree lhs = gimple_call_lhs (call); return lhs != NULL_TREE && !pending_diagnostic::same_tree_p ( @@ -3608,10 +3618,11 @@ region_model::check_region_size (const region *lhs_reg, const svalue *rhs_sval, case svalue_kind::SK_CONSTANT: { const constant_svalue *cst_cap_sval - = as_a (capacity); + = as_a (capacity); tree cst_cap = cst_cap_sval->get_constant (); - if (!capacity_compatible_with_type (cst_cap, pointee_size_tree, - is_struct)) + if (TREE_CODE (cst_cap) == INTEGER_CST + && !capacity_compatible_with_type (cst_cap, pointee_size_tree, + is_struct)) ctxt->warn (new dubious_allocation_size (lhs_reg, rhs_reg, cst_cap)); } @@ -3633,6 +3644,145 @@ region_model::check_region_size (const region *lhs_reg, const svalue *rhs_sval, } } +/* Abstract class for diagnostics related touse of floating point + arithmetic where precision is needed. */ + +class imprecise_floating_point_arithmetic +: public pending_diagnostic_subclass +{ +public: + imprecise_floating_point_arithmetic () + {} + + const char *get_kind () const final override + { + return "imprecise_floating_point_arithmetic"; + } + + int get_controlling_option () const final override + { + return OPT_Wanalyzer_imprecise_floating_point_arithmetic; + } + + bool + operator== (const imprecise_floating_point_arithmetic &other + ATTRIBUTE_UNUSED) const + { + return true; + } +}; + +/* Concrete diagnostic to complain about uses of floating point arithmetic + in the size argument of malloc etc. */ + +class float_as_size_arg : public imprecise_floating_point_arithmetic +{ +public: + float_as_size_arg (tree arg) : m_arg (arg) + {} + + bool operator== (const float_as_size_arg &other) const + { + return pending_diagnostic::same_tree_p (m_arg, other.m_arg); + } + + bool emit (rich_location *rich_loc) final override + { + diagnostic_metadata m; + bool warned = warning_meta (rich_loc, m, get_controlling_option (), + "use of floating point arithmetic inside the" + " size argument might yield unexpected" + " results"); + if (warned) + inform (rich_loc->get_loc (), "only use operands of a type that" + " represents whole numbers inside the" + " size argument"); + return warned; + } + + label_text describe_final_event (const evdesc::final_event &ev) final + override + { + if (m_arg) + return ev.formatted_print ("operand %qE is of type %qT", + m_arg, TREE_TYPE (m_arg)); + return ev.formatted_print ("at least one operand of the size argument is" + " of a floating point type"); + } + +private: + tree m_arg; +}; + +/* Visitor to find uses of floating point variables/constants in an svalue. */ + +class contains_floating_point_visitor : public visitor +{ +public: + contains_floating_point_visitor (const svalue *root_sval) : m_result (NULL) + { + root_sval->accept (this); + } + + const svalue *get_svalue_to_report () + { + return m_result; + } + + void visit_constant_svalue (const constant_svalue *sval) final override + { + /* At the point the analyzer runs, constant integer operands in a floating + point expression are already implictly converted to floating points. + Thus, we do prefer to report non-constants such that the diagnostic + always reports a floating point operand. */ + tree type = sval->get_type (); + if (type && FLOAT_TYPE_P (type) && !m_result) + m_result = sval; + } + + void visit_conjured_svalue (const conjured_svalue *sval) final override + { + tree type = sval->get_type (); + if (type && SCALAR_FLOAT_TYPE_P (type)) + m_result = sval; + } + + void visit_initial_svalue (const initial_svalue *sval) final override + { + tree type = sval->get_type (); + if (type && SCALAR_FLOAT_TYPE_P (type)) + m_result = sval; + } + +private: + /* Non-null if at least one floating point operand was found. */ + const svalue *m_result; +}; + +/* May complain about uses of floating point operands in the capacity of SVAL. + + SVAL is expected to be a region_svalue. */ + +void +region_model::check_region_capacity_for_floats (const svalue *sval, + region_model_context *ctxt) +const +{ + if (!ctxt) + return; + + if (const region_svalue *reg_sval = dyn_cast (sval)) + { + const svalue *capacity = get_capacity (reg_sval->get_pointee ()); + contains_floating_point_visitor v (capacity); + if (const svalue *float_sval = v.get_svalue_to_report ()) + { + tree diag_arg = get_representative_tree (float_sval); + ctxt->warn (new float_as_size_arg (diag_arg)); + } + } +} + /* Set the value of the region given by LHS_REG to the value given by RHS_SVAL. Use CTXT to report any warnings associated with writing to LHS_REG. */ diff --git a/gcc/analyzer/region-model.h b/gcc/analyzer/region-model.h index cdf10872c0f..dcb87101733 100644 --- a/gcc/analyzer/region-model.h +++ b/gcc/analyzer/region-model.h @@ -869,6 +869,8 @@ class region_model region_model_context *ctxt) const; void check_region_size (const region *lhs_reg, const svalue *rhs_sval, region_model_context *ctxt) const; + void check_region_capacity_for_floats (const svalue *reg_sval, + region_model_context *ctxt) const; void check_region_bounds (const region *reg, enum access_direction dir, region_model_context *ctxt) const; diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi index b264ae28fe6..4ef73a264ea 100644 --- a/gcc/doc/invoke.texi +++ b/gcc/doc/invoke.texi @@ -453,6 +453,7 @@ Objective-C and Objective-C++ Dialects}. -Wno-analyzer-fd-use-without-check @gol -Wno-analyzer-file-leak @gol -Wno-analyzer-free-of-non-heap @gol +-Wno-analyzer-imprecise-floating-point-arithmetic @gol -Wno-analyzer-jump-through-null @gol -Wno-analyzer-malloc-leak @gol -Wno-analyzer-mismatching-deallocation @gol @@ -9758,6 +9759,7 @@ Enabling this option effectively enables the following warnings: -Wanalyzer-fd-use-without-check @gol -Wanalyzer-file-leak @gol -Wanalyzer-free-of-non-heap @gol +-Wno-analyzer-imprecise-floating-point-arithmetic @gol -Wanalyzer-jump-through-null @gol -Wanalyzer-malloc-leak @gol -Wanalyzer-mismatching-deallocation @gol @@ -9946,6 +9948,18 @@ is called on a non-heap pointer (e.g. an on-stack buffer, or a global). See @uref{https://cwe.mitre.org/data/definitions/590.html, CWE-590: Free of Memory not on the Heap}. +@item -Wno-analyzer-imprecise-floating-point-arithmetic +@opindex Wanalyzer-imprecise-floating-point-arithmetic +@opindex Wno-analyzer-imprecise-floating-point-arithmetic +This warning requires @option{-fanalyzer}, which enables it; use +@option{-Wno-analyzer-imprecise-floating-point-arithmetic} +to disable it. + +This diagnostic warns for paths through the code in which floating point +arithmetic is used in locations where precise computation is needed. This +diagnostic only warns on use of floating points operands inside the +allocation size at the moment. + @item -Wno-analyzer-jump-through-null @opindex Wanalyzer-jump-through-null @opindex Wno-analyzer-jump-through-null diff --git a/gcc/testsuite/gcc.dg/analyzer/allocation-size-1.c b/gcc/testsuite/gcc.dg/analyzer/allocation-size-1.c index b5bed539250..003914ed96c 100644 --- a/gcc/testsuite/gcc.dg/analyzer/allocation-size-1.c +++ b/gcc/testsuite/gcc.dg/analyzer/allocation-size-1.c @@ -115,3 +115,13 @@ void test_10 (int32_t n) char *ptr = malloc (7 * n); free (ptr); } + +void test_11 () +{ + /* 3.0 is folded to an int before the analyzer runs. */ + int32_t *ptr = malloc (3.0); /* { dg-line malloc11 } */ + free (ptr); + + /* { dg-warning "allocated buffer size is not a multiple of the pointee's size \\\[CWE-131\\\]" "warning" { target *-*-* } malloc11 } */ + /* { dg-message "'int32_t \\*' (\\\{aka '(long )?int \\*'\\\})? here; 'sizeof \\(int32_t (\\\{aka (long )?int\\\})?\\)' is '4'" "note" { target *-*-* } malloc11 } */ +} diff --git a/gcc/testsuite/gcc.dg/analyzer/imprecise-floating-point-1.c b/gcc/testsuite/gcc.dg/analyzer/imprecise-floating-point-1.c new file mode 100644 index 00000000000..110a9d3b9b3 --- /dev/null +++ b/gcc/testsuite/gcc.dg/analyzer/imprecise-floating-point-1.c @@ -0,0 +1,62 @@ +#include + +/* Tests warn on use of floating point operands inside the allocation size. + + The test cases here only test for warnings. The test cases inside + allocation-size-X.c should be plently enough to test for false positives. */ + +void test_1 (float n) +{ + int *ptr = malloc (sizeof (int) * n); /* { dg-line test_1 } */ + free (ptr); + + /* { dg-warning "use of floating point arithmetic inside the size argument might yield unexpected results" "warning" { target *-*-* } test_1 } */ + /* { dg-message "operand 'n' is of type 'float'" "note" { target *-*-* } test_1 } */ + /* { dg-message "only use operands of a type that represents whole numbers inside the size argument" "note" { target *-*-* } test_1 } */ +} + +void test_2 (int n) +{ + int *ptr = malloc (n * 3.1); /* { dg-line test_2 } */ + free (ptr); + + /* { dg-warning "use of floating point arithmetic inside the size argument might yield unexpected results" "warning" { target *-*-* } test_2 } */ + /* { dg-message "operand '\(\\d|e|f|\\.|\\+|\)+' is of type 'double'" "note" { target *-*-* } test_2 } */ + /* { dg-message "only use operands of a type that represents whole numbers inside the size argument" "note" { target *-*-* } test_2 } */ +} + +void *alloc_me (size_t size) +{ + return malloc (size); /* { dg-line test_3 } */ + + /* { dg-warning "use of floating point arithmetic inside the size argument might yield unexpected results" "warning" { target *-*-* } test_3 } */ + /* { dg-message "operand 'f' is of type 'float'" "note" { target *-*-* } test_3 } */ + /* { dg-message "only use operands of a type that represents whole numbers inside the size argument" "note" { target *-*-* } test_3 } */ +} + +void test_3 (float f) +{ + void *ptr = alloc_me (f); /* { dg-message "calling 'alloc_me' from 'test_3'" } */ + free (ptr); +} + +void test_4 (int n) +{ + int *ptr = calloc(1.7 * n, sizeof (int)); /* { dg-line test_4 } */ + free (ptr); + + /* { dg-warning "use of floating point arithmetic inside the size argument might yield unexpected results" "warning" { target *-*-* } test_4 } */ + /* { dg-message "operand '\(\\d|e|f|\\.|\\+|\)+' is of type 'double'" "note" { target *-*-* } test_4 } */ + /* { dg-message "only use operands of a type that represents whole numbers inside the size argument" "note" { target *-*-* } test_4 } */ +} + +int test_5 (float f) +{ + int *ptr = __builtin_alloca (sizeof (int) * f); /* { dg-line test_5 } */ + *ptr = 4; + return *ptr; + + /* { dg-warning "use of floating point arithmetic inside the size argument might yield unexpected results" "warning" { target *-*-* } test_5 } */ + /* { dg-message "operand 'f' is of type 'float'" "note" { target *-*-* } test_5 } */ + /* { dg-message "only use operands of a type that represents whole numbers inside the size argument" "note" { target *-*-* } test_5 } */ +} diff --git a/gcc/testsuite/gcc.dg/analyzer/pr106181.c b/gcc/testsuite/gcc.dg/analyzer/pr106181.c new file mode 100644 index 00000000000..af5b1cfdebc --- /dev/null +++ b/gcc/testsuite/gcc.dg/analyzer/pr106181.c @@ -0,0 +1,11 @@ +#include + +void * +foo (int x) +{ + return __builtin_calloc (x * 1.1, 1); /* { dg-line calloc } */ + + /* { dg-warning "use of floating point arithmetic inside the size argument might yield unexpected results" "warning" { target *-*-* } calloc } */ + /* { dg-message "operand '\(\\d|e|f|\\.|\\+|\)+' is of type 'double'" "note" { target *-*-* } calloc } */ + /* { dg-message "only use operands of a type that represents whole numbers inside the size argument" "note" { target *-*-* } calloc } */ +}