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 --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 +} -- 2.26.3