From 56b2fdf13c40ff121e82d683e356ff5c2c99ef0e Mon Sep 17 00:00:00 2001
From: David Malcolm <dmalcolm@redhat.com>
Date: Fri, 27 Mar 2026 11:23:24 -0400
Subject: [PATCH 41/98] FIXME: redo move of infoleak stuff to its own file
 (breaks plugin tests)

---
 gcc/Makefile.in                       |   1 +
 gcc/analyzer/region-model-infoleak.cc | 478 ++++++++++++++++++++++++++
 gcc/analyzer/region-model.cc          | 445 ------------------------
 3 files changed, 479 insertions(+), 445 deletions(-)
 create mode 100644 gcc/analyzer/region-model-infoleak.cc

diff --git a/gcc/Makefile.in b/gcc/Makefile.in
index ea2d43ce87b5..92c71cbdba26 100644
--- a/gcc/Makefile.in
+++ b/gcc/Makefile.in
@@ -1372,6 +1372,7 @@ ANALYZER_OBJS = \
 	analyzer/region.o \
 	analyzer/region-model.o \
 	analyzer/region-model-asm.o \
+	analyzer/region-model-infoleak.o \
 	analyzer/region-model-manager.o \
 	analyzer/region-model-reachability.o \
 	analyzer/setjmp-longjmp.o \
