analyzer: fix another ICE in PR 107158
authorDavid Malcolm <dmalcolm@redhat.com>
Thu, 6 Oct 2022 19:46:49 +0000 (15:46 -0400)
committerDavid Malcolm <dmalcolm@redhat.com>
Thu, 6 Oct 2022 19:46:49 +0000 (15:46 -0400)
I overreduced PR analyzer/107158 in r13-3096-gef878564140cbc, and there
was another ICE in the original reproducer, which this patch fixes.

gcc/analyzer/ChangeLog:
PR analyzer/107158
* store.cc (store::replay_call_summary_cluster): Eliminate
special-casing of RK_HEAP_ALLOCATED in favor of sharing code with
RK_DECL, avoiding an ICE due to attempting to bind a
compound_svalue into a binding_cluster when an svalue in the
summary cluster converts to a compound_svalue in the caller.

gcc/testsuite/ChangeLog:
PR analyzer/107158
* gcc.dg/analyzer/call-summaries-pr107158-2.c: New test.

Signed-off-by: David Malcolm <dmalcolm@redhat.com>
gcc/analyzer/store.cc
gcc/testsuite/gcc.dg/analyzer/call-summaries-pr107158-2.c [new file with mode: 0644]

index d2279b5..2631ea2 100644 (file)
@@ -3238,6 +3238,8 @@ store::replay_call_summary_cluster (call_summary_replay &r,
                   caller_sval, NULL /* uncertainty_t * */);
       }
       break;
