diff mbox series

[2/9] analyzer: handle symbolic bindings in scan_for_null_terminator [PR105899]

Message ID 20230824143903.3161185-3-dmalcolm@redhat.com
State New
Headers show
Series analyzer: strlen, strcpy, and strcat [PR105899] | expand

Commit Message

David Malcolm Aug. 24, 2023, 2:38 p.m. UTC
gcc/analyzer/ChangeLog:
	PR analyzer/105899
	* region-model.cc (iterable_cluster::iterable_cluster): Add
	symbolic binding keys to m_symbolic_bindings.
	(iterable_cluster::has_symbolic_bindings_p): New.
	(iterable_cluster::m_symbolic_bindings): New field.
	(region_model::scan_for_null_terminator): Treat clusters with
	symbolic bindings as having unknown strlen.

gcc/testsuite/ChangeLog:
	PR analyzer/105899
	* gcc.dg/analyzer/sprintf-1.c: Include "analyzer-decls.h".
	(test_strlen_1): New.
---
 gcc/analyzer/region-model.cc              | 15 +++++++++++++++
 gcc/testsuite/gcc.dg/analyzer/sprintf-1.c | 11 +++++++++++
 2 files changed, 26 insertions(+)
diff mbox series

Patch

diff --git a/gcc/analyzer/region-model.cc b/gcc/analyzer/region-model.cc
index 99817aee3a93..7a2f81f36e0f 100644
--- a/gcc/analyzer/region-model.cc
+++ b/gcc/analyzer/region-model.cc
@@ -3420,6 +3420,8 @@  public:
 	    if (concrete_key->get_byte_range (&fragment_bytes))
 	      m_fragments.safe_push (fragment (fragment_bytes, sval));
 	  }
+	else
+	  m_symbolic_bindings.safe_push (key);
       }
     m_fragments.qsort (fragment::cmp_ptrs);
   }
@@ -3440,8 +3442,14 @@  public:
     return false;
   }
 
+  bool has_symbolic_bindings_p () const
+  {
+    return !m_symbolic_bindings.is_empty ();
+  }
+
 private:
   auto_vec<fragment> m_fragments;
+  auto_vec<const binding_key *> m_symbolic_bindings;
 };
 
 /* Simulate reading the bytes at BYTES from BASE_REG.
@@ -3610,6 +3618,13 @@  region_model::scan_for_null_terminator (const region *reg,
   /* No binding for this base_region, or no binding at src_byte_offset
      (or a symbolic binding).  */
 
+  if (c.has_symbolic_bindings_p ())
+    {
+      if (out_sval)
+	*out_sval = m_mgr->get_or_create_unknown_svalue (NULL_TREE);
+      return m_mgr->get_or_create_unknown_svalue (size_type_node);
+    }
+
   /* TODO: the various special-cases seen in
      region_model::get_store_value.  */
 
diff --git a/gcc/testsuite/gcc.dg/analyzer/sprintf-1.c b/gcc/testsuite/gcc.dg/analyzer/sprintf-1.c
index f8dc806d6192..e7c2b3089c5b 100644
--- a/gcc/testsuite/gcc.dg/analyzer/sprintf-1.c
+++ b/gcc/testsuite/gcc.dg/analyzer/sprintf-1.c
@@ -1,6 +1,8 @@ 
 /* See e.g. https://en.cppreference.com/w/c/io/fprintf
    and https://www.man7.org/linux/man-pages/man3/sprintf.3.html */
 
+#include "analyzer-decls.h"
+
 extern int
 sprintf(char* dst, const char* fmt, ...)
   __attribute__((__nothrow__));
@@ -64,3 +66,12 @@  test_fmt_not_terminated (char *dst)
   return sprintf (dst, fmt); /* { dg-warning "stack-based buffer over-read" } */
   /* { dg-message "while looking for null terminator for argument 2 \\('&fmt'\\) of 'sprintf'..." "event" { target *-*-* } .-1 } */
 }
+
+void
+test_strlen_1 (void)
+{
+  char buf[10];
+  sprintf (buf, "msg: %s\n", "abc");
+  __analyzer_eval (__builtin_strlen (buf) == 8); /* { dg-warning "UNKNOWN" } */
+  // TODO: ideally would be TRUE  
+}