public inbox for gcc-cvs@sourceware.org
help / color / mirror / Atom feed
* [gcc r14-3114] analyzer: remove default return value from region_model::on_call_pre
@ 2023-08-09 20:18 David Malcolm
  0 siblings, 0 replies; only message in thread
From: David Malcolm @ 2023-08-09 20:18 UTC (permalink / raw)
  To: gcc-cvs

https://gcc.gnu.org/g:73da34a538ddc2ad17e80e93b64b526f704693d2

commit r14-3114-g73da34a538ddc2ad17e80e93b64b526f704693d2
Author: David Malcolm <dmalcolm@redhat.com>
Date:   Wed Aug 9 16:17:04 2023 -0400

    analyzer: remove default return value from region_model::on_call_pre
    
    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’
    
    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.
    
    Signed-off-by: David Malcolm <dmalcolm@redhat.com>

Diff:
---
 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/testsuite/gcc.dg/analyzer/allocation-size-1.c  |   3 +-
 gcc/testsuite/gcc.dg/analyzer/allocation-size-2.c  |   3 +-
 gcc/testsuite/gcc.dg/analyzer/allocation-size-3.c  |   9 +-
 gcc/testsuite/gcc.dg/analyzer/allocation-size-4.c  |   6 +-
 .../gcc.dg/analyzer/allocation-size-multiline-1.c  |  12 +-
 .../gcc.dg/analyzer/allocation-size-multiline-2.c  |  15 +-
 .../gcc.dg/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 579517c23e61..93a28b4b5cff 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 793317eaa026..93f4846f674d 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<const svalue *> 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 25ea55461825..24be2247e63a 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 cfca305d5528..8bc84c820559 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 3e319a076bbd..b9ee2e45c86a 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<putenv_of_auto_var> (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 1c747e14eabe..a5c12f493460 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 e92b3f7b074e..094b7af3dbc6 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<const region *> 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<const svalue *> 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 03ad3598a3cd..c75744ff63a9 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_context> 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_context> 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_context> 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_context> 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_context> 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 0cfe68217229..0252b3922d42 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 72e1b31601cd..f79b2a7d7b51 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 dcffc1175cf8..003914ed96cd 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 d26c2672531b..eb770f73d4a4 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 6b753073008e..6751441dd18f 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 642e8f5f4967..a56b25b4374d 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 9938ba237a08..7251665105db 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 9e1269cbb7a5..7cadbb747516 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 71790d91753b..b3de582368fc 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 94c5a1b7c920..75aef53d3487 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 57bccf4f2eb5..02dba7a3234d 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 de887dbad837..806cb90ef56a 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,

^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2023-08-09 20:18 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-08-09 20:18 [gcc r14-3114] analyzer: remove default return value from region_model::on_call_pre David Malcolm

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).