+
+    case RK_HEAP_ALLOCATED:
     case RK_DECL:
       {
        const region *caller_dest_reg
@@ -3246,6 +3248,10 @@ store::replay_call_summary_cluster (call_summary_replay &r,
          return;
        const svalue *summary_sval
          = summary.get_any_binding (mgr, summary_base_reg);
+       if (!summary_sval)
+         summary_sval = reg_mgr->get_or_create_compound_svalue
+           (summary_base_reg->get_type (),
+            summary_cluster->get_map ());
        const svalue *caller_sval
          = r.convert_svalue_from_summary (summary_sval);
        if (!caller_sval)
@@ -3255,34 +3261,6 @@ store::replay_call_summary_cluster (call_summary_replay &r,
                   caller_sval, NULL /* uncertainty_t * */);
       }
       break;
-    case RK_HEAP_ALLOCATED:
-      {
-       const region *caller_dest_reg
-         = r.convert_region_from_summary (summary_base_reg);
-       gcc_assert (caller_dest_reg);
-       binding_cluster *caller_cluster
-         = get_or_create_cluster (caller_dest_reg);
-       auto_vec <const binding_key *> summary_keys;
-       for (auto kv : *summary_cluster)
-         summary_keys.safe_push (kv.first);
-       summary_keys.qsort (binding_key::cmp_ptrs);
-       for (auto summary_key : summary_keys)
-         {
-           const binding_key *caller_key
-             = r.convert_key_from_summary (summary_key);
-           if (!caller_key)
-             continue;
-           const svalue *summary_sval
-             = summary_cluster->get_map ().get (summary_key);
-           const svalue *caller_sval
-             = r.convert_svalue_from_summary (summary_sval);
-           if (!caller_sval)
-             caller_sval = reg_mgr->get_or_create_unknown_svalue
-               (summary_sval->get_type ());
-           caller_cluster->bind_key (caller_key, caller_sval);
-         }
-      }
-      break;
 
     case RK_ALLOCA:
       /* Ignore bindings of alloca regions in the summary.  */
diff --git a/gcc/testsuite/gcc.dg/analyzer/call-summaries-pr107158-2.c b/gcc/testsuite/gcc.dg/analyzer/call-summaries-pr107158-2.c
new file mode 100644 (file)
index 0000000..c2e9e2b
--- /dev/null
@@ -0,0 +1,108 @@
+/* { dg-additional-options "-fanalyzer-call-summaries -Wno-analyzer-too-complex" } */
+
+typedef __SIZE_TYPE__ size_t;
+typedef struct _IO_FILE FILE;
+extern char *fgets(char *__restrict __s, int __n, FILE *__restrict __stream)
+    __attribute__((__access__(__write_only__, 1, 2)));
+extern void perror(const char *__s);
+enum {
+  _ISspace = ((5) < 8 ? ((1 << (5)) << 8) : ((1 << (5)) >> 8)),
+};
+extern const unsigned short int **__ctype_b_loc(void)
+    __attribute__((__nothrow__, __leaf__)) __attribute__((__const__));
+extern void *malloc(size_t __size) __attribute__((__nothrow__, __leaf__))
+__attribute__((__malloc__)) __attribute__((__alloc_size__(1)));
+extern void exit(int __status) __attribute__((__nothrow__, __leaf__))
+__attribute__((__noreturn__));
+extern char *strcpy(char *__restrict __dest, const char *__restrict __src)
+    __attribute__((__nothrow__, __leaf__)) __attribute__((__nonnull__(1, 2)));
+extern size_t strlen(const char *__s) __attribute__((__nothrow__, __leaf__))
+__attribute__((__pure__)) __attribute__((__nonnull__(1)));
+
+struct mydata {
+  struct mydata *link;
+  char *name;
+  char *type;
+};
+
+static struct mydata *all_data;
+static int line_no;
+
+_Noreturn static void failed(const char *message) {
+  perror(message);
+  exit(1);
+}
+
+static char *string_dup(const char *string) {
+  char *buf;
+
+  if ((buf = malloc(strlen(string) + 1)) == ((void *)0))
+    failed("malloc() failed");
+
+  return strcpy(buf, string);
+}
+
+static void store_data(const char *name, const char *type) {
+  struct mydata *p, *q;
+
+  if ((p = (struct mydata *)malloc(sizeof(struct mydata))) == ((void *)0))
+    failed("malloc() failed");
+
+  p->link = ((void *)0);
+  p->name = string_dup(name);
+  p->type = string_dup(type);
+
+  if ((q = all_data) == ((void *)0))
+    all_data = p;
+  else {
+    while (q->link != ((void *)0))
+      q = q->link;
+    q->link = p;
+  }
+}
+
+static void parse_tbl(char *buffer) {
+  char *s = buffer;
+  char *t = s + strlen(s);
+
+  do {
+    t--;
+    if (((*__ctype_b_loc())[(int)(((int)*t))] & (unsigned short int)_ISspace))
+      *t = '\0';
+    else
+      break;
+  } while (t > s);
+  while (((*__ctype_b_loc())[(int)(((int)*s))] & (unsigned short int)_ISspace))
+    s++;
+  buffer = s;
+
+  line_no++;
+  if (*buffer != ';' && *buffer != '\0') {
+    if (*buffer == '#') {
+      store_data(buffer, ""); /* { dg-bogus "leak" "PR analyzer/107158" { xfail *-*-* } } */
+    } else {
+
+      while (*s && !((*__ctype_b_loc())[(int)(((int)*s))] &
+                     (unsigned short int)_ISspace))
+        s++;
+      while (
+          ((*__ctype_b_loc())[(int)(((int)*s))] & (unsigned short int)_ISspace))
+        *s++ = '\0';
+      store_data(buffer, s); /* { dg-bogus "leak" "PR analyzer/107158" { xfail *-*-* } } */
+    }
+  }
+}
+
+/* [...snip...] */
+
+static void makecfg(FILE *ifp, FILE *ofp, FILE *ofp2) {
+  char buffer[8192];
+
+  /* [...snip...] */
+
+  line_no = 0;
+  while (fgets(buffer, sizeof(buffer) - 1, ifp))
+    parse_tbl(buffer);
+
+  /* [...snip...] */
+}