https://gcc.gnu.org/g:8f84c84e571ae6ef045dd7c510e49e76f6ca1b7d
commit r16-6137-g8f84c84e571ae6ef045dd7c510e49e76f6ca1b7d Author: David Malcolm <[email protected]> Date: Mon Dec 15 11:48:49 2025 -0500 analyzer: fix strlen(STRING_CST + OFFSET) [PR123085] gcc/analyzer/ChangeLog: PR analyzer/123085 * region-model.cc (region_model::scan_for_null_terminator_1): Use byte offset when accessing string constant. gcc/testsuite/ChangeLog: PR analyzer/123085 * c-c++-common/analyzer/strlen-pr123085.c: New test. Signed-off-by: David Malcolm <[email protected]> Diff: --- gcc/analyzer/region-model.cc | 37 +++++++++++++--------- .../c-c++-common/analyzer/strlen-pr123085.c | 8 +++++ 2 files changed, 30 insertions(+), 15 deletions(-) diff --git a/gcc/analyzer/region-model.cc b/gcc/analyzer/region-model.cc index 3ef5291d7b06..13b5dc3cd733 100644 --- a/gcc/analyzer/region-model.cc +++ b/gcc/analyzer/region-model.cc @@ -4684,24 +4684,31 @@ region_model::scan_for_null_terminator_1 (const region *reg, if (const string_region *str_reg = base_reg->dyn_cast_string_region ()) { tree string_cst = str_reg->get_string_cst (); - if (const void *p = memchr (TREE_STRING_POINTER (string_cst), - 0, - TREE_STRING_LENGTH (string_cst))) + if (src_byte_offset >= 0 + && src_byte_offset < TREE_STRING_LENGTH (string_cst) + && wi::fits_shwi_p (src_byte_offset)) { - size_t num_bytes_read - = (const char *)p - TREE_STRING_POINTER (string_cst) + 1; - /* Simulate the read. */ - byte_range bytes_to_read (0, num_bytes_read); - const svalue *sval = get_store_bytes (reg, bytes_to_read, ctxt); - if (out_sval) - *out_sval = sval; - if (logger) - logger->log ("using string_cst"); - return m_mgr->get_or_create_int_cst (size_type_node, - num_bytes_read); + HOST_WIDE_INT str_byte_offset = src_byte_offset.to_shwi (); + const char *effective_start + = TREE_STRING_POINTER (string_cst) + str_byte_offset; + size_t effective_len + = TREE_STRING_LENGTH (string_cst) - str_byte_offset; + if (const void *p = memchr (effective_start, 0, effective_len)) + { + size_t num_bytes_read + = (const char *)p - effective_start + 1; + /* Simulate the read. */ + byte_range bytes_to_read (0, num_bytes_read); + const svalue *sval = get_store_bytes (reg, bytes_to_read, ctxt); + if (out_sval) + *out_sval = sval; + if (logger) + logger->log ("using string_cst"); + return m_mgr->get_or_create_int_cst (size_type_node, + num_bytes_read); + } } } - const binding_cluster *cluster = m_store.get_cluster (base_reg); iterable_cluster c (cluster); if (logger) diff --git a/gcc/testsuite/c-c++-common/analyzer/strlen-pr123085.c b/gcc/testsuite/c-c++-common/analyzer/strlen-pr123085.c new file mode 100644 index 000000000000..85552e76a887 --- /dev/null +++ b/gcc/testsuite/c-c++-common/analyzer/strlen-pr123085.c @@ -0,0 +1,8 @@ +static int bug(const char *dirname) { + dirname++; + return __builtin_strlen(dirname); /* { dg-bogus "buffer over-read" } */ +} + +int main (void) { + return bug("abcd"); +}
