[committed] analyzer: fix missing -Wanalyzer-use-of-uninitialized-value on special-cased functions [PR106573]

Message ID 20220810000304.3059351-1-dmalcolm@redhat.com
State Committed
Commit bddd8d86e3036e480158ba9219ee3f290ba652ce
Headers
Series [committed] analyzer: fix missing -Wanalyzer-use-of-uninitialized-value on special-cased functions [PR106573] |

Commit Message

David Malcolm Aug. 10, 2022, 12:03 a.m. UTC
  We were missing checks for uninitialized params on calls to functions
that the analyzer has hardcoded knowledge of - both for those that are
handled just by state machines, and for those that are handled in
region-model-impl-calls.cc (for those arguments for which the svalue
wasn't accessed in handling the call).

Fixed thusly.

Successfully bootstrapped & regrtested on x86_64-pc-linux-gnu.
Pushed to trunk as r13-2007-gbddd8d86e3036e.

gcc/analyzer/ChangeLog:
	PR analyzer/106573
	* region-model.cc (region_model::on_call_pre): Ensure that we call
	get_arg_svalue on all arguments.

gcc/testsuite/ChangeLog:
	PR analyzer/106573
	* gcc.dg/analyzer/error-uninit.c: New test.
	* gcc.dg/analyzer/fd-uninit-1.c: New test.
	* gcc.dg/analyzer/file-uninit-1.c: New test.

Signed-off-by: David Malcolm <dmalcolm@redhat.com>
---
 gcc/analyzer/region-model.cc                  |  8 +++
 gcc/testsuite/gcc.dg/analyzer/error-uninit.c  | 29 +++++++++++
 gcc/testsuite/gcc.dg/analyzer/fd-uninit-1.c   | 21 ++++++++
 gcc/testsuite/gcc.dg/analyzer/file-uninit-1.c | 52 +++++++++++++++++++
 4 files changed, 110 insertions(+)
 create mode 100644 gcc/testsuite/gcc.dg/analyzer/error-uninit.c
 create mode 100644 gcc/testsuite/gcc.dg/analyzer/fd-uninit-1.c
 create mode 100644 gcc/testsuite/gcc.dg/analyzer/file-uninit-1.c
  

Patch

diff --git a/gcc/analyzer/region-model.cc b/gcc/analyzer/region-model.cc
index a140f4d5088..8393c7ddbf7 100644
--- a/gcc/analyzer/region-model.cc
+++ b/gcc/analyzer/region-model.cc
@@ -1355,6 +1355,14 @@  region_model::on_call_pre (const gcall *call, region_model_context *ctxt,
       && gimple_call_internal_fn (call) == IFN_DEFERRED_INIT)
     return false;
 
+  /* Get svalues for all of the arguments at the callsite, to ensure that we
+     complain about any uninitialized arguments.  This might lead to
+     duplicates if any of the handling below also looks up the svalues,
+     but the deduplication code should deal with that.  */
+  if (ctxt)
+    for (unsigned arg_idx = 0; arg_idx < cd.num_args (); arg_idx++)
+      cd.get_arg_svalue (arg_idx);
+
   /* Some of the cases below update the lhs of the call based on the
      return value, but not all.  Provide a default value, which may
      get overwritten below.  */
diff --git a/gcc/testsuite/gcc.dg/analyzer/error-uninit.c b/gcc/testsuite/gcc.dg/analyzer/error-uninit.c
new file mode 100644
index 00000000000..8d52a177b11
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/analyzer/error-uninit.c
@@ -0,0 +1,29 @@ 
+/* Verify that we check for uninitialized values passed to functions
+   that we have special-cased region-model handling for.  */
+
+extern void error (int __status, int __errnum, const char *__format, ...)
+     __attribute__ ((__format__ (__printf__, 3, 4)));
+
+void test_uninit_status (int arg)
+{
+  int st;
+  error (st, 42, "test: %s", arg); /* { dg-warning "use of uninitialized value 'st'" } */
+}
+
+void test_uninit_errnum (int st)
+{
+  int num;
+  error (st, num, "test"); /* { dg-warning "use of uninitialized value 'num'" } */
+}
+
+void test_uninit_fmt (int st)
+{
+  const char *fmt;
+  error (st, 42, fmt); /* { dg-warning "use of uninitialized value 'fmt'" } */
+}
+
+void test_uninit_vargs (int st)
+{
+  int arg;
+  error (st, 42, "test: %s", arg); /* { dg-warning "use of uninitialized value 'arg'" } */
+}
diff --git a/gcc/testsuite/gcc.dg/analyzer/fd-uninit-1.c b/gcc/testsuite/gcc.dg/analyzer/fd-uninit-1.c
new file mode 100644
index 00000000000..b5b189ece98
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/analyzer/fd-uninit-1.c
@@ -0,0 +1,21 @@ 
+/* Verify that we check for uninitialized values passed to functions
+   that we have special-cased state-machine handling for.  */
+
+int dup (int old_fd);
+int not_dup (int old_fd);
+
+int
+test_1 ()
+{
+  int m;
+  return dup (m); /* { dg-warning "use of uninitialized value 'm'" "uninit" } */
+  /* { dg-bogus "'dup' on possibly invalid file descriptor 'm'" "invalid fd false +ve" { xfail *-*-* } .-1 } */
+  /* XFAIL: probably covered by fix for PR analyzer/106551.  */
+}
+
+int
+test_2 ()
+{
+  int m;
+  return not_dup (m); /* { dg-warning "use of uninitialized value 'm'" } */
+}
diff --git a/gcc/testsuite/gcc.dg/analyzer/file-uninit-1.c b/gcc/testsuite/gcc.dg/analyzer/file-uninit-1.c
new file mode 100644
index 00000000000..0f8ac5442b1
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/analyzer/file-uninit-1.c
@@ -0,0 +1,52 @@ 
+/* Verify that we check for uninitialized values passed to functions
+   that we have special-cased state-machine handling for.  */
+
+typedef struct FILE   FILE;
+
+FILE* fopen (const char*, const char*);
+int   fclose (FILE*);
+int fseek (FILE *, long, int);
+
+FILE *
+test_fopen_uninit_path (void)
+{
+  const char *path;
+  FILE *f = fopen (path, "r"); /* { dg-warning "use of uninitialized value 'path'" } */
+  return f;
+}
+
+FILE *
+test_fopen_uninit_mode (const char *path)
+{
+  const char *mode;
+  FILE *f = fopen (path, mode); /* { dg-warning "use of uninitialized value 'mode'" } */
+  return f;
+}
+
+void
+test_fclose_uninit (void)
+{
+  FILE *f;
+  fclose (f); /* { dg-warning "use of uninitialized value 'f'" } */
+}
+
+int
+test_fseek_uninit_stream (void)
+{
+  FILE *stream;
+  return fseek (stream, 0, 0); /* { dg-warning "use of uninitialized value 'stream'" } */
+}
+
+int
+test_fseek_uninit_offset (FILE *stream, int whence)
+{
+  long offset;
+  return fseek (stream, offset, whence); /* { dg-warning "use of uninitialized value 'offset'" } */
+}
+
+int
+test_fseek_uninit_whence (FILE *stream, long offset)
+{
+  int whence;
+  return fseek (stream, offset, whence); /* { dg-warning "use of uninitialized value 'whence'" } */
+}