[committed] analyzer: fix ICE in taint checker on unary ops [PR104029]

Message ID 20220114225304.1765152-1-dmalcolm@redhat.com
State Committed
Commit 8931adfa0530590d21e74e5c7a1f8d26df575775
Headers
Series [committed] analyzer: fix ICE in taint checker on unary ops [PR104029] |

Commit Message

David Malcolm Jan. 14, 2022, 10:53 p.m. UTC
  gcc/analyzer/ChangeLog:
	PR analyzer/104029
	* sm-taint.cc (taint_state_machine::alt_get_inherited_state):
	Remove gcc_unreachable from default case for unary ops.

gcc/testsuite/ChangeLog:
	PR analyzer/104029
	* gcc.dg/analyzer/pr104029.c: New test.
	* gcc.dg/analyzer/taint-ops.c: New test.
---
 gcc/analyzer/sm-taint.cc                  |   1 -
 gcc/testsuite/gcc.dg/analyzer/pr104029.c  | 115 ++++++++++++++++++++++
 gcc/testsuite/gcc.dg/analyzer/taint-ops.c | 106 ++++++++++++++++++++
 3 files changed, 221 insertions(+), 1 deletion(-)
 create mode 100644 gcc/testsuite/gcc.dg/analyzer/pr104029.c
 create mode 100644 gcc/testsuite/gcc.dg/analyzer/taint-ops.c
  

Comments

David Malcolm Jan. 14, 2022, 10:56 p.m. UTC | #1
On Fri, 2022-01-14 at 17:53 -0500, David Malcolm wrote:
> gcc/analyzer/ChangeLog:
>         PR analyzer/104029
>         * sm-taint.cc (taint_state_machine::alt_get_inherited_state):
>         Remove gcc_unreachable from default case for unary ops.
> 
> gcc/testsuite/ChangeLog:
>         PR analyzer/104029
>         * gcc.dg/analyzer/pr104029.c: New test.
>         * gcc.dg/analyzer/taint-ops.c: New test.

Forgot to add:

Successfully bootstrapped & regrtested on x86_64-pc-linux-gnu.
Pushed to trunk as r12-6597-g8931adfa0530590d21e74e5c7a1f8d26df575775.

[...snip...]
  

Patch

diff --git a/gcc/analyzer/sm-taint.cc b/gcc/analyzer/sm-taint.cc
index 54c7e6015ab..3a46256b020 100644
--- a/gcc/analyzer/sm-taint.cc
+++ b/gcc/analyzer/sm-taint.cc
@@ -649,7 +649,6 @@  taint_state_machine::alt_get_inherited_state (const sm_state_map &map,
 	      return arg_state;
 	    }
 	  default:
-	    gcc_unreachable ();
 	    break;
 	  }
       }
