aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorDavid Malcolm <dmalcolm@redhat.com>2023-08-29 10:57:42 -0400
committerDavid Malcolm <dmalcolm@redhat.com>2023-08-29 10:57:42 -0400
commitf687fc1ff6d4a44db87a35e9e3be7f20425bdacc (patch)
tree597efde3e2641ea1a4b8faba643893058cbbd934 /gcc
parentd16af3ebea84749ac673db29a4124d2dc7cd369e (diff)
downloadgcc-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.cc28
-rw-r--r--gcc/testsuite/c-c++-common/analyzer/pr99193-2.c2
-rw-r--r--gcc/testsuite/gcc.dg/analyzer/strdup-1.c27
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;
+}