[13/21] analyzer: fix defaults in compound assignments from non-zero offsets [PR112969]

Message ID 20240509174236.2278921-14-dmalcolm@redhat.com
State New
Headers
Series Various backports to gcc 13 (analyzer, jit, diagnostics) |

Commit Message

David Malcolm May 9, 2024, 5:42 p.m. UTC
  Confusion in binding_cluster::maybe_get_compound_binding about whether
offsets are relative to the start of the region or to the start of the
cluster was leading to incorrect handling of default values, leading
to false positives from -Wanalyzer-use-of-uninitialized-value, from
-Wanalyzer-exposure-through-uninit-copy, and other logic errors.

Fixed thusly.

Backported from commit r14-8428-g6426d466779fa8 (keeping tests
in gcc.dg, rather than c-c++-common).

gcc/analyzer/ChangeLog:
	PR analyzer/112969
	* store.cc (binding_cluster::maybe_get_compound_binding): When
	populating default_map, express the bit-range of the default key
	for REG relative to REG, rather than to the base region.

gcc/testsuite/ChangeLog:
	PR analyzer/112969
	* gcc.dg/analyzer/compound-assignment-5.c (test_3): Remove
	xfails, reorder tests.
	* gcc.dg/analyzer/compound-assignment-pr112969.c: New test.
	* gcc.dg/plugin/infoleak-pr112969.c: New test.
	* gcc.dg/plugin/plugin.exp: Add infoleak-pr112969.c to
	analyzer_kernel_plugin.c tests.

Signed-off-by: David Malcolm <dmalcolm@redhat.com>
---
 gcc/analyzer/store.cc                         | 11 +++-
 .../gcc.dg/analyzer/compound-assignment-5.c   | 29 ++++-------
 .../analyzer/compound-assignment-pr112969.c   | 35 +++++++++++++
 .../gcc.dg/plugin/infoleak-pr112969.c         | 52 +++++++++++++++++++
 gcc/testsuite/gcc.dg/plugin/plugin.exp        |  1 +
 5 files changed, 109 insertions(+), 19 deletions(-)
 create mode 100644 gcc/testsuite/gcc.dg/analyzer/compound-assignment-pr112969.c
 create mode 100644 gcc/testsuite/gcc.dg/plugin/infoleak-pr112969.c
  

Patch