diff --git a/gcc/analyzer/region-model-infoleak.cc b/gcc/analyzer/region-model-infoleak.cc
new file mode 100644
index 000000000000..71cb11a039c0
--- /dev/null
+++ b/gcc/analyzer/region-model-infoleak.cc
@@ -0,0 +1,478 @@
+/* Implementation of region_model::maybe_complain_about_infoleak
+   Copyright (C) 2022-2026 Free Software Foundation, Inc.
+   Contributed by David Malcolm <dmalcolm@redhat.com>.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 3, or (at your option)
+any later version.
+
+GCC is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+
+#include "analyzer/common.h"
+
+#include "gcc-rich-location.h"
+
+#include "analyzer/region-model.h"
+#include "diagnostics/sarif-sink.h"
+#include "analyzer/record-layout.h"
+
+#if ENABLE_ANALYZER
+
+namespace ana {
+
+/* A subclass of pending_diagnostic for complaining about uninitialized data
+   being copied across a trust boundary to an untrusted output
+   (e.g. copy_to_user infoleaks in the Linux kernel).  */
+
+class exposure_through_uninit_copy
+  : public pending_diagnostic_subclass<exposure_through_uninit_copy>
+{
+public:
+  exposure_through_uninit_copy (const region *src_region,
+				const region *dest_region,
+				const svalue *copied_sval)
+  : m_src_region (src_region),
+    m_dest_region (dest_region),
+    m_copied_sval (copied_sval)
+  {
+    gcc_assert (m_copied_sval->get_kind () == SK_POISONED
+		|| m_copied_sval->get_kind () == SK_COMPOUND);
+  }
+
+  const char *get_kind () const final override
+  {
+    return "exposure_through_uninit_copy";
+  }
+
+  bool operator== (const exposure_through_uninit_copy &other) const
+  {
+    return (m_src_region == other.m_src_region
+	    && m_dest_region == other.m_dest_region
+	    && m_copied_sval == other.m_copied_sval);
+  }
+
+  int get_controlling_option () const final override
+  {
+    return OPT_Wanalyzer_exposure_through_uninit_copy;
+  }
+
+  bool emit (diagnostic_emission_context &ctxt) final override
+  {
+    /* CWE-200: Exposure of Sensitive Information to an Unauthorized Actor.  */
+    ctxt.add_cwe (200);
+    enum memory_space mem_space = get_src_memory_space ();
+    bool warned;
+    switch (mem_space)
+      {
+      default:
+	warned = ctxt.warn ("potential exposure of sensitive information"
+			    " by copying uninitialized data"
+			    " across trust boundary");
+	break;
+      case MEMSPACE_STACK:
+	warned = ctxt.warn ("potential exposure of sensitive information"
+			    " by copying uninitialized data from stack"
+			    " across trust boundary");
+	break;
+      case MEMSPACE_HEAP:
+	warned = ctxt.warn ("potential exposure of sensitive information"
+			    " by copying uninitialized data from heap"
+			    " across trust boundary");
+	break;
+      }
+    if (warned)
+      {
+	const location_t loc = ctxt.get_location ();
+	inform_number_of_uninit_bits (loc);
+	complain_about_uninit_ranges (loc);
+
+	if (mem_space == MEMSPACE_STACK)
+	  maybe_emit_fixit_hint ();
+      }
+    return warned;
+  }
+
+  bool
+  describe_final_event (pretty_printer &pp,
+			const evdesc::final_event &) final override
+  {
+    enum memory_space mem_space = get_src_memory_space ();
+    switch (mem_space)
+      {
+      default:
+	pp_string (&pp, "uninitialized data copied here");
+	return true;
+
+      case MEMSPACE_STACK:
+	pp_string (&pp, "uninitialized data copied from stack here");
+	return true;
+
+      case MEMSPACE_HEAP:
+	pp_string (&pp, "uninitialized data copied from heap here");
+	return true;
+      }
+  }
+
+  void mark_interesting_stuff (interesting_t *interest) final override
+  {
+    if (m_src_region)
+      interest->add_region_creation (m_src_region);
+  }
+
+  void
+  maybe_add_sarif_properties (diagnostics::sarif_object &result_obj)
+    const final override
+  {
+    auto &props = result_obj.get_or_create_properties ();
+#define PROPERTY_PREFIX "gcc/-Wanalyzer-exposure-through-uninit-copy/"
+    props.set (PROPERTY_PREFIX "src_region", m_src_region->to_json ());
+    props.set (PROPERTY_PREFIX "dest_region", m_dest_region->to_json ());
+    props.set (PROPERTY_PREFIX "copied_sval", m_copied_sval->to_json ());
+#undef PROPERTY_PREFIX
+  }
+
+private:
+  enum memory_space get_src_memory_space () const
+  {
+    return m_src_region ? m_src_region->get_memory_space () : MEMSPACE_UNKNOWN;
+  }
+
+  bit_size_t calc_num_uninit_bits () const
+  {
+    switch (m_copied_sval->get_kind ())
+      {
+      default:
+	gcc_unreachable ();
+	break;
+      case SK_POISONED:
+	{
+	  const poisoned_svalue *poisoned_sval
+	    = as_a <const poisoned_svalue *> (m_copied_sval);
+	  gcc_assert (poisoned_sval->get_poison_kind () == poison_kind::uninit);
+
+	  /* Give up if don't have type information.  */
+	  if (m_copied_sval->get_type () == NULL_TREE)
+	    return 0;
+
+	  bit_size_t size_in_bits;
+	  if (int_size_in_bits (m_copied_sval->get_type (), &size_in_bits))
+	    return size_in_bits;
+
+	  /* Give up if we can't get the size of the type.  */
+	  return 0;
+	}
+	break;
+      case SK_COMPOUND:
+	{
+	  const compound_svalue *compound_sval
+	    = as_a <const compound_svalue *> (m_copied_sval);
+	  bit_size_t result = 0;
+	  /* Find keys for uninit svals.  */
+	  for (auto iter : compound_sval->get_concrete_bindings ())
+	    {
+	      const svalue *sval = iter.second;
+	      if (const poisoned_svalue *psval
+		  = sval->dyn_cast_poisoned_svalue ())
+		if (psval->get_poison_kind () == poison_kind::uninit)
+		  {
+		    const bit_range &bits = iter.first;
+		    result += bits.m_size_in_bits;
+		  }
+	    }
+	  return result;
+	}
+      }
+  }
+
+  void inform_number_of_uninit_bits (location_t loc) const
+  {
+    bit_size_t num_uninit_bits = calc_num_uninit_bits ();
+    if (num_uninit_bits <= 0)
+      return;
+    if (num_uninit_bits % BITS_PER_UNIT == 0)
+      {
+	/* Express in bytes.  */
+	byte_size_t num_uninit_bytes = num_uninit_bits / BITS_PER_UNIT;
+	if (num_uninit_bytes == 1)
+	  inform (loc, "1 byte is uninitialized");
+	else
+	  inform (loc,
+		  "%wu bytes are uninitialized", num_uninit_bytes.to_uhwi ());
+      }
+    else
+      {
+	/* Express in bits.  */
+	if (num_uninit_bits == 1)
+	  inform (loc, "1 bit is uninitialized");
+	else
+	  inform (loc,
+		  "%wu bits are uninitialized", num_uninit_bits.to_uhwi ());
+      }
+  }
+
+  void complain_about_uninit_ranges (location_t loc) const
+  {
+    if (const compound_svalue *compound_sval
+	= m_copied_sval->dyn_cast_compound_svalue ())
+      {
+	/* Find keys for uninit svals.  */
+	auto_vec<bit_range> uninit_bit_ranges;
+	for (auto iter : compound_sval->get_concrete_bindings ())
+	  {
+	    const svalue *sval = iter.second;
+	    if (const poisoned_svalue *psval
+		= sval->dyn_cast_poisoned_svalue ())
+	      if (psval->get_poison_kind () == poison_kind::uninit)
+		uninit_bit_ranges.safe_push (iter.first);
+	  }
+
+	std::unique_ptr<record_layout> layout;
+
+	tree type = m_copied_sval->get_type ();
+	if (type && TREE_CODE (type) == RECORD_TYPE)
+	  {
+	    layout = std::make_unique<record_layout> (type);
+
+	    if (0)
+	      layout->dump ();
+	  }
+
+	unsigned i;
+	bit_range *bits;
+	FOR_EACH_VEC_ELT (uninit_bit_ranges, i, bits)
+	  {
+	    bit_offset_t start_bit = bits->get_start_bit_offset ();
+	    bit_offset_t next_bit = bits->get_next_bit_offset ();
+	    complain_about_uninit_range (loc, start_bit, next_bit,
+					 layout.get ());
+	  }
+      }
+  }
+
+  void complain_about_uninit_range (location_t loc,
+				    bit_offset_t start_bit,
+				    bit_offset_t next_bit,
+				    const record_layout *layout) const
+  {
+    if (layout)
+      {
+	while (start_bit < next_bit)
+	  {
+	    if (const record_layout::item *item
+		  = layout->get_item_at (start_bit))
+	      {
+		gcc_assert (start_bit >= item->get_start_bit_offset ());
+		gcc_assert (start_bit < item->get_next_bit_offset ());
+		if (item->get_start_bit_offset () == start_bit
+		    && item->get_next_bit_offset () <= next_bit)
+		  complain_about_fully_uninit_item (*item);
+		else
+		  complain_about_partially_uninit_item (*item);
+		start_bit = item->get_next_bit_offset ();
+		continue;
+	      }
+	    else
+	      break;
+	  }
+      }
+
+    if (start_bit >= next_bit)
+      return;
+
+    if (start_bit % 8 == 0 && next_bit % 8 == 0)
+      {
+	/* Express in bytes.  */
+	byte_offset_t start_byte = start_bit / 8;
+	byte_offset_t last_byte = (next_bit / 8) - 1;
+	if (last_byte == start_byte)
+	  inform (loc,
+		  "byte %wu is uninitialized",
+		  start_byte.to_uhwi ());
+	else
+	  inform (loc,
+		  "bytes %wu - %wu are uninitialized",
+		  start_byte.to_uhwi (),
+		  last_byte.to_uhwi ());
+      }
+    else
+      {
+	/* Express in bits.  */
+	bit_offset_t last_bit = next_bit - 1;
+	if (last_bit == start_bit)
+	  inform (loc,
+		  "bit %wu is uninitialized",
+		  start_bit.to_uhwi ());
+	else
+	  inform (loc,
+		  "bits %wu - %wu are uninitialized",
+		  start_bit.to_uhwi (),
+		  last_bit.to_uhwi ());
+      }
+  }
+
+  static void
+  complain_about_fully_uninit_item (const record_layout::item &item)
+  {
+    const_tree field = item.m_field;
+    bit_size_t num_bits = item.m_bit_range.m_size_in_bits;
+    if (item.m_is_padding)
+      {
+	if (num_bits % 8 == 0)
+	  {
+	    /* Express in bytes.  */
+	    byte_size_t num_bytes = num_bits / BITS_PER_UNIT;
+	    if (num_bytes == 1)
+	      inform (DECL_SOURCE_LOCATION (field),
+		      "padding after field %qD is uninitialized (1 byte)",
+		      field);
+	    else
+	      inform (DECL_SOURCE_LOCATION (field),
+		      "padding after field %qD is uninitialized (%wu bytes)",
+		      field, num_bytes.to_uhwi ());
+	  }
+	else
+	  {
+	    /* Express in bits.  */
+	    if (num_bits == 1)
+	      inform (DECL_SOURCE_LOCATION (field),
+		      "padding after field %qD is uninitialized (1 bit)",
+		      field);
+	    else
+	      inform (DECL_SOURCE_LOCATION (field),
+		      "padding after field %qD is uninitialized (%wu bits)",
+		      field, num_bits.to_uhwi ());
+	  }
+      }
+    else
+      {
+	if (num_bits % 8 == 0)
+	  {
+	    /* Express in bytes.  */
+	    byte_size_t num_bytes = num_bits / BITS_PER_UNIT;
+	    if (num_bytes == 1)
+	      inform (DECL_SOURCE_LOCATION (field),
+		      "field %qD is uninitialized (1 byte)", field);
+	    else
+	      inform (DECL_SOURCE_LOCATION (field),
+		      "field %qD is uninitialized (%wu bytes)",
+		      field, num_bytes.to_uhwi ());
+	  }
+	else
+	  {
+	    /* Express in bits.  */
+	    if (num_bits == 1)
+	      inform (DECL_SOURCE_LOCATION (field),
+		      "field %qD is uninitialized (1 bit)", field);
+	    else
+	      inform (DECL_SOURCE_LOCATION (field),
+		      "field %qD is uninitialized (%wu bits)",
+		      field, num_bits.to_uhwi ());
+	  }
+      }
+  }
+
+  static void
+  complain_about_partially_uninit_item (const record_layout::item &item)
+  {
+    const_tree field = item.m_field;
+    if (item.m_is_padding)
+      inform (DECL_SOURCE_LOCATION (field),
+	      "padding after field %qD is partially uninitialized",
+	      field);
+    else
+      inform (DECL_SOURCE_LOCATION (field),
+	      "field %qD is partially uninitialized",
+	      field);
+    /* TODO: ideally we'd describe what parts are uninitialized.  */
+  }
+
+  void maybe_emit_fixit_hint () const
+  {
+    if (tree decl = m_src_region->maybe_get_decl ())
+      {
+	gcc_rich_location hint_richloc (DECL_SOURCE_LOCATION (decl));
+	hint_richloc.add_fixit_insert_after (" = {0}");
+	inform (&hint_richloc,
+		"suggest forcing zero-initialization by"
+		" providing a %<{0}%> initializer");
+      }
+  }
+
+private:
+  const region *m_src_region;
+  const region *m_dest_region;
+  const svalue *m_copied_sval;
+};
+
+/* Return true if any part of SVAL is uninitialized.  */
+
+static bool
+contains_uninit_p (const svalue *sval)
+{
+  switch (sval->get_kind ())
+    {
+    default:
+      return false;
+    case SK_POISONED:
+      {
+	const poisoned_svalue *psval
+	  = as_a <const poisoned_svalue *> (sval);
+	return psval->get_poison_kind () == poison_kind::uninit;
+      }
+    case SK_COMPOUND:
+      {
+	const compound_svalue *compound_sval
+	  = as_a <const compound_svalue *> (sval);
+
+	for (auto iter = compound_sval->begin ();
+	     iter != compound_sval->end (); ++iter)
+	  {
+	    const svalue *inner_sval = iter->second;
+	    if (const poisoned_svalue *psval
+		= inner_sval->dyn_cast_poisoned_svalue ())
+	      if (psval->get_poison_kind () == poison_kind::uninit)
+		return true;
+	  }
+
+	return false;
+      }
+    }
+}
+
+/* Function for use by plugins when simulating writing data through a
+   pointer to an "untrusted" region DST_REG (and thus crossing a security
+   boundary), such as copying data to user space in an OS kernel.
+
+   Check that COPIED_SVAL is fully initialized.  If not, complain about
+   an infoleak to CTXT.
+
+   SRC_REG can be nullptr; if non-NULL it is used as a hint in the diagnostic
+   as to where COPIED_SVAL came from.  */
+
+void
+region_model::maybe_complain_about_infoleak (const region *dst_reg,
+					     const svalue *copied_sval,
+					     const region *src_reg,
+					     region_model_context *ctxt)
+{
+  /* Check for exposure.  */
+  if (contains_uninit_p (copied_sval))
+    ctxt->warn
+      (std::make_unique<exposure_through_uninit_copy> (src_reg,
+						       dst_reg,
+						       copied_sval));
+}
+
+} // namespace ana
+
+#endif /* #if ENABLE_ANALYZER */
diff --git a/gcc/analyzer/region-model.cc b/gcc/analyzer/region-model.cc
index 79441dc29ca3..e4a2aba6cb31 100644
--- a/gcc/analyzer/region-model.cc
+++ b/gcc/analyzer/region-model.cc
@@ -38,7 +38,6 @@ along with GCC; see the file COPYING3.  If not see
 #include "target.h"
 #include "calls.h"
 #include "is-a.h"
