public inbox for gcc-cvs@sourceware.org
help / color / mirror / Atom feed
* [gcc r13-4577] analyzer: handle memmove like memcpy
@ 2022-12-09  2:20 David Malcolm
  0 siblings, 0 replies; only message in thread
From: David Malcolm @ 2022-12-09  2:20 UTC (permalink / raw)
  To: gcc-cvs

https://gcc.gnu.org/g:cf80a23e19db83b7cb2220371d21642aa08261e0

commit r13-4577-gcf80a23e19db83b7cb2220371d21642aa08261e0
Author: David Malcolm <dmalcolm@redhat.com>
Date:   Thu Dec 8 21:19:23 2022 -0500

    analyzer: handle memmove like memcpy
    
    gcc/analyzer/ChangeLog:
            * region-model-impl-calls.cc (class kf_memcpy): Rename to...
            (class kf_memcpy_memmove): ...this.
            (kf_memcpy::impl_call_pre): Rename to...
            (kf_memcpy_memmove::impl_call_pre): ...this, and check the src for
            poison.
            (register_known_functions): Update for above renaming, and
            register BUILT_IN_MEMMOVE and BUILT_IN_MEMMOVE_CHK.
    
    gcc/testsuite/ChangeLog:
            * gcc.dg/analyzer/memcpy-1.c (test_8a, test_8b): New tests.
            * gcc.dg/analyzer/memmove-1.c: New test, based on memcpy-1.c
            * gcc.dg/analyzer/out-of-bounds-1.c (test7): Update expected
            result for uninit srcBuf.
            * gcc.dg/analyzer/out-of-bounds-5.c (test8, test9): Add
            dg-warnings for memcpy from uninit src vla.
            * gcc.dg/analyzer/pr104308.c (test_memmove_within_uninit):
            Expect creation point note to be missing on riscv*-*-*.
    
    Signed-off-by: David Malcolm <dmalcolm@redhat.com>

Diff:
---
 gcc/analyzer/region-model-impl-calls.cc         |  18 ++-
 gcc/testsuite/gcc.dg/analyzer/memcpy-1.c        |  14 ++
 gcc/testsuite/gcc.dg/analyzer/memmove-1.c       | 182 ++++++++++++++++++++++++
 gcc/testsuite/gcc.dg/analyzer/out-of-bounds-1.c |   2 +-
 gcc/testsuite/gcc.dg/analyzer/out-of-bounds-5.c |   2 +
 gcc/testsuite/gcc.dg/analyzer/pr104308.c        |   2 +-
 6 files changed, 212 insertions(+), 8 deletions(-)

diff --git a/gcc/analyzer/region-model-impl-calls.cc b/gcc/analyzer/region-model-impl-calls.cc
index 6aeb9281bff..ff2f1b1ef9c 100644
--- a/gcc/analyzer/region-model-impl-calls.cc
+++ b/gcc/analyzer/region-model-impl-calls.cc
@@ -246,10 +246,12 @@ kf_malloc::impl_call_pre (const call_details &cd) const
     }
 }
 
-/* Handler for "memcpy" and "__builtin_memcpy".  */
-// TODO: complain about overlapping src and dest.
+/* Handler for "memcpy" and "__builtin_memcpy",
+   "memmove", and "__builtin_memmove".  */
+/* TODO: complain about overlapping src and dest for the memcpy
+   variants.  */
 
-class kf_memcpy : public known_function
+class kf_memcpy_memmove : public known_function
 {
 public:
   bool matches_call_types_p (const call_details &cd) const final override
@@ -263,7 +265,7 @@ public:
 };
 
 void
-kf_memcpy::impl_call_pre (const call_details &cd) const
+kf_memcpy_memmove::impl_call_pre (const call_details &cd) const
 {
   const svalue *dest_ptr_sval = cd.get_arg_svalue (0);
   const svalue *src_ptr_sval = cd.get_arg_svalue (1);
@@ -285,6 +287,8 @@ kf_memcpy::impl_call_pre (const call_details &cd) const
     = mgr->get_sized_region (dest_reg, NULL_TREE, num_bytes_sval);
   const svalue *src_contents_sval
     = model->get_store_value (sized_src_reg, cd.get_ctxt ());
+  model->check_for_poison (src_contents_sval, cd.get_arg_tree (1),
+			   cd.get_ctxt ());
   model->set_value (sized_dest_reg, src_contents_sval, cd.get_ctxt ());
 }
 