diff --git a/gcc/analyzer/store.cc b/gcc/analyzer/store.cc
index e8c927b9fe9..0acb0a2b186 100644
--- a/gcc/analyzer/store.cc
+++ b/gcc/analyzer/store.cc
@@ -1718,7 +1718,16 @@  binding_cluster::maybe_get_compound_binding (store_manager *mgr,
   else
     default_sval = sval_mgr->get_or_create_initial_value (reg);
   const binding_key *default_key = binding_key::make (mgr, reg);
-  default_map.put (default_key, default_sval);
+
+  /* Express the bit-range of the default key for REG relative to REG,
+     rather than to the base region.  */
+  const concrete_binding *concrete_default_key
+    = default_key->dyn_cast_concrete_binding ();
+  if (!concrete_default_key)
+    return nullptr;
+  const concrete_binding *default_key_relative_to_reg
+     = mgr->get_concrete_binding (0, concrete_default_key->get_size_in_bits ());
+  default_map.put (default_key_relative_to_reg, default_sval);
 
   for (map_t::iterator iter = m_map.begin (); iter != m_map.end (); ++iter)
     {
diff --git a/gcc/testsuite/gcc.dg/analyzer/compound-assignment-5.c b/gcc/testsuite/gcc.dg/analyzer/compound-assignment-5.c
index ccf8fe392bf..e1f42177b08 100644
--- a/gcc/testsuite/gcc.dg/analyzer/compound-assignment-5.c
+++ b/gcc/testsuite/gcc.dg/analyzer/compound-assignment-5.c
@@ -23,7 +23,7 @@  void test_1 (void)
 
 /* Copying from an on-stack array to a global array.  */
 
-struct coord glob_arr[16];
+struct coord glob_arr2[16];
 
 void test_2 (void)
 {
@@ -31,32 +31,29 @@  void test_2 (void)
   arr[3].x = 5;
   arr[3].y = 6;
 
-  glob_arr[7] = arr[3];
+  glob_arr2[7] = arr[3];
 
-  __analyzer_eval (glob_arr[7].x == 5); /* { dg-warning "TRUE" } */
-  __analyzer_eval (glob_arr[7].y == 6); /* { dg-warning "TRUE" } */
+  __analyzer_eval (glob_arr2[7].x == 5); /* { dg-warning "TRUE" } */
+  __analyzer_eval (glob_arr2[7].y == 6); /* { dg-warning "TRUE" } */
 }
 
 /* Copying from a partially initialized on-stack array to a global array.  */
 
-struct coord glob_arr[16];
+struct coord glob_arr3[16];
 
 void test_3 (void)
 {
   struct coord arr[16];
   arr[3].y = 6;
 
-  glob_arr[7] = arr[3]; // or should the uninit warning be here?
+  glob_arr3[7] = arr[3]; // or should the uninit warning be here?
 
-  __analyzer_eval (glob_arr[7].x); /* { dg-warning "uninitialized" "uninit" { xfail *-*-* } } */
-  /* { dg-bogus "UNKNOWN" "unknown" { xfail *-*-* } .-1 } */
-  __analyzer_eval (glob_arr[7].y == 6); /* { dg-warning "TRUE" } */
+  __analyzer_eval (glob_arr3[7].y == 6); /* { dg-warning "TRUE" } */
+  __analyzer_eval (glob_arr3[7].x); /* { dg-warning "uninitialized" "uninit" } */
 }
 
 /* Symbolic bindings: copying from one array to another.  */
 
-struct coord glob_arr[16];
-
 void test_4 (int i)
 {
   struct coord arr_a[16];
@@ -77,8 +74,6 @@  void test_4 (int i)
 
 /* Symbolic bindings: copying within an array: symbolic src and dest  */
 
-struct coord glob_arr[16];
-
 void test_5a (int i, int j)
 {
   struct coord arr[16];
@@ -95,8 +90,6 @@  void test_5a (int i, int j)
 
 /* Symbolic bindings: copying within an array: symbolic src, concrete dest.  */
 
-struct coord glob_arr[16];
-
 void test_5b (int i)
 {
   struct coord arr[16];
@@ -113,8 +106,6 @@  void test_5b (int i)
 
 /* Symbolic bindings: copying within an array: concrete src, symbolic dest.  */
 
-struct coord glob_arr[16];
-
 void test_5c (int i)
 {
   struct coord arr[16];
@@ -132,10 +123,12 @@  void test_5c (int i)
 /* No info on the subregion being copied, and hence
    binding_cluster2::maybe_get_compound_binding should return NULL.  */
 
+struct coord glob_arr6[16];
+
 void test_6 (void)
 {
   struct coord arr[16];
-  arr[7] = glob_arr[3];
+  arr[7] = glob_arr6[3];
 
   __analyzer_eval (arr[7].x == 5); /* { dg-warning "UNKNOWN" } */
   __analyzer_eval (arr[7].y == 6); /* { dg-warning "UNKNOWN" } */
diff --git a/gcc/testsuite/gcc.dg/analyzer/compound-assignment-pr112969.c b/gcc/testsuite/gcc.dg/analyzer/compound-assignment-pr112969.c
new file mode 100644
index 00000000000..4bc037cb7cf
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/analyzer/compound-assignment-pr112969.c
@@ -0,0 +1,35 @@ 
+/* Reduced from -Wanalyzer-exposure-through-uninit-copy false positives
+   seen in Linux kernel in drivers/net/ethernet/intel/ice/ice_ptp.c  */
+
+#include "analyzer-decls.h"
+
+/* { dg-do compile } */
+
+struct hwtstamp_config
+{
+  int flags;
+  int tx_type;
+  int rx_filter;
+};
+
+struct ice_ptp
+{
+  long placeholder;
+  struct hwtstamp_config tstamp_config;
+};
+
+struct ice_pf
+{
+  struct ice_ptp ptp;
+};
+
+void
+ice_ptp_set_ts_config(struct ice_pf* pf)
+{
+  struct hwtstamp_config config;
+  pf->ptp.tstamp_config.tx_type = 1;
+  pf->ptp.tstamp_config.rx_filter = 2;
+  config = pf->ptp.tstamp_config;
+  __analyzer_eval (config.flags == pf->ptp.tstamp_config.flags); /* { dg-warning "TRUE" } */
+  /* { dg-bogus "use of uninitialized value 'config.flags'" "PR analyzer/112969" { target *-*-* } .-1 } */
+}
diff --git a/gcc/testsuite/gcc.dg/plugin/infoleak-pr112969.c b/gcc/testsuite/gcc.dg/plugin/infoleak-pr112969.c
new file mode 100644
index 00000000000..e78fe365975
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/plugin/infoleak-pr112969.c
@@ -0,0 +1,52 @@ 
+/* Reduced from -Wanalyzer-exposure-through-uninit-copy false positives
+   seen in Linux kernel in drivers/net/ethernet/intel/ice/ice_ptp.c  */
+
+/* { dg-do compile } */
+/* { dg-options "-fanalyzer" } */
+/* { dg-require-effective-target analyzer } */
+
+extern unsigned long
+copy_from_user(void* to, const void* from, unsigned long n);
+
+extern unsigned long
+copy_to_user(void* to, const void* from, unsigned long n);
+
+struct ifreq
+{
+  union
+  {
+    void* ifru_data;
+  } ifr_ifru;
+};
+
+struct hwtstamp_config
+{
+  int flags;
+  int tx_type;
+  int rx_filter;
+};
+
+struct ice_ptp
+{
+  long placeholder;
+  struct hwtstamp_config tstamp_config;
+};
+
+struct ice_pf
+{
+  struct ice_ptp ptp;
+};
+int
+ice_ptp_set_ts_config(struct ice_pf* pf, struct ifreq* ifr)
+{
+  struct hwtstamp_config config;
+  int err;
+  if (copy_from_user(&config, ifr->ifr_ifru.ifru_data, sizeof(config)))
+    return -14;
+  pf->ptp.tstamp_config.tx_type = 0;
+  pf->ptp.tstamp_config.rx_filter = 0;
+  config = pf->ptp.tstamp_config;
+  if (copy_to_user(ifr->ifr_ifru.ifru_data, &config, sizeof(config))) /* { dg-bogus "-Wanalyzer-exposure-through-uninit-copy" "PR analyzer/112969" } */
+    return -14;
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.dg/plugin/plugin.exp b/gcc/testsuite/gcc.dg/plugin/plugin.exp
index 4d6304cd100..6465b3c34bf 100644
--- a/gcc/testsuite/gcc.dg/plugin/plugin.exp
+++ b/gcc/testsuite/gcc.dg/plugin/plugin.exp
@@ -141,6 +141,7 @@  set plugin_test_list [list \
 	  infoleak-CVE-2017-18550-1.c \
 	  infoleak-antipatterns-1.c \
 	  infoleak-fixit-1.c \
+	  infoleak-pr112969.c \
 	  infoleak-net-ethtool-ioctl.c \
 	  infoleak-vfio_iommu_type1.c \
 	  taint-CVE-2011-0521-1-fixed.c \