-#include "gcc-rich-location.h"
 #include "gcc-urlifier.h"
 #include "diagnostics/sarif-sink.h"
 #include "tree-pretty-print.h"
@@ -67,7 +66,6 @@ along with GCC; see the file COPYING3.  If not see
 #include "analyzer/checker-event.h"
 #include "analyzer/checker-path.h"
 #include "analyzer/feasible-graph.h"
-#include "analyzer/record-layout.h"
 #include "analyzer/function-set.h"
 
 #if ENABLE_ANALYZER
@@ -6617,449 +6615,6 @@ region_model::unset_dynamic_extents (const region *reg)
   m_dynamic_extents.remove (reg);
 }
 
-/* A subclass of pending_diagnostic for complaining about uninitialized data
-   being copied across a trust boundary to an untrusted output
-   (e.g. copy_to_user infoleaks in the Linux kernel).  */
-
-class exposure_through_uninit_copy
-  : public pending_diagnostic_subclass<exposure_through_uninit_copy>
-{
-public:
-  exposure_through_uninit_copy (const region *src_region,
-				const region *dest_region,
-				const svalue *copied_sval)
-  : m_src_region (src_region),
-    m_dest_region (dest_region),
-    m_copied_sval (copied_sval)
-  {
-    gcc_assert (m_copied_sval->get_kind () == SK_POISONED
-		|| m_copied_sval->get_kind () == SK_COMPOUND);
-  }
-
-  const char *get_kind () const final override
-  {
-    return "exposure_through_uninit_copy";
-  }
-
-  bool operator== (const exposure_through_uninit_copy &other) const
-  {
-    return (m_src_region == other.m_src_region
-	    && m_dest_region == other.m_dest_region
-	    && m_copied_sval == other.m_copied_sval);
-  }
-
-  int get_controlling_option () const final override
-  {
-    return OPT_Wanalyzer_exposure_through_uninit_copy;
-  }
-
-  bool emit (diagnostic_emission_context &ctxt) final override
-  {
-    /* CWE-200: Exposure of Sensitive Information to an Unauthorized Actor.  */
-    ctxt.add_cwe (200);
-    enum memory_space mem_space = get_src_memory_space ();
-    bool warned;
-    switch (mem_space)
-      {
-      default:
-	warned = ctxt.warn ("potential exposure of sensitive information"
-			    " by copying uninitialized data"
-			    " across trust boundary");
-	break;
-      case MEMSPACE_STACK:
-	warned = ctxt.warn ("potential exposure of sensitive information"
-			    " by copying uninitialized data from stack"
-			    " across trust boundary");
-	break;
-      case MEMSPACE_HEAP:
-	warned = ctxt.warn ("potential exposure of sensitive information"
-			    " by copying uninitialized data from heap"
-			    " across trust boundary");
-	break;
-      }
-    if (warned)
-      {
-	const location_t loc = ctxt.get_location ();
-	inform_number_of_uninit_bits (loc);
-	complain_about_uninit_ranges (loc);
-
-	if (mem_space == MEMSPACE_STACK)
-	  maybe_emit_fixit_hint ();
-      }
-    return warned;
-  }
-
-  bool
-  describe_final_event (pretty_printer &pp,
-			const evdesc::final_event &) final override
-  {
-    enum memory_space mem_space = get_src_memory_space ();
-    switch (mem_space)
-      {
-      default:
-	pp_string (&pp, "uninitialized data copied here");
-	return true;
-
-      case MEMSPACE_STACK:
-	pp_string (&pp, "uninitialized data copied from stack here");
-	return true;
-
-      case MEMSPACE_HEAP:
-	pp_string (&pp, "uninitialized data copied from heap here");
-	return true;
-      }
-  }
-
-  void mark_interesting_stuff (interesting_t *interest) final override
-  {
-    if (m_src_region)
-      interest->add_region_creation (m_src_region);
-  }
-
-  void
-  maybe_add_sarif_properties (diagnostics::sarif_object &result_obj)
-    const final override
-  {
-    auto &props = result_obj.get_or_create_properties ();
-#define PROPERTY_PREFIX "gcc/-Wanalyzer-exposure-through-uninit-copy/"
-    props.set (PROPERTY_PREFIX "src_region", m_src_region->to_json ());
-    props.set (PROPERTY_PREFIX "dest_region", m_dest_region->to_json ());
-    props.set (PROPERTY_PREFIX "copied_sval", m_copied_sval->to_json ());
-#undef PROPERTY_PREFIX
-  }
-
-private:
-  enum memory_space get_src_memory_space () const
-  {
-    return m_src_region ? m_src_region->get_memory_space () : MEMSPACE_UNKNOWN;
-  }
-
-  bit_size_t calc_num_uninit_bits () const
-  {
-    switch (m_copied_sval->get_kind ())
-      {
-      default:
-	gcc_unreachable ();
-	break;
-      case SK_POISONED:
-	{
-	  const poisoned_svalue *poisoned_sval
-	    = as_a <const poisoned_svalue *> (m_copied_sval);
-	  gcc_assert (poisoned_sval->get_poison_kind () == poison_kind::uninit);
-
-	  /* Give up if don't have type information.  */
-	  if (m_copied_sval->get_type () == NULL_TREE)
-	    return 0;
-
-	  bit_size_t size_in_bits;
-	  if (int_size_in_bits (m_copied_sval->get_type (), &size_in_bits))
-	    return size_in_bits;
-
-	  /* Give up if we can't get the size of the type.  */
-	  return 0;
-	}
-	break;
-      case SK_COMPOUND:
-	{
-	  const compound_svalue *compound_sval
-	    = as_a <const compound_svalue *> (m_copied_sval);
-	  bit_size_t result = 0;
-	  /* Find keys for uninit svals.  */
-	  for (auto iter : compound_sval->get_concrete_bindings ())
-	    {
-	      const svalue *sval = iter.second;
-	      if (const poisoned_svalue *psval
-		  = sval->dyn_cast_poisoned_svalue ())
-		if (psval->get_poison_kind () == poison_kind::uninit)
-		  {
-		    const bit_range &bits = iter.first;
-		    result += bits.m_size_in_bits;
-		  }
-	    }
-	  return result;
-	}
-      }
-  }
-
-  void inform_number_of_uninit_bits (location_t loc) const
-  {
-    bit_size_t num_uninit_bits = calc_num_uninit_bits ();
-    if (num_uninit_bits <= 0)
-      return;
-    if (num_uninit_bits % BITS_PER_UNIT == 0)
-      {
-	/* Express in bytes.  */
-	byte_size_t num_uninit_bytes = num_uninit_bits / BITS_PER_UNIT;
-	if (num_uninit_bytes == 1)
-	  inform (loc, "1 byte is uninitialized");
-	else
-	  inform (loc,
-		  "%wu bytes are uninitialized", num_uninit_bytes.to_uhwi ());
-      }
-    else
-      {
-	/* Express in bits.  */
-	if (num_uninit_bits == 1)
-	  inform (loc, "1 bit is uninitialized");
-	else
-	  inform (loc,
-		  "%wu bits are uninitialized", num_uninit_bits.to_uhwi ());
-      }
-  }
-
-  void complain_about_uninit_ranges (location_t loc) const
-  {
-    if (const compound_svalue *compound_sval
-	= m_copied_sval->dyn_cast_compound_svalue ())
-      {
-	/* Find keys for uninit svals.  */
-	auto_vec<bit_range> uninit_bit_ranges;
-	for (auto iter : compound_sval->get_concrete_bindings ())
-	  {
-	    const svalue *sval = iter.second;
-	    if (const poisoned_svalue *psval
-		= sval->dyn_cast_poisoned_svalue ())
-	      if (psval->get_poison_kind () == poison_kind::uninit)
-		uninit_bit_ranges.safe_push (iter.first);
-	  }
-
-	std::unique_ptr<record_layout> layout;
-
-	tree type = m_copied_sval->get_type ();
-	if (type && TREE_CODE (type) == RECORD_TYPE)
-	  {
-	    layout = std::make_unique<record_layout> (type);
-
-	    if (0)
-	      layout->dump ();
-	  }
-
-	unsigned i;
-	bit_range *bits;
-	FOR_EACH_VEC_ELT (uninit_bit_ranges, i, bits)
-	  {
-	    bit_offset_t start_bit = bits->get_start_bit_offset ();
-	    bit_offset_t next_bit = bits->get_next_bit_offset ();
-	    complain_about_uninit_range (loc, start_bit, next_bit,
-					 layout.get ());
-	  }
-      }
-  }
-
-  void complain_about_uninit_range (location_t loc,
-				    bit_offset_t start_bit,
-				    bit_offset_t next_bit,
-				    const record_layout *layout) const
-  {
-    if (layout)
-      {
-	while (start_bit < next_bit)
-	  {
-	    if (const record_layout::item *item
-		  = layout->get_item_at (start_bit))
-	      {
-		gcc_assert (start_bit >= item->get_start_bit_offset ());
-		gcc_assert (start_bit < item->get_next_bit_offset ());
-		if (item->get_start_bit_offset () == start_bit
-		    && item->get_next_bit_offset () <= next_bit)
-		  complain_about_fully_uninit_item (*item);
-		else
-		  complain_about_partially_uninit_item (*item);
-		start_bit = item->get_next_bit_offset ();
-		continue;
-	      }
-	    else
-	      break;
-	  }
-      }
-
-    if (start_bit >= next_bit)
-      return;
-
-    if (start_bit % 8 == 0 && next_bit % 8 == 0)
-      {
-	/* Express in bytes.  */
-	byte_offset_t start_byte = start_bit / 8;
-	byte_offset_t last_byte = (next_bit / 8) - 1;
-	if (last_byte == start_byte)
-	  inform (loc,
-		  "byte %wu is uninitialized",
-		  start_byte.to_uhwi ());
-	else
-	  inform (loc,
-		  "bytes %wu - %wu are uninitialized",
-		  start_byte.to_uhwi (),
-		  last_byte.to_uhwi ());
-      }
-    else
-      {
-	/* Express in bits.  */
-	bit_offset_t last_bit = next_bit - 1;
-	if (last_bit == start_bit)
-	  inform (loc,
-		  "bit %wu is uninitialized",
-		  start_bit.to_uhwi ());
-	else
-	  inform (loc,
-		  "bits %wu - %wu are uninitialized",
-		  start_bit.to_uhwi (),
-		  last_bit.to_uhwi ());
-      }
-  }
-
-  static void
-  complain_about_fully_uninit_item (const record_layout::item &item)
-  {
-    const_tree field = item.m_field;
-    bit_size_t num_bits = item.m_bit_range.m_size_in_bits;
-    if (item.m_is_padding)
-      {
-	if (num_bits % 8 == 0)
-	  {
-	    /* Express in bytes.  */
-	    byte_size_t num_bytes = num_bits / BITS_PER_UNIT;
-	    if (num_bytes == 1)
-	      inform (DECL_SOURCE_LOCATION (field),
-		      "padding after field %qD is uninitialized (1 byte)",
-		      field);
-	    else
-	      inform (DECL_SOURCE_LOCATION (field),
-		      "padding after field %qD is uninitialized (%wu bytes)",
-		      field, num_bytes.to_uhwi ());
-	  }
-	else
-	  {
-	    /* Express in bits.  */
-	    if (num_bits == 1)
-	      inform (DECL_SOURCE_LOCATION (field),
-		      "padding after field %qD is uninitialized (1 bit)",
-		      field);
-	    else
-	      inform (DECL_SOURCE_LOCATION (field),
-		      "padding after field %qD is uninitialized (%wu bits)",
-		      field, num_bits.to_uhwi ());
-	  }
-      }
-    else
-      {
-	if (num_bits % 8 == 0)
-	  {
-	    /* Express in bytes.  */
-	    byte_size_t num_bytes = num_bits / BITS_PER_UNIT;
-	    if (num_bytes == 1)
-	      inform (DECL_SOURCE_LOCATION (field),
-		      "field %qD is uninitialized (1 byte)", field);
-	    else
-	      inform (DECL_SOURCE_LOCATION (field),
-		      "field %qD is uninitialized (%wu bytes)",
-		      field, num_bytes.to_uhwi ());
-	  }
-	else
-	  {
-	    /* Express in bits.  */
-	    if (num_bits == 1)
-	      inform (DECL_SOURCE_LOCATION (field),
-		      "field %qD is uninitialized (1 bit)", field);
-	    else
-	      inform (DECL_SOURCE_LOCATION (field),
-		      "field %qD is uninitialized (%wu bits)",
-		      field, num_bits.to_uhwi ());
-	  }
-      }
-  }
-
-  static void
-  complain_about_partially_uninit_item (const record_layout::item &item)
-  {
-    const_tree field = item.m_field;
-    if (item.m_is_padding)
-      inform (DECL_SOURCE_LOCATION (field),
-	      "padding after field %qD is partially uninitialized",
-	      field);
-    else
-      inform (DECL_SOURCE_LOCATION (field),
-	      "field %qD is partially uninitialized",
-	      field);
-    /* TODO: ideally we'd describe what parts are uninitialized.  */
-  }
-
-  void maybe_emit_fixit_hint () const
-  {
-    if (tree decl = m_src_region->maybe_get_decl ())
-      {
-	gcc_rich_location hint_richloc (DECL_SOURCE_LOCATION (decl));
-	hint_richloc.add_fixit_insert_after (" = {0}");
-	inform (&hint_richloc,
-		"suggest forcing zero-initialization by"
-		" providing a %<{0}%> initializer");
-      }
-  }
-
-private:
-  const region *m_src_region;
-  const region *m_dest_region;
-  const svalue *m_copied_sval;
-};
-
-/* Return true if any part of SVAL is uninitialized.  */
-
-static bool
-contains_uninit_p (const svalue *sval)
-{
-  switch (sval->get_kind ())
-    {
-    default:
-      return false;
-    case SK_POISONED:
-      {
-	const poisoned_svalue *psval
-	  = as_a <const poisoned_svalue *> (sval);
-	return psval->get_poison_kind () == poison_kind::uninit;
-      }
-    case SK_COMPOUND:
-      {
-	const compound_svalue *compound_sval
-	  = as_a <const compound_svalue *> (sval);
-
-	for (auto iter = compound_sval->begin ();
-	     iter != compound_sval->end (); ++iter)
-	  {
-	    const svalue *inner_sval = iter->second;
-	    if (const poisoned_svalue *psval
-		= inner_sval->dyn_cast_poisoned_svalue ())
-	      if (psval->get_poison_kind () == poison_kind::uninit)
-		return true;
-	  }
-
-	return false;
-      }
-    }
-}
-
-/* Function for use by plugins when simulating writing data through a
-   pointer to an "untrusted" region DST_REG (and thus crossing a security
-   boundary), such as copying data to user space in an OS kernel.
-
-   Check that COPIED_SVAL is fully initialized.  If not, complain about
-   an infoleak to CTXT.
-
-   SRC_REG can be nullptr; if non-NULL it is used as a hint in the diagnostic
-   as to where COPIED_SVAL came from.  */
-
-void
-region_model::maybe_complain_about_infoleak (const region *dst_reg,
-					     const svalue *copied_sval,
-					     const region *src_reg,
-					     region_model_context *ctxt)
-{
-  /* Check for exposure.  */
-  if (contains_uninit_p (copied_sval))
-    ctxt->warn
-      (std::make_unique<exposure_through_uninit_copy> (src_reg,
-						       dst_reg,
-						       copied_sval));
-}
-
 /* Set errno to a positive symbolic int, as if some error has occurred.  */
 
 void
-- 
2.49.0