@@ -927,8 +931,10 @@ register_known_functions (known_function_manager &kfm)
     kfm.add (BUILT_IN_EXPECT_WITH_PROBABILITY, make_unique<kf_expect> ());
     kfm.add (BUILT_IN_FREE, make_unique<kf_free> ());
     kfm.add (BUILT_IN_MALLOC, make_unique<kf_malloc> ());
-    kfm.add (BUILT_IN_MEMCPY, make_unique<kf_memcpy> ());
-    kfm.add (BUILT_IN_MEMCPY_CHK, make_unique<kf_memcpy> ());
+    kfm.add (BUILT_IN_MEMCPY, make_unique<kf_memcpy_memmove> ());
+    kfm.add (BUILT_IN_MEMCPY_CHK, make_unique<kf_memcpy_memmove> ());
+    kfm.add (BUILT_IN_MEMMOVE, make_unique<kf_memcpy_memmove> ());
+    kfm.add (BUILT_IN_MEMMOVE_CHK, make_unique<kf_memcpy_memmove> ());
     kfm.add (BUILT_IN_MEMSET, make_unique<kf_memset> ());
     kfm.add (BUILT_IN_MEMSET_CHK, make_unique<kf_memset> ());
     kfm.add (BUILT_IN_REALLOC, make_unique<kf_realloc> ());
diff --git a/gcc/testsuite/gcc.dg/analyzer/memcpy-1.c b/gcc/testsuite/gcc.dg/analyzer/memcpy-1.c
index a9368d3307d..b1ffed0a979 100644
--- a/gcc/testsuite/gcc.dg/analyzer/memcpy-1.c
+++ b/gcc/testsuite/gcc.dg/analyzer/memcpy-1.c
@@ -166,3 +166,17 @@ void test_7b (void *src, size_t sz)
 {
   memcpy ((void *)"hello world", src, sz); /* { dg-warning "write to string literal" } */
 }
