From patchwork Wed Aug 9 20:21:04 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: David Malcolm X-Patchwork-Id: 1819571 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=server2.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=p6pGuei9; dkim-atps=neutral Received: from server2.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 4RLhKV3Xgxz1yfl for ; Thu, 10 Aug 2023 06:21:34 +1000 (AEST) Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 6C25E3854830 for ; Wed, 9 Aug 2023 20:21:32 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 6C25E3854830 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gcc.gnu.org; s=default; t=1691612492; bh=hV1PWqZMNDxaM5zSud4FRFLcSdcG5PyJjlnjUw0keLo=; h=To:Cc:Subject:Date:List-Id:List-Unsubscribe:List-Archive: List-Post:List-Help:List-Subscribe:From:Reply-To:From; b=p6pGuei9hu4aVuvrV+kvQFeS9jprnRBhCsRXGKCy7tHv0ot/uaXbpebT3n4XCEbSX LxpL04/yfAyvYQ7HBZ0vZvhkVqoMXQOXD4zA8gam0clNHpNAYHxCSMmYY7/4bWP5Bz LOC99HlxMHBV6ibYKI2PvctQcLIKpnRCxo1DBw88= 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 8F4B13857357 for ; Wed, 9 Aug 2023 20:21:09 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 8F4B13857357 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-292-9gJ9OFumPz-5eN1DRdiWUQ-1; Wed, 09 Aug 2023 16:21:07 -0400 X-MC-Unique: 9gJ9OFumPz-5eN1DRdiWUQ-1 Received: from smtp.corp.redhat.com (int-mx03.intmail.prod.int.rdu2.redhat.com [10.11.54.3]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id F0B2E8011AD for ; Wed, 9 Aug 2023 20:21:06 +0000 (UTC) Received: from t14s.localdomain.com (unknown [10.22.18.185]) by smtp.corp.redhat.com (Postfix) with ESMTP id A78851121318; Wed, 9 Aug 2023 20:21:06 +0000 (UTC) To: gcc-patches@gcc.gnu.org Cc: David Malcolm Subject: [pushed] analyzer: remove default return value from region_model::on_call_pre Date: Wed, 9 Aug 2023 16:21:04 -0400 Message-Id: <20230809202104.1804417-1-dmalcolm@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.1 on 10.11.54.3 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com X-Spam-Status: No, score=-11.4 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_H4, 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.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" Previously, the code for simulating calls to external functions in region_model::on_call_pre wrote a default svalue to the LHS of the call statement, which could be further overwritten by known_function subclasses. Unfortunately, this led to messy hacks, such as when the default svalue was an allocation: the LHS would be written to with two different heap-allocated regions, requiring special-case cleanups to avoid the stray state from the first heap allocation leading to state explosions; see r14-3001-g021077b94741c9. The following patch eliminates this write of a default svalue to the LHS of callsite. Instead, all known_function implementations that have a return value are now responsible for set the LHS themselves. A new call_details::set_any_lhs_with_defaults function is provided to make it easy to get the old behavior. On working through the various known_function subclasses, I noticed that memset was using the default behavior. That patch updates this so that it's now known to return its first parameter. Cleaning this up eliminates various doubling of saved_diagnostics (e.g. for dubious_allocation_size) where it was generating a diagnostic for both writes to the LHS, deduplicating them to the first diagnostic (with the default LHS), and then failing to create a region_creation_event when emitting the diagnostic, leading to the fallback wording in dubious_allocation_size::describe_final_event, such as: (1) allocated 42 bytes and assigned to ‘int32_t *’ {aka ‘int *’} here; ‘sizeof (int32_t {aka int})’ is ‘4’ Without the double write to the LHS, it creates a region_creation_event, so we get the allocation and the assignment as two separate events in the diagnostic path, e.g.: (1) allocated 42 bytes here (2) assigned to ‘int32_t *’ {aka ‘int *’} here; ‘sizeof (int32_t {aka int})’ is ‘4’ Successfully bootstrapped & regrtested on x86_64-pc-linux-gnu. Pushed to trunk as r14-3114-g73da34a538ddc2. gcc/analyzer/ChangeLog: * analyzer.h (class pure_known_function_with_default_return): New subclass. * call-details.cc (const_fn_p): Move here from region-model.cc. (maybe_get_const_fn_result): Likewise. (get_result_size_in_bytes): Likewise. (call_details::set_any_lhs_with_defaults): New function, based on code in region_model::on_call_pre. * call-details.h (call_details::set_any_lhs_with_defaults): New decl. * diagnostic-manager.cc (diagnostic_manager::emit_saved_diagnostic): Log the index of the saved_diagnostic. * kf.cc (pure_known_function_with_default_return::impl_call_pre): New. (kf_memset::impl_call_pre): Set the LHS to the first param. (kf_putenv::impl_call_pre): Call cd.set_any_lhs_with_defaults. (kf_sprintf::impl_call_pre): Call cd.set_any_lhs_with_defaults. (class kf_stack_restore): Derive from pure_known_function_with_default_return. (class kf_stack_save): Likewise. (kf_strlen::impl_call_pre): Call cd.set_any_lhs_with_defaults. * region-model-reachability.cc (reachable_regions::handle_sval): Remove logic for symbolic regions for pointers. * region-model.cc (region_model::canonicalize): Remove purging of dynamic extents workaround for surplus values from region_model::on_call_pre's default LHS code. (const_fn_p): Move to call-details.cc. (maybe_get_const_fn_result): Likewise. (get_result_size_in_bytes): Likewise. (region_model::update_for_nonzero_return): Call cd.set_any_lhs_with_defaults. (region_model::on_call_pre): Remove the assignment to the LHS of a default return value, instead requiring all known_function implementations to write to any LHS of the call. Use cd.set_any_lhs_with_defaults on the non-kf paths. * sm-fd.cc (kf_socket::outcome_of_socket::update_model): Use cd.set_any_lhs_with_defaults when failing to get at fd state. (kf_bind::outcome_of_bind::update_model): Likewise. (kf_listen::outcome_of_listen::update_model): Likewise. (kf_accept::outcome_of_accept::update_model): Likewise. (kf_connect::outcome_of_connect::update_model): Likewise. (kf_read::impl_call_pre): Use cd.set_any_lhs_with_defaults. * sm-file.cc (class kf_stdio_output_fn): Derive from pure_known_function_with_default_return. (class kf_ferror): Likewise. (class kf_fileno): Likewise. (kf_fgets::impl_call_pre): Use cd.set_any_lhs_with_defaults. (kf_read::impl_call_pre): Likewise. (class kf_getc): Derive from pure_known_function_with_default_return. (class kf_getchar): Likewise. * varargs.cc (kf_va_arg::impl_call_pre): Use cd.set_any_lhs_with_defaults. gcc/testsuite/ChangeLog: * gcc.dg/analyzer/allocation-size-1.c: Update expected results to reflect splitting of allocation size and assignment messages from a single event into pairs of events * gcc.dg/analyzer/allocation-size-2.c: Likewise. * gcc.dg/analyzer/allocation-size-3.c: Likewise. * gcc.dg/analyzer/allocation-size-4.c: Likewise. * gcc.dg/analyzer/allocation-size-multiline-1.c: Likewise. * gcc.dg/analyzer/allocation-size-multiline-2.c: Likewise. * gcc.dg/analyzer/allocation-size-multiline-3.c: Likewise. * gcc.dg/analyzer/memset-1.c (test_1): Verify that the return value is the initial argument. * gcc.dg/plugin/analyzer_kernel_plugin.c (copy_across_boundary_fn::impl_call_pre): Ensure the LHS is set on the "known zero size" case. * gcc.dg/plugin/analyzer_known_fns_plugin.c (known_function_attempt_to_copy::impl_call_pre): Likewise. --- gcc/analyzer/analyzer.h | 10 ++ gcc/analyzer/call-details.cc | 129 +++++++++++++++ gcc/analyzer/call-details.h | 1 + gcc/analyzer/diagnostic-manager.cc | 3 +- gcc/analyzer/kf.cc | 18 +- gcc/analyzer/region-model-reachability.cc | 21 --- gcc/analyzer/region-model.cc | 156 ++---------------- gcc/analyzer/sm-fd.cc | 51 ++++-- gcc/analyzer/sm-file.cc | 14 +- gcc/analyzer/varargs.cc | 2 + .../gcc.dg/analyzer/allocation-size-1.c | 3 +- .../gcc.dg/analyzer/allocation-size-2.c | 3 +- .../gcc.dg/analyzer/allocation-size-3.c | 9 +- .../gcc.dg/analyzer/allocation-size-4.c | 6 +- .../analyzer/allocation-size-multiline-1.c | 12 +- .../analyzer/allocation-size-multiline-2.c | 15 +- .../analyzer/allocation-size-multiline-3.c | 10 +- gcc/testsuite/gcc.dg/analyzer/memset-1.c | 3 +- .../gcc.dg/plugin/analyzer_kernel_plugin.c | 7 +- .../gcc.dg/plugin/analyzer_known_fns_plugin.c | 7 +- 20 files changed, 266 insertions(+), 214 deletions(-) diff --git a/gcc/analyzer/analyzer.h b/gcc/analyzer/analyzer.h index 579517c23e6..93a28b4b5cf 100644 --- a/gcc/analyzer/analyzer.h +++ b/gcc/analyzer/analyzer.h @@ -293,6 +293,16 @@ public: } }; +/* Abstract subclass of known_function that merely sets the return + value of the function (based on function attributes), and assumes + it has no side-effects. */ + +class pure_known_function_with_default_return : public known_function +{ +public: + void impl_call_pre (const call_details &cd) const override; +}; + extern void register_known_functions (known_function_manager &mgr); extern void register_known_analyzer_functions (known_function_manager &kfm); extern void register_known_fd_functions (known_function_manager &kfm); diff --git a/gcc/analyzer/call-details.cc b/gcc/analyzer/call-details.cc index 793317eaa02..93f4846f674 100644 --- a/gcc/analyzer/call-details.cc +++ b/gcc/analyzer/call-details.cc @@ -105,6 +105,135 @@ call_details::maybe_set_lhs (const svalue *result) const return false; } +/* Return true if CD is known to be a call to a function with + __attribute__((const)). */ + +static bool +const_fn_p (const call_details &cd) +{ + tree fndecl = cd.get_fndecl_for_call (); + if (!fndecl) + return false; + gcc_assert (DECL_P (fndecl)); + return TREE_READONLY (fndecl); +} + +/* If this CD is known to be a call to a function with + __attribute__((const)), attempt to get a const_fn_result_svalue + based on the arguments, or return NULL otherwise. */ + +static const svalue * +maybe_get_const_fn_result (const call_details &cd) +{ + if (!const_fn_p (cd)) + return NULL; + + unsigned num_args = cd.num_args (); + if (num_args > const_fn_result_svalue::MAX_INPUTS) + /* Too many arguments. */ + return NULL; + + auto_vec inputs (num_args); + for (unsigned arg_idx = 0; arg_idx < num_args; arg_idx++) + { + const svalue *arg_sval = cd.get_arg_svalue (arg_idx); + if (!arg_sval->can_have_associated_state_p ()) + return NULL; + inputs.quick_push (arg_sval); + } + + region_model_manager *mgr = cd.get_manager (); + const svalue *sval + = mgr->get_or_create_const_fn_result_svalue (cd.get_lhs_type (), + cd.get_fndecl_for_call (), + inputs); + return sval; +} + +/* Look for attribute "alloc_size" on the called function and, if found, + return a symbolic value of type size_type_node for the allocation size + based on the call's parameters. + Otherwise, return null. */ + +static const svalue * +get_result_size_in_bytes (const call_details &cd) +{ + const tree attr = cd.lookup_function_attribute ("alloc_size"); + if (!attr) + return nullptr; + + const tree atval_1 = TREE_VALUE (attr); + if (!atval_1) + return nullptr; + + unsigned argidx1 = TREE_INT_CST_LOW (TREE_VALUE (atval_1)) - 1; + if (cd.num_args () <= argidx1) + return nullptr; + + const svalue *sval_arg1 = cd.get_arg_svalue (argidx1); + + if (const tree atval_2 = TREE_CHAIN (atval_1)) + { + /* Two arguments. */ + unsigned argidx2 = TREE_INT_CST_LOW (TREE_VALUE (atval_2)) - 1; + if (cd.num_args () <= argidx2) + return nullptr; + const svalue *sval_arg2 = cd.get_arg_svalue (argidx2); + /* TODO: ideally we shouldn't need this cast here; + see PR analyzer/110902. */ + return cd.get_manager ()->get_or_create_cast + (size_type_node, + cd.get_manager ()->get_or_create_binop (size_type_node, + MULT_EXPR, + sval_arg1, sval_arg2)); + } + else + /* Single argument. */ + return cd.get_manager ()->get_or_create_cast (size_type_node, sval_arg1); +} + +/* If this call has an LHS, assign a value to it based on attributes + of the function: + - if __attribute__((const)), use a const_fn_result_svalue, + - if __attribute__((malloc)), use a heap-allocated region with + unknown content + - otherwise, use a conjured_svalue. + + If __attribute__((alloc_size), set the dynamic extents on the region + pointed to. */ + +void +call_details::set_any_lhs_with_defaults () const +{ + if (!m_lhs_region) + return; + + const svalue *sval = maybe_get_const_fn_result (*this); + if (!sval) + { + region_model_manager *mgr = get_manager (); + if (lookup_function_attribute ("malloc")) + { + const region *new_reg + = m_model->get_or_create_region_for_heap_alloc (NULL, m_ctxt); + m_model->mark_region_as_unknown (new_reg, NULL); + sval = mgr->get_ptr_svalue (get_lhs_type (), new_reg); + } + else + /* For the common case of functions without __attribute__((const)), + use a conjured value, and purge any prior state involving that + value (in case this is in a loop). */ + sval = get_or_create_conjured_svalue (m_lhs_region); + if (const svalue *size_in_bytes = get_result_size_in_bytes (*this)) + { + const region *reg + = m_model->deref_rvalue (sval, NULL_TREE, m_ctxt, false); + m_model->set_dynamic_extents (reg, size_in_bytes, m_ctxt); + } + } + maybe_set_lhs (sval); +} + /* Return the number of arguments used by the call statement. */ unsigned diff --git a/gcc/analyzer/call-details.h b/gcc/analyzer/call-details.h index 25ea5546182..24be2247e63 100644 --- a/gcc/analyzer/call-details.h +++ b/gcc/analyzer/call-details.h @@ -41,6 +41,7 @@ public: const region *get_lhs_region () const { return m_lhs_region; } bool maybe_set_lhs (const svalue *result) const; + void set_any_lhs_with_defaults () const; unsigned num_args () const; bool arg_is_pointer_p (unsigned idx) const diff --git a/gcc/analyzer/diagnostic-manager.cc b/gcc/analyzer/diagnostic-manager.cc index cfca305d552..8bc84c82055 100644 --- a/gcc/analyzer/diagnostic-manager.cc +++ b/gcc/analyzer/diagnostic-manager.cc @@ -1372,7 +1372,8 @@ diagnostic_manager::emit_saved_diagnostic (const exploded_graph &eg, const saved_diagnostic &sd) { LOG_SCOPE (get_logger ()); - log ("sd: %qs at SN: %i", sd.m_d->get_kind (), sd.m_snode->m_index); + log ("sd[%i]: %qs at SN: %i", + sd.get_index (), sd.m_d->get_kind (), sd.m_snode->m_index); log ("num dupes: %i", sd.get_num_dupes ()); pretty_printer *pp = global_dc->printer->clone (); diff --git a/gcc/analyzer/kf.cc b/gcc/analyzer/kf.cc index 3e319a076bb..b9ee2e45c86 100644 --- a/gcc/analyzer/kf.cc +++ b/gcc/analyzer/kf.cc @@ -40,6 +40,15 @@ along with GCC; see the file COPYING3. If not see namespace ana { +/* class pure_known_function_with_default_return : public known_function. */ + +void +pure_known_function_with_default_return:: +impl_call_pre (const call_details &cd) const +{ + cd.set_any_lhs_with_defaults (); +} + /* Implementations of specific functions. */ /* Handler for "alloca". */ @@ -557,6 +566,8 @@ kf_memset::impl_call_pre (const call_details &cd) const nullptr, cd.get_ctxt ()); model->fill_region (sized_dest_reg, fill_value_u8); + + cd.maybe_set_lhs (dest_sval); } /* A subclass of pending_diagnostic for complaining about 'putenv' @@ -683,6 +694,7 @@ public: ctxt->warn (make_unique (fndecl, reg)); break; } + cd.set_any_lhs_with_defaults (); } }; @@ -1034,12 +1046,13 @@ public: = model->deref_rvalue (dst_ptr, cd.get_arg_tree (0), ctxt); const svalue *content = cd.get_or_create_conjured_svalue (dst_reg); model->set_value (dst_reg, content, ctxt); + cd.set_any_lhs_with_defaults (); } }; /* Handler for "__builtin_stack_restore". */ -class kf_stack_restore : public known_function +class kf_stack_restore : public pure_known_function_with_default_return { public: bool matches_call_types_p (const call_details &) const final override @@ -1052,7 +1065,7 @@ public: /* Handler for "__builtin_stack_save". */ -class kf_stack_save : public known_function +class kf_stack_save : public pure_known_function_with_default_return { public: bool matches_call_types_p (const call_details &) const final override @@ -1175,6 +1188,7 @@ kf_strlen::impl_call_pre (const call_details &cd) const } } /* Otherwise a conjured value. */ + cd.set_any_lhs_with_defaults (); } /* Handler for "strndup" and "__builtin_strndup". */ diff --git a/gcc/analyzer/region-model-reachability.cc b/gcc/analyzer/region-model-reachability.cc index 1c747e14eab..a5c12f49346 100644 --- a/gcc/analyzer/region-model-reachability.cc +++ b/gcc/analyzer/region-model-reachability.cc @@ -184,27 +184,6 @@ reachable_regions::handle_sval (const svalue *sval) } add (pointee, ptr_is_mutable); } - else if (sval->get_type () - && TREE_CODE (sval->get_type ()) == POINTER_TYPE - && sval->get_kind () == SK_CONJURED) - { - /* Also add symbolic regions for pointers, but only for conjured svalues - for the LHS of a stmt. Doing it for more leads to state explosions - on chains of calls to external functions, due to each conjured svalue - potentially being modified at each successive call, recursively. */ - const conjured_svalue *conjured_sval = (const conjured_svalue *)sval; - if (conjured_sval->lhs_value_p ()) - { - const region *pointee - = m_model->get_manager ()->get_symbolic_region (sval); - /* Use const-ness of pointer type to affect mutability. */ - bool ptr_is_mutable = true; - if (TYPE_READONLY (TREE_TYPE (sval->get_type ()))) - ptr_is_mutable = false; - add (pointee, ptr_is_mutable); - } - } - /* Treat all svalues within a compound_svalue as reachable. */ if (const compound_svalue *compound_sval = sval->dyn_cast_compound_svalue ()) diff --git a/gcc/analyzer/region-model.cc b/gcc/analyzer/region-model.cc index e92b3f7b074..094b7af3dbc 100644 --- a/gcc/analyzer/region-model.cc +++ b/gcc/analyzer/region-model.cc @@ -441,29 +441,6 @@ region_model::canonicalize () { m_store.canonicalize (m_mgr->get_store_manager ()); m_constraints->canonicalize (); - - if (!m_dynamic_extents.is_empty ()) - { - /* Purge any dynamic extents for regions that aren't referenced. - Normally these are eliminated when leaks are detected, but we - can also gain stray heap_allocated_regions that aren't seen - by the leak-detection code. This happens when - region_model::on_call_pre provides a default result for a - function with both attributes "malloc" and "alloc_size" that - also has a known_function implementation. - Purge dynamic extent information for such regions. */ - auto_bitmap referenced_base_region_ids; - get_referenced_base_regions (referenced_base_region_ids); - auto_vec purgable_dyn_extents; - for (auto iter : m_dynamic_extents) - { - const region *reg = iter.first; - if (!bitmap_bit_p (referenced_base_region_ids, reg->get_id ())) - purgable_dyn_extents.safe_push (reg); - } - for (auto reg : purgable_dyn_extents) - m_dynamic_extents.remove (reg); - } } /* Return true if this region_model is in canonical form. */ @@ -1304,51 +1281,6 @@ region_model::check_call_args (const call_details &cd) const cd.get_arg_svalue (arg_idx); } -/* Return true if CD is known to be a call to a function with - __attribute__((const)). */ - -static bool -const_fn_p (const call_details &cd) -{ - tree fndecl = cd.get_fndecl_for_call (); - if (!fndecl) - return false; - gcc_assert (DECL_P (fndecl)); - return TREE_READONLY (fndecl); -} - -/* If this CD is known to be a call to a function with - __attribute__((const)), attempt to get a const_fn_result_svalue - based on the arguments, or return NULL otherwise. */ - -static const svalue * -maybe_get_const_fn_result (const call_details &cd) -{ - if (!const_fn_p (cd)) - return NULL; - - unsigned num_args = cd.num_args (); - if (num_args > const_fn_result_svalue::MAX_INPUTS) - /* Too many arguments. */ - return NULL; - - auto_vec inputs (num_args); - for (unsigned arg_idx = 0; arg_idx < num_args; arg_idx++) - { - const svalue *arg_sval = cd.get_arg_svalue (arg_idx); - if (!arg_sval->can_have_associated_state_p ()) - return NULL; - inputs.quick_push (arg_sval); - } - - region_model_manager *mgr = cd.get_manager (); - const svalue *sval - = mgr->get_or_create_const_fn_result_svalue (cd.get_lhs_type (), - cd.get_fndecl_for_call (), - inputs); - return sval; -} - /* Update this model for an outcome of a call that returns a specific integer constant. If UNMERGEABLE, then make the result unmergeable, e.g. to prevent @@ -1381,7 +1313,9 @@ region_model::update_for_zero_return (const call_details &cd, update_for_int_cst_return (cd, 0, unmergeable); } -/* Update this model for an outcome of a call that returns non-zero. */ +/* Update this model for an outcome of a call that returns non-zero. + Specifically, assign an svalue to the LHS, and add a constraint that + that svalue is non-zero. */ void region_model::update_for_nonzero_return (const call_details &cd) @@ -1390,6 +1324,7 @@ region_model::update_for_nonzero_return (const call_details &cd) return; if (TREE_CODE (cd.get_lhs_type ()) != INTEGER_TYPE) return; + cd.set_any_lhs_with_defaults (); const svalue *zero = m_mgr->get_or_create_int_cst (cd.get_lhs_type (), 0); const svalue *result @@ -1485,48 +1420,6 @@ region_model::get_known_function (enum internal_fn ifn) const return known_fn_mgr->get_internal_fn (ifn); } -/* Look for attribute "alloc_size" on the called function and, if found, - return a symbolic value of type size_type_node for the allocation size - based on the call's parameters. - Otherwise, return null. */ - -static const svalue * -get_result_size_in_bytes (const call_details &cd) -{ - const tree attr = cd.lookup_function_attribute ("alloc_size"); - if (!attr) - return nullptr; - - const tree atval_1 = TREE_VALUE (attr); - if (!atval_1) - return nullptr; - - unsigned argidx1 = TREE_INT_CST_LOW (TREE_VALUE (atval_1)) - 1; - if (cd.num_args () <= argidx1) - return nullptr; - - const svalue *sval_arg1 = cd.get_arg_svalue (argidx1); - - if (const tree atval_2 = TREE_CHAIN (atval_1)) - { - /* Two arguments. */ - unsigned argidx2 = TREE_INT_CST_LOW (TREE_VALUE (atval_2)) - 1; - if (cd.num_args () <= argidx2) - return nullptr; - const svalue *sval_arg2 = cd.get_arg_svalue (argidx2); - /* TODO: ideally we shouldn't need this cast here; - see PR analyzer/110902. */ - return cd.get_manager ()->get_or_create_cast - (size_type_node, - cd.get_manager ()->get_or_create_binop (size_type_node, - MULT_EXPR, - sval_arg1, sval_arg2)); - } - else - /* Single argument. */ - return cd.get_manager ()->get_or_create_cast (size_type_node, sval_arg1); -} - /* Update this model for the CALL stmt, using CTXT to report any diagnostics - the first half. @@ -1562,40 +1455,6 @@ region_model::on_call_pre (const gcall *call, region_model_context *ctxt) tree callee_fndecl = get_fndecl_for_call (call, ctxt); - /* Some of the cases below update the lhs of the call based on the - return value, but not all. Provide a default value, which may - get overwritten below. */ - if (tree lhs = gimple_call_lhs (call)) - { - const region *lhs_region = get_lvalue (lhs, ctxt); - const svalue *sval = maybe_get_const_fn_result (cd); - if (!sval) - { - if (callee_fndecl - && lookup_attribute ("malloc", DECL_ATTRIBUTES (callee_fndecl))) - { - const region *new_reg - = get_or_create_region_for_heap_alloc (NULL, ctxt); - mark_region_as_unknown (new_reg, NULL); - sval = m_mgr->get_ptr_svalue (cd.get_lhs_type (), new_reg); - } - else - /* For the common case of functions without __attribute__((const)), - use a conjured value, and purge any prior state involving that - value (in case this is in a loop). */ - sval = m_mgr->get_or_create_conjured_svalue (TREE_TYPE (lhs), call, - lhs_region, - conjured_purge (this, - ctxt)); - if (const svalue *size_in_bytes = get_result_size_in_bytes (cd)) - { - const region *reg = deref_rvalue (sval, NULL_TREE, ctxt, false); - set_dynamic_extents (reg, size_in_bytes, ctxt); - } - } - set_value (lhs_region, sval, ctxt); - } - if (gimple_call_internal_p (call)) if (const known_function *kf = get_known_function (gimple_call_internal_fn (call))) @@ -1605,7 +1464,10 @@ region_model::on_call_pre (const gcall *call, region_model_context *ctxt) } if (!callee_fndecl) - return true; /* Unknown side effects. */ + { + cd.set_any_lhs_with_defaults (); + return true; /* Unknown side effects. */ + } if (const known_function *kf = get_known_function (callee_fndecl, cd)) { @@ -1613,6 +1475,8 @@ region_model::on_call_pre (const gcall *call, region_model_context *ctxt) return false; /* No further side effects. */ } + cd.set_any_lhs_with_defaults (); + const int callee_fndecl_flags = flags_from_decl_or_type (callee_fndecl); if (callee_fndecl_flags & (ECF_CONST | ECF_PURE)) return false; /* No side effects. */ diff --git a/gcc/analyzer/sm-fd.cc b/gcc/analyzer/sm-fd.cc index 03ad3598a3c..c75744ff63a 100644 --- a/gcc/analyzer/sm-fd.cc +++ b/gcc/analyzer/sm-fd.cc @@ -2282,10 +2282,16 @@ public: const fd_state_machine *fd_sm; std::unique_ptr sm_ctxt; if (!get_fd_state (ctxt, &smap, &fd_sm, NULL, &sm_ctxt)) - return true; + { + cd.set_any_lhs_with_defaults (); + return true; + } const extrinsic_state *ext_state = ctxt->get_ext_state (); if (!ext_state) - return true; + { + cd.set_any_lhs_with_defaults (); + return true; + } return fd_sm->on_socket (cd, m_success, sm_ctxt.get (), *ext_state); } @@ -2329,10 +2335,16 @@ public: const fd_state_machine *fd_sm; std::unique_ptr sm_ctxt; if (!get_fd_state (ctxt, &smap, &fd_sm, NULL, &sm_ctxt)) - return true; + { + cd.set_any_lhs_with_defaults (); + return true; + } const extrinsic_state *ext_state = ctxt->get_ext_state (); if (!ext_state) - return true; + { + cd.set_any_lhs_with_defaults (); + return true; + } return fd_sm->on_bind (cd, m_success, sm_ctxt.get (), *ext_state); } }; @@ -2374,10 +2386,16 @@ class kf_listen : public known_function const fd_state_machine *fd_sm; std::unique_ptr sm_ctxt; if (!get_fd_state (ctxt, &smap, &fd_sm, NULL, &sm_ctxt)) - return true; + { + cd.set_any_lhs_with_defaults (); + return true; + } const extrinsic_state *ext_state = ctxt->get_ext_state (); if (!ext_state) - return true; + { + cd.set_any_lhs_with_defaults (); + return true; + } return fd_sm->on_listen (cd, m_success, sm_ctxt.get (), *ext_state); } @@ -2420,10 +2438,16 @@ class kf_accept : public known_function const fd_state_machine *fd_sm; std::unique_ptr sm_ctxt; if (!get_fd_state (ctxt, &smap, &fd_sm, NULL, &sm_ctxt)) - return true; + { + cd.set_any_lhs_with_defaults (); + return true; + } const extrinsic_state *ext_state = ctxt->get_ext_state (); if (!ext_state) - return true; + { + cd.set_any_lhs_with_defaults (); + return true; + } return fd_sm->on_accept (cd, m_success, sm_ctxt.get (), *ext_state); } @@ -2469,10 +2493,16 @@ public: const fd_state_machine *fd_sm; std::unique_ptr sm_ctxt; if (!get_fd_state (ctxt, &smap, &fd_sm, NULL, &sm_ctxt)) - return true; + { + cd.set_any_lhs_with_defaults (); + return true; + } const extrinsic_state *ext_state = ctxt->get_ext_state (); if (!ext_state) - return true; + { + cd.set_any_lhs_with_defaults (); + return true; + } return fd_sm->on_connect (cd, m_success, sm_ctxt.get (), *ext_state); } @@ -2687,6 +2717,7 @@ public: const svalue *new_sval = cd.get_or_create_conjured_svalue (base_reg); model->set_value (base_reg, new_sval, cd.get_ctxt ()); } + cd.set_any_lhs_with_defaults (); } }; diff --git a/gcc/analyzer/sm-file.cc b/gcc/analyzer/sm-file.cc index 0cfe6821722..0252b3922d4 100644 --- a/gcc/analyzer/sm-file.cc +++ b/gcc/analyzer/sm-file.cc @@ -494,7 +494,7 @@ make_fileptr_state_machine (logger *logger) effects that are out of scope for the analyzer: we only want to model the effects on the return value. */ -class kf_stdio_output_fn : public known_function +class kf_stdio_output_fn : public pure_known_function_with_default_return { public: bool matches_call_types_p (const call_details &) const final override @@ -507,7 +507,7 @@ public: /* Handler for "ferror"". */ -class kf_ferror : public known_function +class kf_ferror : public pure_known_function_with_default_return { public: bool matches_call_types_p (const call_details &cd) const final override @@ -521,7 +521,7 @@ public: /* Handler for "fileno"". */ -class kf_fileno : public known_function +class kf_fileno : public pure_known_function_with_default_return { public: bool matches_call_types_p (const call_details &cd) const final override @@ -557,6 +557,7 @@ public: const svalue *new_sval = cd.get_or_create_conjured_svalue (base_reg); model->set_value (base_reg, new_sval, cd.get_ctxt ()); } + cd.set_any_lhs_with_defaults (); } }; @@ -592,12 +593,13 @@ public: const svalue *new_sval = cd.get_or_create_conjured_svalue (base_reg); model->set_value (base_reg, new_sval, cd.get_ctxt ()); } + cd.set_any_lhs_with_defaults (); } }; /* Handler for "getc"". */ -class kf_getc : public known_function +class kf_getc : public pure_known_function_with_default_return { public: bool matches_call_types_p (const call_details &cd) const final override @@ -605,13 +607,11 @@ public: return (cd.num_args () == 1 && cd.arg_is_pointer_p (0)); } - - /* No side effects. */ }; /* Handler for "getchar"". */ -class kf_getchar : public known_function +class kf_getchar : public pure_known_function_with_default_return { public: bool matches_call_types_p (const call_details &cd) const final override diff --git a/gcc/analyzer/varargs.cc b/gcc/analyzer/varargs.cc index 72e1b31601c..f79b2a7d7b5 100644 --- a/gcc/analyzer/varargs.cc +++ b/gcc/analyzer/varargs.cc @@ -1007,6 +1007,8 @@ kf_va_arg::impl_call_pre (const call_details &cd) const tree va_list_tree = get_va_list_diag_arg (cd.get_arg_tree (0)); ap_sval = model->check_for_poison (ap_sval, va_list_tree, ap_reg, ctxt); + cd.set_any_lhs_with_defaults (); + if (const region *impl_reg = ap_sval->maybe_get_region ()) { const svalue *old_impl_sval = model->get_store_value (impl_reg, ctxt); diff --git a/gcc/testsuite/gcc.dg/analyzer/allocation-size-1.c b/gcc/testsuite/gcc.dg/analyzer/allocation-size-1.c index dcffc1175cf..003914ed96c 100644 --- a/gcc/testsuite/gcc.dg/analyzer/allocation-size-1.c +++ b/gcc/testsuite/gcc.dg/analyzer/allocation-size-1.c @@ -16,7 +16,8 @@ void test_2 (void) free (ptr); /* { dg-warning "allocated buffer size is not a multiple of the pointee's size \\\[CWE-131\\\]" "warning" { target *-*-* } malloc2 } */ - /* { dg-message "allocated 42 bytes and assigned to 'int32_t \\*' (\\\{aka '(long )?int \\*'\\\})? here; 'sizeof \\(int32_t (\\\{aka (long )?int\\\})?\\)' is '4'" "note" { target *-*-* } malloc2 } */ + /* { dg-message "42 bytes" "note" { target *-*-* } malloc2 } */ + /* { dg-message "'int32_t \\*' (\\\{aka '(long )?int \\*'\\\})? here; 'sizeof \\(int32_t (\\\{aka (long )?int\\\})?\\)' is '4'" "note" { target *-*-* } malloc2 } */ } void test_3 (void) diff --git a/gcc/testsuite/gcc.dg/analyzer/allocation-size-2.c b/gcc/testsuite/gcc.dg/analyzer/allocation-size-2.c index d26c2672531..eb770f73d4a 100644 --- a/gcc/testsuite/gcc.dg/analyzer/allocation-size-2.c +++ b/gcc/testsuite/gcc.dg/analyzer/allocation-size-2.c @@ -19,7 +19,8 @@ void test_2 (int32_t n) free (ptr); /* { dg-warning "allocated buffer size is not a multiple of the pointee's size \\\[CWE-131\\\]" "warning" { target *-*-* } malloc2 } */ - /* { dg-message "allocated '\[a-z0-9\\*\\(\\)\\s\]*' bytes and assigned to 'int32_t \\*' (\\\{aka '(long )?int \\*'\\\})? here; 'sizeof \\(int32_t (\\\{aka (long )?int\\\})?\\)' is '4" "note" { target *-*-* } malloc2 } */ + /* { dg-message "'\[a-z0-9\\*\\(\\)\\s\]*' bytes" "note" { target *-*-* } malloc2 } */ + /* { dg-message "'int32_t \\*' (\\\{aka '(long )?int \\*'\\\})? here; 'sizeof \\(int32_t (\\\{aka (long )?int\\\})?\\)' is '4" "note" { target *-*-* } malloc2 } */ } void test_3 (int32_t n) diff --git a/gcc/testsuite/gcc.dg/analyzer/allocation-size-3.c b/gcc/testsuite/gcc.dg/analyzer/allocation-size-3.c index 6b753073008..6751441dd18 100644 --- a/gcc/testsuite/gcc.dg/analyzer/allocation-size-3.c +++ b/gcc/testsuite/gcc.dg/analyzer/allocation-size-3.c @@ -20,7 +20,8 @@ void test_1 (void) free (id_sequence); /* { dg-warning "allocated buffer size is not a multiple of the pointee's size \\\[CWE-131\\\]" "warning" { target *-*-* } malloc1 } */ - /* { dg-message "allocated 3 bytes and assigned to 'int32_t \\*' (\\\{aka '(long )?int \\*'\\\})? here; 'sizeof \\(int32_t (\\\{aka (long )?int\\\})?\\)' is '4'" "note" { target *-*-* } malloc1 } */ + /* { dg-message "3 bytes" "note" { target *-*-* } malloc1 } */ + /* { dg-message "'int32_t \\*' (\\\{aka '(long )?int \\*'\\\})? here; 'sizeof \\(int32_t (\\\{aka (long )?int\\\})?\\)' is '4'" "note" { target *-*-* } malloc1 } */ } void test_2 (void) @@ -29,7 +30,8 @@ void test_2 (void) free (ptr); /* { dg-warning "allocated buffer size is not a multiple of the pointee's size \\\[CWE-131\\\]" "warning" { target *-*-* } malloc2 } */ - /* { dg-message "allocated 14 bytes and assigned to 'int32_t \\*' (\\\{aka '(long )?int \\*'\\\})? here; 'sizeof \\(int32_t (\\\{aka (long )?int\\\})?\\)' is '4'" "note" { target *-*-* } malloc2 } */ + /* { dg-message "14 bytes" "note" { target *-*-* } malloc2 } */ + /* { dg-message "'int32_t \\*' (\\\{aka '(long )?int \\*'\\\})? here; 'sizeof \\(int32_t (\\\{aka (long )?int\\\})?\\)' is '4'" "note" { target *-*-* } malloc2 } */ } void test_3 (int32_t n) @@ -38,7 +40,8 @@ void test_3 (int32_t n) free (ptr); /* { dg-warning "allocated buffer size is not a multiple of the pointee's size \\\[CWE-131\\\]" "warning" { target *-*-* } malloc3 } */ - /* { dg-message "allocated '\[a-z0-9\\+\\(\\)\\s\]*' bytes and assigned to 'int32_t \\*' (\\\{aka '(long )?int \\*'\\\})? here; 'sizeof \\(int32_t (\\\{aka (long )?int\\\})?\\)' is '4'" "note" { target *-*-* } malloc3 } */ + /* { dg-message "'\[a-z0-9\\+\\(\\)\\s\]*' bytes" "note" { target *-*-* } malloc3 } */ + /* { dg-message "'int32_t \\*' (\\\{aka '(long )?int \\*'\\\})? here; 'sizeof \\(int32_t (\\\{aka (long )?int\\\})?\\)' is '4'" "note" { target *-*-* } malloc3 } */ } void test_4 (int32_t n, int32_t m) diff --git a/gcc/testsuite/gcc.dg/analyzer/allocation-size-4.c b/gcc/testsuite/gcc.dg/analyzer/allocation-size-4.c index 642e8f5f496..a56b25b4374 100644 --- a/gcc/testsuite/gcc.dg/analyzer/allocation-size-4.c +++ b/gcc/testsuite/gcc.dg/analyzer/allocation-size-4.c @@ -30,7 +30,8 @@ void test_2 (void) free (ptr); /* { dg-warning "allocated buffer size is not a multiple of the pointee's size \\\[CWE-131\\\]" "warning" { target *-*-* } malloc2 } */ - /* { dg-message "allocated \\d+ bytes and assigned to 'int32_t \\*' (\\\{aka '(long )?int \\*'\\\})? here; 'sizeof \\(int32_t (\\\{aka (long )?int\\\})?\\)' is '4'" "note" { target *-*-* } malloc2 } */ + /* { dg-message "\\d+ bytes" "note" { target *-*-* } malloc2 } */ + /* { dg-message "'int32_t \\*' (\\\{aka '(long )?int \\*'\\\})? here; 'sizeof \\(int32_t (\\\{aka (long )?int\\\})?\\)' is '4'" "note" { target *-*-* } malloc2 } */ } void test_3 (void) @@ -55,5 +56,6 @@ void test_5 (void) free (ptr); /* { dg-warning "allocated buffer size is not a multiple of the pointee's size \\\[CWE-131\\\]" "warning" { target *-*-* } malloc5 } */ - /* { dg-message "allocated 1 bytes and assigned to 'struct base \\*' here; 'sizeof \\(struct base\\)' is '\\d+'" "note" { target *-*-* } malloc5 } */ + /* { dg-message "allocated 1 byte here" "note" { target *-*-* } malloc5 } */ + /* { dg-message "'struct base \\*' here; 'sizeof \\(struct base\\)' is '\\d+'" "note" { target *-*-* } malloc5 } */ } diff --git a/gcc/testsuite/gcc.dg/analyzer/allocation-size-multiline-1.c b/gcc/testsuite/gcc.dg/analyzer/allocation-size-multiline-1.c index 9938ba237a0..7251665105d 100644 --- a/gcc/testsuite/gcc.dg/analyzer/allocation-size-multiline-1.c +++ b/gcc/testsuite/gcc.dg/analyzer/allocation-size-multiline-1.c @@ -11,12 +11,13 @@ void test_constant_1 (void) /* { dg-begin-multiline-output "" } int32_t *ptr = __builtin_malloc (1); ^~~~~~~~~~~~~~~~~~~~ - 'test_constant_1': event 1 + 'test_constant_1': events 1-2 | | int32_t *ptr = __builtin_malloc (1); | ^~~~~~~~~~~~~~~~~~~~ | | - | (1) allocated 1 bytes and assigned to 'int32_t *' {aka 'int *'} here; 'sizeof (int32_t {aka int})' is '4' + | (1) allocated 1 byte here + | (2) assigned to 'int32_t *' | { dg-end-multiline-output "" } */ @@ -29,12 +30,13 @@ void test_constant_2 (void) /* { dg-begin-multiline-output "" } int32_t *ptr = __builtin_malloc (2); ^~~~~~~~~~~~~~~~~~~~ - 'test_constant_2': event 1 + 'test_constant_2': events 1-2 | | int32_t *ptr = __builtin_malloc (2); | ^~~~~~~~~~~~~~~~~~~~ | | - | (1) allocated 2 bytes and assigned to 'int32_t *' {aka 'int *'} here; 'sizeof (int32_t {aka int})' is '4' + | (1) allocated 2 bytes here + | (2) assigned to 'int32_t *' | { dg-end-multiline-output "" } */ @@ -52,6 +54,6 @@ void test_symbolic (int n) | int32_t *ptr = __builtin_malloc (n * 2); | ^~~~~~~~~~~~~~~~~~~~~~~~ | | - | (1) allocated 'n * 2' bytes and assigned to 'int32_t *' {aka 'int *'} here; 'sizeof (int32_t {aka int})' is '4' + | (1) allocated 'n * 2' bytes and assigned to 'int32_t *' | { dg-end-multiline-output "" } */ diff --git a/gcc/testsuite/gcc.dg/analyzer/allocation-size-multiline-2.c b/gcc/testsuite/gcc.dg/analyzer/allocation-size-multiline-2.c index 9e1269cbb7a..7cadbb74751 100644 --- a/gcc/testsuite/gcc.dg/analyzer/allocation-size-multiline-2.c +++ b/gcc/testsuite/gcc.dg/analyzer/allocation-size-multiline-2.c @@ -11,12 +11,13 @@ void test_constant_1 (void) /* { dg-begin-multiline-output "" } int32_t *ptr = __builtin_alloca (1); ^~~~~~~~~~~~~~~~~~~~ - 'test_constant_1': event 1 + 'test_constant_1': events 1-2 | | int32_t *ptr = __builtin_alloca (1); | ^~~~~~~~~~~~~~~~~~~~ | | - | (1) allocated 1 bytes and assigned to 'int32_t *' {aka 'int *'} here; 'sizeof (int32_t {aka int})' is '4' + | (1) allocated 1 byte here + | (2) assigned to 'int32_t *' | { dg-end-multiline-output "" } */ @@ -28,12 +29,13 @@ void test_constant_2 (void) /* { dg-begin-multiline-output "" } int32_t *ptr = __builtin_alloca (2); ^~~~~~~~~~~~~~~~~~~~ - 'test_constant_2': event 1 + 'test_constant_2': events 1-2 | | int32_t *ptr = __builtin_alloca (2); | ^~~~~~~~~~~~~~~~~~~~ | | - | (1) allocated 2 bytes and assigned to 'int32_t *' {aka 'int *'} here; 'sizeof (int32_t {aka int})' is '4' + | (1) allocated 2 bytes here + | (2) assigned to 'int32_t *' | { dg-end-multiline-output "" } */ @@ -45,12 +47,13 @@ void test_symbolic (int n) /* { dg-begin-multiline-output "" } int32_t *ptr = __builtin_alloca (n * 2); ^~~~~~~~~~~~~~~~~~~~~~~~ - 'test_symbolic': event 1 + 'test_symbolic': events 1-2 | | int32_t *ptr = __builtin_alloca (n * 2); | ^~~~~~~~~~~~~~~~~~~~~~~~ | | - | (1) allocated 'n * 2' bytes and assigned to 'int32_t *' {aka 'int *'} here; 'sizeof (int32_t {aka int})' is '4' + | (1) allocated 'n * 2' bytes here + | (2) assigned to 'int32_t *' | { dg-end-multiline-output "" } */ diff --git a/gcc/testsuite/gcc.dg/analyzer/allocation-size-multiline-3.c b/gcc/testsuite/gcc.dg/analyzer/allocation-size-multiline-3.c index 71790d91753..b3de582368f 100644 --- a/gcc/testsuite/gcc.dg/analyzer/allocation-size-multiline-3.c +++ b/gcc/testsuite/gcc.dg/analyzer/allocation-size-multiline-3.c @@ -15,12 +15,13 @@ void test_constant_99 (void) /* { dg-begin-multiline-output "" } int32_t *ptr = alloca (99); ^~~~~~ - 'test_constant_99': event 1 + 'test_constant_99': events 1-2 | | int32_t *ptr = alloca (99); | ^~~~~~ | | - | (1) allocated 99 bytes and assigned to 'int32_t *' {aka 'int *'} here; 'sizeof (int32_t {aka int})' is '4' + | (1) allocated 99 bytes here + | (2) assigned to 'int32_t *' {aka '{re:long :re?}int *'} here; 'sizeof (int32_t {aka {re:long :re?}int})' is '4' | { dg-end-multiline-output "" } */ @@ -32,11 +33,12 @@ void test_symbolic (int n) /* { dg-begin-multiline-output "" } int32_t *ptr = alloca (n * 2); ^~~~~~ - 'test_symbolic': event 1 + 'test_symbolic': events 1-2 | | int32_t *ptr = alloca (n * 2); | ^~~~~~ | | - | (1) allocated 'n * 2' bytes and assigned to 'int32_t *' {aka 'int *'} here; 'sizeof (int32_t {aka int})' is '4' + | (1) allocated 'n * 2' bytes here + | (2) assigned to 'int32_t *' {aka '{re:long :re?}int *'} here; 'sizeof (int32_t {aka {re:long :re?}int})' is '4' | { dg-end-multiline-output "" } */ diff --git a/gcc/testsuite/gcc.dg/analyzer/memset-1.c b/gcc/testsuite/gcc.dg/analyzer/memset-1.c index 94c5a1b7c92..75aef53d348 100644 --- a/gcc/testsuite/gcc.dg/analyzer/memset-1.c +++ b/gcc/testsuite/gcc.dg/analyzer/memset-1.c @@ -6,8 +6,9 @@ void test_1 (void) { char buf[256]; - memset (buf, 0, 256); + void *p = memset (buf, 0, 256); __analyzer_eval (buf[42] == 0); /* { dg-warning "TRUE" } */ + __analyzer_eval (p == buf); /* { dg-warning "TRUE" } */ } /* As above, but with __builtin_memset. */ diff --git a/gcc/testsuite/gcc.dg/plugin/analyzer_kernel_plugin.c b/gcc/testsuite/gcc.dg/plugin/analyzer_kernel_plugin.c index 57bccf4f2eb..02dba7a3234 100644 --- a/gcc/testsuite/gcc.dg/plugin/analyzer_kernel_plugin.c +++ b/gcc/testsuite/gcc.dg/plugin/analyzer_kernel_plugin.c @@ -86,8 +86,11 @@ class copy_across_boundary_fn : public known_function if (tree cst = num_bytes_sval->maybe_get_constant ()) if (zerop (cst)) - /* No-op. */ - return; + { + /* No-op. */ + model->update_for_zero_return (cd, true); + return; + } const region *sized_src_reg = mgr->get_sized_region (src_reg, NULL_TREE, diff --git a/gcc/testsuite/gcc.dg/plugin/analyzer_known_fns_plugin.c b/gcc/testsuite/gcc.dg/plugin/analyzer_known_fns_plugin.c index de887dbad83..806cb90ef56 100644 --- a/gcc/testsuite/gcc.dg/plugin/analyzer_known_fns_plugin.c +++ b/gcc/testsuite/gcc.dg/plugin/analyzer_known_fns_plugin.c @@ -147,8 +147,11 @@ public: if (tree cst = num_bytes_sval->maybe_get_constant ()) if (zerop (cst)) - /* No-op. */ - return; + { + /* No-op. */ + cd.set_any_lhs_with_defaults (); + return; + } const region *sized_src_reg = mgr->get_sized_region (src_reg, NULL_TREE,