diff options
author | David Malcolm <dmalcolm@redhat.com> | 2023-08-29 10:57:42 -0400 |
---|---|---|
committer | David Malcolm <dmalcolm@redhat.com> | 2023-08-29 10:57:42 -0400 |
commit | f687fc1ff6d4a44db87a35e9e3be7f20425bdacc (patch) | |
tree | 597efde3e2641ea1a4b8faba643893058cbbd934 /gcc | |
parent | d16af3ebea84749ac673db29a4124d2dc7cd369e (diff) | |
download | gcc-f687fc1ff6d4a44db87a35e9e3be7f20425bdacc.zip gcc-f687fc1ff6d4a44db87a35e9e3be7f20425bdacc.tar.gz gcc-f687fc1ff6d4a44db87a35e9e3be7f20425bdacc.tar.bz2 |
analyzer: improve strdup handling [PR105899]
gcc/analyzer/ChangeLog:
PR analyzer/105899
* kf.cc (kf_strdup::impl_call_pre): Set size of
dynamically-allocated buffer. Simulate copying the string from
the source region to the new buffer.
gcc/testsuite/ChangeLog:
PR analyzer/105899
* c-c++-common/analyzer/pr99193-2.c: Add
-Wno-analyzer-too-complex.
* gcc.dg/analyzer/strdup-1.c: Include "analyzer-decls.h".
(test_concrete_strlen): New.
(test_symbolic_strlen): New.
Signed-off-by: David Malcolm <dmalcolm@redhat.com>
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/analyzer/kf.cc | 28 | ||||
-rw-r--r-- | gcc/testsuite/c-c++-common/analyzer/pr99193-2.c | 2 | ||||
-rw-r--r-- | gcc/testsuite/gcc.dg/analyzer/strdup-1.c | 27 |
3 files changed, 48 insertions, 9 deletions
diff --git a/gcc/analyzer/kf.cc b/gcc/analyzer/kf.cc index 333ffd9..37792ae 100644 --- a/gcc/analyzer/kf.cc +++ b/gcc/analyzer/kf.cc @@ -1301,17 +1301,27 @@ public: void impl_call_pre (const call_details &cd) const final override { region_model *model = cd.get_model (); + region_model_context *ctxt = cd.get_ctxt (); region_model_manager *mgr = cd.get_manager (); - cd.check_for_null_terminated_string_arg (0); - /* Ideally we'd get the size here, and simulate copying the bytes. */ - const region *new_reg - = model->get_or_create_region_for_heap_alloc (NULL, cd.get_ctxt ()); - model->mark_region_as_unknown (new_reg, NULL); - if (cd.get_lhs_type ()) + const svalue *bytes_to_copy; + if (const svalue *num_bytes_read_sval + = cd.check_for_null_terminated_string_arg (0, true, &bytes_to_copy)) { - const svalue *ptr_sval - = mgr->get_ptr_svalue (cd.get_lhs_type (), new_reg); - cd.maybe_set_lhs (ptr_sval); + const region *new_reg + = model->get_or_create_region_for_heap_alloc (num_bytes_read_sval, + ctxt); + model->write_bytes (new_reg, num_bytes_read_sval, bytes_to_copy, ctxt); + if (cd.get_lhs_type ()) + { + const svalue *ptr_sval + = mgr->get_ptr_svalue (cd.get_lhs_type (), new_reg); + cd.maybe_set_lhs (ptr_sval); + } + } + else + { + if (ctxt) + ctxt->terminate_path (); } } }; diff --git a/gcc/testsuite/c-c++-common/analyzer/pr99193-2.c b/gcc/testsuite/c-c++-common/analyzer/pr99193-2.c index 791b857..12326ef 100644 --- a/gcc/testsuite/c-c++-common/analyzer/pr99193-2.c +++ b/gcc/testsuite/c-c++-common/analyzer/pr99193-2.c @@ -3,6 +3,8 @@ Based on https://github.com/libguestfs/libguestfs/blob/f19fd566f6387ce7e4d82409528c9dde374d25e0/df/main.c#L404 which is GPLv2 or later. */ +/* { dg-additional-options "-Wno-analyzer-too-complex" } */ + typedef __SIZE_TYPE__ size_t; typedef __builtin_va_list va_list; diff --git a/gcc/testsuite/gcc.dg/analyzer/strdup-1.c b/gcc/testsuite/gcc.dg/analyzer/strdup-1.c index f6c176f..11bc964 100644 --- a/gcc/testsuite/gcc.dg/analyzer/strdup-1.c +++ b/gcc/testsuite/gcc.dg/analyzer/strdup-1.c @@ -1,6 +1,8 @@ #include <string.h> #include <stdlib.h> +#include "analyzer-decls.h" + extern void requires_nonnull (void *ptr) __attribute__((nonnull)); @@ -52,3 +54,28 @@ char *test_uninitialized (void) return strdup (buf); /* { dg-warning "use of uninitialized value 'buf\\\[0\\\]'" } */ /* { dg-message "while looking for null terminator for argument 1 \\('&buf'\\) of 'strdup'..." "event" { target *-*-* } .-1 } */ } + +char *test_concrete_strlen (void) +{ + char *p = strdup ("abc"); + if (!p) + return p; + __analyzer_eval (__analyzer_get_strlen (p) == 3); /* { dg-warning "TRUE" } */ + __analyzer_eval (p[0] == 'a'); /* { dg-warning "TRUE" } */ + __analyzer_eval (p[1] == 'b'); /* { dg-warning "TRUE" } */ + __analyzer_eval (p[2] == 'c'); /* { dg-warning "TRUE" } */ + __analyzer_eval (p[3] == '\0'); /* { dg-warning "TRUE" } */ + return p; +} + +char *test_symbolic_strlen (const char *p) +{ + char *q = strdup (p); + if (!q) + return q; + __analyzer_eval (__analyzer_get_strlen (p) == __analyzer_get_strlen (q)); /* { dg-warning "UNKNOWN" } */ + // TODO: should be TRUE + __analyzer_eval (p[0] == q[0]); /* { dg-warning "UNKNOWN" } */ + // TODO: should be TRUE + return q; +} |