+
+/* memcpy from uninitialized buffer.  */
+
+void test_8a (void *dst)
+{
+  char src[16];
+  memcpy (dst, src, 16); /* { dg-warning "use of uninitialized value" } */
+}
+
+void test_8b (void *dst, size_t n)
+{
+  char src[16];
+  memcpy (dst, src, n); /* { dg-warning "use of uninitialized value" } */
+}
diff --git a/gcc/testsuite/gcc.dg/analyzer/memmove-1.c b/gcc/testsuite/gcc.dg/analyzer/memmove-1.c
new file mode 100644
index 00000000000..06627ede081
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/analyzer/memmove-1.c
@@ -0,0 +1,182 @@
+#include <string.h>
+#include "analyzer-decls.h"
+
+/* Function for thwarting expansion of memmove by optimizer.  */
+
+typedef void * (*memmove_t) (void *dst, const void *src, size_t n);
+  
+static memmove_t __attribute__((noinline))
+get_memmove (void)
+{
+  return memmove;
+}
+
+void *test_1 (void *dst, void *src, size_t n)
+{
+  void *result = memmove (dst, src, n);
+  __analyzer_eval (result == dst); /* { dg-warning "TRUE" } */
+  return result;
+}
+
+void *test_1a (void *dst, void *src, size_t n)
+{
+  void *result = __memmove_chk (dst, src, n, -1);
+  __analyzer_eval (result == dst); /* { dg-warning "TRUE" } */
+  return result;
+}
+
+void *test_1b (void *dst, void *src, size_t n)
+{
+  memmove_t fn = get_memmove ();
+  void *result = fn (dst, src, n);
+  __analyzer_eval (result == dst); /* { dg-warning "TRUE" } */
+  return result;
+}
+
+void test_2 (int i)
+{
+  int j;
+  memmove (&j, &i, sizeof (int));
+  __analyzer_eval (i == j); /* { dg-warning "TRUE" } */
+}
+
+void test_2a (int i)
+{
+  int j;
+  __memmove_chk (&j, &i, sizeof (int), sizeof (int));
+  __analyzer_eval (i == j);  /* { dg-warning "TRUE" } */
+}
+
+void test_2b (int i)
+{
+  int j;
+  memmove_t fn = get_memmove ();
+  fn (&j, &i, sizeof (int));
+  __analyzer_eval (i == j); /* { dg-warning "TRUE" } */
+}
+
+void test_3 (void *src, size_t n)
+{
+  char buf[40], other[40];
+  buf[0] = 'a';
+  other[0] = 'b';
+  __analyzer_eval (buf[0] == 'a');    /* { dg-warning "TRUE" } */
+  __analyzer_eval (other[0] == 'b');  /* { dg-warning "TRUE" } */
+
+  memmove (buf, src, n);
+  __analyzer_eval (buf[0] == 'a');    /* { dg-warning "UNKNOWN" } */
+  __analyzer_eval (other[0] == 'b');  /* { dg-warning "TRUE" } */
+}
+
+void test_3b (void *src, size_t n)
+{
+  char buf[40], other[40];
+  memmove_t fn = get_memmove ();
+  buf[0] = 'a';
+  other[0] = 'b';
+  __analyzer_eval (buf[0] == 'a');    /* { dg-warning "TRUE" } */
+  __analyzer_eval (other[0] == 'b');  /* { dg-warning "TRUE" } */
+
+  fn (buf, src, n);
+  __analyzer_eval (buf[0] == 'a');    /* { dg-warning "UNKNOWN" } */
+  __analyzer_eval (other[0] == 'b');  /* { dg-warning "TRUE" } */
+}
+
+/* Overwriting a zeroed buffer, then memmove of the result.  */
+
+void test_4 (int a, int b)
+{
+  int src[1024];
+  int dst[1024];
+  memset (src, 0, sizeof (src));
+  src[42] = a;
+  src[100] = b;
+  __analyzer_eval (src[0] == 0);    /* { dg-warning "TRUE" } */
+  __analyzer_eval (src[42] == a);    /* { dg-warning "TRUE" } */
+  __analyzer_eval (src[100] == b);    /* { dg-warning "TRUE" } */
+  __analyzer_eval (src[1023] == 0);    /* { dg-warning "TRUE" } */
+
+  memmove (dst, src, sizeof (src));
+  __analyzer_eval (dst[0] == 0);    /* { dg-warning "TRUE" } */
+  __analyzer_eval (dst[42] == a);    /* { dg-warning "TRUE" } */
+  __analyzer_eval (dst[100] == b);    /* { dg-warning "TRUE" } */
+  __analyzer_eval (dst[1023] == 0);    /* { dg-warning "TRUE" } */  
+}
+
+void test_4b (int a, int b)
+{
+  int src[1024];
+  int dst[1024];
+  memmove_t fn = get_memmove ();
+  memset (src, 0, sizeof (src));
+  src[42] = a;
+  src[100] = b;
+  __analyzer_eval (src[0] == 0);    /* { dg-warning "TRUE" } */
+  __analyzer_eval (src[42] == a);    /* { dg-warning "TRUE" } */
+  __analyzer_eval (src[100] == b);    /* { dg-warning "TRUE" } */
+  __analyzer_eval (src[1023] == 0);    /* { dg-warning "TRUE" } */
+
+  fn (dst, src, sizeof (src));
+  __analyzer_eval (dst[0] == 0);    /* { dg-warning "TRUE" } */
+  __analyzer_eval (dst[42] == a);    /* { dg-warning "TRUE" } */
+  __analyzer_eval (dst[100] == b);    /* { dg-warning "TRUE" } */
+  __analyzer_eval (dst[1023] == 0);    /* { dg-warning "TRUE" } */  
+}
+
+/* Populating a buffer from an unknown buffer.  */
+
+void test_5 (void *src, size_t sz)
+{
+  char dst[1024];
+  memmove (dst, src, sizeof (dst));
+  __analyzer_eval (dst[0] == 0); /* { dg-warning "UNKNOWN" } */
+  __analyzer_eval (dst[1023] == 0); /* { dg-warning "UNKNOWN" } */
+}
+
+void test_5b (void *src, size_t sz)
+{
+  char dst[1024];
+  memmove_t fn = get_memmove ();
+  fn (dst, src, sizeof (dst));
+  __analyzer_eval (dst[0] == 0); /* { dg-warning "UNKNOWN" } */
+  __analyzer_eval (dst[1023] == 0); /* { dg-warning "UNKNOWN" } */
+}
+
+/* Zero-sized memmove.  */
+
+void test_6 (void *dst, void *src)
+{
+  memmove (dst, src, 0);
+}
+
+void test_6b (void *dst, void *src)
+{
+  memmove_t fn = get_memmove ();
+  fn (dst, src, 0);
+}
+
+/* memmove to string literal.  */
+
+void test_7 (void *src, size_t sz)
+{
+  memmove ((void *)"hello world", src, sz); /* { dg-warning "write to string literal" } */
+}
+
+void test_7b (void *src, size_t sz)
+{
+  memmove ((void *)"hello world", src, sz); /* { dg-warning "write to string literal" } */
+}
+
+/* memcpy from uninitialized buffer.  */
+
+void test_8a (void *dst)
+{
+  char src[16];
+  memmove (dst, src, 16); /* { dg-warning "use of uninitialized value" } */
+}
+
+void test_8b (void *dst, size_t n)
+{
+  char src[16];
+  memmove (dst, src, n); /* { dg-warning "use of uninitialized value" } */
+}
diff --git a/gcc/testsuite/gcc.dg/analyzer/out-of-bounds-1.c b/gcc/testsuite/gcc.dg/analyzer/out-of-bounds-1.c
index 977476ed2fb..93b379c173a 100644
--- a/gcc/testsuite/gcc.dg/analyzer/out-of-bounds-1.c
+++ b/gcc/testsuite/gcc.dg/analyzer/out-of-bounds-1.c
@@ -117,6 +117,6 @@ void test7 (void)
 
   // TODO: Should we handle widening_svalues as a follow-up?
   /* { dg-warning "over-read" "warning" { xfail *-*-* } test7 } */