diff --git a/gcc/testsuite/gcc.dg/analyzer/pr104029.c b/gcc/testsuite/gcc.dg/analyzer/pr104029.c
new file mode 100644
index 00000000000..adf15ed356f
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/analyzer/pr104029.c
@@ -0,0 +1,115 @@ 
+// TODO: remove need for this option
+/* { dg-additional-options "-fanalyzer-checker=taint" } */
+
+typedef __SIZE_TYPE__ size_t;
+typedef const void *t_comptype;
+typedef int (*t_compfunc)(t_comptype, t_comptype);
+
+extern int *__errno_location(void)
+  __attribute__((__nothrow__, __leaf__,__const__));
+extern void free(void *__ptr)
+  __attribute__((__nothrow__, __leaf__));
+extern void *my_malloc1(const char *file, int line, size_t size);
+
+int heapsort(void *vbase, size_t nmemb, size_t size, t_compfunc compar) {
+  char tmp, *tmp1, *tmp2, *abase, *k, *p, *t;
+  size_t cnt, i, j, l;
+
+  if (nmemb <= 1)
+    return (0);
+
+  if (!size) {
+    (*__errno_location()) = 22;
+    return (-1);
+  }
+
+  k = my_malloc1(__FILE__, __LINE__, size);
+
+  abase = (char *)vbase - size;
+
+  for (l = nmemb / 2 + 1; --l;) {
+    for (i = l; (j = i * 2) <= nmemb; i = j) {
+      p = abase + j * size;
+      if (j < nmemb && compar(p, p + size) < 0) {
+        p += size;
+        ++j;
+      }
+      t = abase + i * size;
+      if (compar(p, t) <= 0)
+        break;
+      {
+        cnt = size;
+        do {
+          tmp = *t;
+          *t++ = *p;
+          *p++ = tmp;
+        } while (--cnt);
+      };
+    }
+  };
+
+  while (nmemb > 1) {
+    {
+      cnt = size;
+      tmp1 = k;
+      tmp2 = abase + nmemb * size;
+      do {
+        *tmp1++ = *tmp2++;
+      } while (--cnt);
+    };
+    {
+      cnt = size;
+      tmp1 = abase + nmemb * size;
+      tmp2 = abase + size;
+      do {
+        *tmp1++ = *tmp2++;
+      } while (--cnt);
+    };
+    --nmemb;
+    {
+      for (i = 1; (j = i * 2) <= nmemb; i = j) {
+        p = abase + j * size;
+        if (j < nmemb && compar(p, p + size) < 0) {
+          p += size;
+          ++j;
+        }
+        t = abase + i * size;
+        {
+          cnt = size;
+          tmp1 = t;
+          tmp2 = p;
+          do {
+            *tmp1++ = *tmp2++;
+          } while (--cnt);
+        };
+      }
+      for (;;) {
+        j = i;
+        i = j / 2;
+        p = abase + j * size;
+        t = abase + i * size;
+        if (j == 1 || compar(k, t) < 0) {
+          {
+            cnt = size;
+            tmp1 = p;
+            tmp2 = k;
+            do {
+              *tmp1++ = *tmp2++;
+            } while (--cnt);
+          };
+          break;
+        }
+        {
+          cnt = size;
+          tmp1 = p;
+          tmp2 = t;
+          do {
+            *tmp1++ = *tmp2++;
+          } while (--cnt);
+        };
+      }
+    };
+  }
+  free(k);
+  return (0);
+}
diff --git a/gcc/testsuite/gcc.dg/analyzer/taint-ops.c b/gcc/testsuite/gcc.dg/analyzer/taint-ops.c
new file mode 100644
index 00000000000..729dbe53a0c
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/analyzer/taint-ops.c
@@ -0,0 +1,106 @@ 
+/* { dg-additional-options "-fanalyzer-checker=taint" } */
+// TODO: remove need for this option
+/* This test can probably be removed when -fanalyzer enables
+   the taint checker by default.  */
+
+#include "analyzer-decls.h"
+
+void
+test_1 (char a)
+{
+  char b = -a;
+}
+
+/* Copies of code from data-model-1.c.  */
+
+void test_20 (int i, int j)
+{
+  __analyzer_eval (i + 1); /* { dg-warning "UNKNOWN" } */
+  __analyzer_eval (i + j); /* { dg-warning "UNKNOWN" } */
+
+  __analyzer_eval (i - 1); /* { dg-warning "UNKNOWN" } */
+  __analyzer_eval (i - j); /* { dg-warning "UNKNOWN" } */
+
+  __analyzer_eval (i * 2); /* { dg-warning "UNKNOWN" } */
+  __analyzer_eval (i * j); /* { dg-warning "UNKNOWN" } */
+
+  __analyzer_eval (i / 2); /* { dg-warning "UNKNOWN" } */
+  __analyzer_eval (i / j); /* { dg-warning "UNKNOWN" } */
+
+  __analyzer_eval (i % 2); /* { dg-warning "UNKNOWN" } */
+  __analyzer_eval (i % j); /* { dg-warning "UNKNOWN" } */
+
+  __analyzer_eval (i & 1); /* { dg-warning "UNKNOWN" } */
+  __analyzer_eval (i & j); /* { dg-warning "UNKNOWN" } */
+
+  __analyzer_eval (i | 1); /* { dg-warning "UNKNOWN" } */
+  __analyzer_eval (i | j); /* { dg-warning "UNKNOWN" } */
+
+  __analyzer_eval (i ^ 1); /* { dg-warning "UNKNOWN" } */
+  __analyzer_eval (i ^ j); /* { dg-warning "UNKNOWN" } */
+
+  __analyzer_eval (i >> 1); /* { dg-warning "UNKNOWN" } */
+  __analyzer_eval (i >> j); /* { dg-warning "UNKNOWN" } */
+
+  __analyzer_eval (i << 1); /* { dg-warning "UNKNOWN" } */
+  __analyzer_eval (i << j); /* { dg-warning "UNKNOWN" } */
+
+  __analyzer_eval (i && 0); /* { dg-warning "FALSE" } */
+  __analyzer_eval (i && 1); /* { dg-warning "UNKNOWN" } */
+  __analyzer_eval (i && j); /* { dg-warning "UNKNOWN" } */
+
+  __analyzer_eval (i || 0); /* { dg-warning "UNKNOWN" } */
+
+  __analyzer_eval (i || 1); /* { dg-warning "TRUE" } */
+  __analyzer_eval (i || j); /* { dg-warning "UNKNOWN" } */
+
+  __analyzer_eval (~i); /* { dg-warning "UNKNOWN" } */
+  __analyzer_eval (-i); /* { dg-warning "UNKNOWN" } */
+  __analyzer_eval (+i); /* { dg-warning "UNKNOWN" } */
+
+  /* Anything added above should be added to the next function also.  */
+}
+
+void test_21 (void)
+{
+  int i, j, zero;
+  int *pi = &i;
+  int *pj = &j;
+  int *pzero = &zero;
+  *pi = 5;
+  *pj = 3;
+  *pzero = 0;
+
+  __analyzer_eval (i + j == 8); /* { dg-warning "TRUE" } */
+  __analyzer_eval (i - j == 2); /* { dg-warning "TRUE" } */
+  __analyzer_eval (i * j == 15); /* { dg-warning "TRUE" } */
+  __analyzer_eval (i / j == 1); /* { dg-warning "TRUE" } */
+  __analyzer_eval (i % j == 2); /* { dg-warning "TRUE" } */
+
+  /* Division by zero.  */
+  // TODO: should we warn for this?
+  __analyzer_eval (i / zero); /* { dg-warning "UNKNOWN" } */
+  __analyzer_eval (i % zero); /* { dg-warning "UNKNOWN" } */
+
+  __analyzer_eval ((i & 1) == (5 & 1)); /* { dg-warning "TRUE" } */
+  __analyzer_eval ((i & j) == (5 & 3)); /* { dg-warning "TRUE" } */
+  __analyzer_eval ((i | 1) == (5 | 1)); /* { dg-warning "TRUE" } */
+  __analyzer_eval ((i | j) == (5 | 3)); /* { dg-warning "TRUE" } */
+  __analyzer_eval ((i ^ 1) == (5 ^ 1)); /* { dg-warning "TRUE" } */
+  __analyzer_eval ((i ^ j) == (5 ^ 3)); /* { dg-warning "TRUE" } */
+  __analyzer_eval ((i >> 1) == (5 >> 1)); /* { dg-warning "TRUE" } */
+  __analyzer_eval ((i >> j) == (5 >> 3)); /* { dg-warning "TRUE" } */
+  __analyzer_eval ((i << 1) == (5 << 1)); /* { dg-warning "TRUE" } */
+  __analyzer_eval ((i << j) == (5 << 3)); /* { dg-warning "TRUE" } */
+  __analyzer_eval (i && 0); /* { dg-warning "FALSE" } */
+  __analyzer_eval (i && 1); /* { dg-warning "TRUE" } */
+  __analyzer_eval (i && j); /* { dg-warning "TRUE" } */
+
+  __analyzer_eval (i || 0); /* { dg-warning "TRUE" } */
+  __analyzer_eval (i || 1); /* { dg-warning "TRUE" } */
+  __analyzer_eval (i || j); /* { dg-warning "TRUE" } */
+
+  __analyzer_eval (~i == ~5); /* { dg-warning "TRUE" } */
+  __analyzer_eval (-i == -5); /* { dg-warning "TRUE" } */
+  __analyzer_eval (+i == +5); /* { dg-warning "TRUE" } */
+}