+  /* { dg-warning "use of uninitialized value" "uninit warning" { target *-*-* } test7 } */
   /* { dg-warning "overflow" "warning" { xfail *-*-* } test7 } */
-  /* { dg-message "" "note" { xfail *-*-* } test7 } */
 }
diff --git a/gcc/testsuite/gcc.dg/analyzer/out-of-bounds-5.c b/gcc/testsuite/gcc.dg/analyzer/out-of-bounds-5.c
index 52fea79152e..eb6aae0f8cb 100644
--- a/gcc/testsuite/gcc.dg/analyzer/out-of-bounds-5.c
+++ b/gcc/testsuite/gcc.dg/analyzer/out-of-bounds-5.c
@@ -69,6 +69,7 @@ void test8 (size_t size, size_t offset)
   char dst[size];
   memcpy (dst, src, size + offset); /* { dg-line test8 } */
   /* { dg-warning "over-read" "warning" { target *-*-* } test8 } */
+  /* { dg-warning "use of uninitialized value" "warning" { target *-*-* } test8 } */
   /* { dg-warning "overflow" "warning" { target *-*-* } test8 } */
 }
 
@@ -78,6 +79,7 @@ void test9 (size_t size, size_t offset)
   int32_t dst[size];
   memcpy (dst, src, 4 * size + 1); /* { dg-line test9 } */
   /* { dg-warning "over-read" "warning" { target *-*-* } test9 } */
+  /* { dg-warning "use of uninitialized value" "warning" { target *-*-* } test9 } */
   /* { dg-warning "overflow" "warning" { target *-*-* } test9 } */
 }
 
diff --git a/gcc/testsuite/gcc.dg/analyzer/pr104308.c b/gcc/testsuite/gcc.dg/analyzer/pr104308.c
index a3a0cbb7317..e6a2c8821bf 100644
--- a/gcc/testsuite/gcc.dg/analyzer/pr104308.c
+++ b/gcc/testsuite/gcc.dg/analyzer/pr104308.c
@@ -6,7 +6,7 @@
 
 int test_memmove_within_uninit (void)
 {
-  char s[5]; /* { dg-message "region created on stack here" } */
+  char s[5]; /* { dg-message "region created on stack here" "" { xfail riscv*-*-* } } */
   memmove(s, s + 1, 2); /* { dg-warning "use of uninitialized value" } */
   return 0;
 }

^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2022-12-09  2:20 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-12-09  2:20 [gcc r13-4577] analyzer: handle memmove like memcpy David Malcolm

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).