]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
analyzer: Fix ICE in cmp_csts_same_type on RAW_DATA_CST [PR119278]
authorJakub Jelinek <jakub@redhat.com>
Fri, 14 Mar 2025 14:30:43 +0000 (15:30 +0100)
committerJakub Jelinek <jakub@gcc.gnu.org>
Fri, 14 Mar 2025 14:30:43 +0000 (15:30 +0100)
The following testcase ICEs in cmp_csts_same_type because RAW_DATA_CST
isn't handled there.  As TREE_TYPE (cst1) in that case is INTEGER_TYPE,
e.g. char/signed char/unsigned char, the type itself doesn't imply
the size, so the length is compared first, followed by comparing the
data.
While at it, I've noticed STRING_CST handling is wrong, because STRING_CST
can represent even string literals with embedded nul characters.
We shouldn't stop at those, hence memcmp.
While for STRING_CST TREE_TYPE should likely already imply the length
and so same type should imply same TREE_STRING_LENGTH, I've repeated
the comparisons in there just in case.

2025-03-14  Jakub Jelinek  <jakub@redhat.com>

PR analyzer/119278
* svalue.cc (cmp_csts_same_type): For STRING_CST, compare
TREE_STRING_LENGTH first just in case and use memcmp rather
than strcmp.  Handle RAW_DATA_CST.

* c-c++-common/analyzer/pr119278.c: New test.

gcc/analyzer/svalue.cc
gcc/testsuite/c-c++-common/analyzer/pr119278.c [new file with mode: 0644]

index c61be4d9002b510d7a4fc55628a0c64318702e60..2e3f051d899c7b82e0db18c235c3318418533fca 100644 (file)
@@ -467,8 +467,21 @@ cmp_csts_same_type (const_tree cst1, const_tree cst2)
     case INTEGER_CST:
       return tree_int_cst_compare (cst1, cst2);
     case STRING_CST:
-      return strcmp (TREE_STRING_POINTER (cst1),
-                    TREE_STRING_POINTER (cst2));
+      if (TREE_STRING_LENGTH (cst1) < TREE_STRING_LENGTH (cst2))
+       return -1;
+      if (TREE_STRING_LENGTH (cst1) > TREE_STRING_LENGTH (cst2))
+       return 1;
+      return memcmp (TREE_STRING_POINTER (cst1),
+                    TREE_STRING_POINTER (cst2),
+                    TREE_STRING_LENGTH (cst1));
+    case RAW_DATA_CST:
+      if (RAW_DATA_LENGTH (cst1) < RAW_DATA_LENGTH (cst2))
+       return -1;
+      if (RAW_DATA_LENGTH (cst1) > RAW_DATA_LENGTH (cst2))
+       return 1;
+      return memcmp (RAW_DATA_POINTER (cst1),
+                    RAW_DATA_POINTER (cst2),
+                    RAW_DATA_LENGTH (cst1));
     case REAL_CST:
       /* Impose an arbitrary but deterministic order.  */
       return memcmp (TREE_REAL_CST_PTR (cst1),
diff --git a/gcc/testsuite/c-c++-common/analyzer/pr119278.c b/gcc/testsuite/c-c++-common/analyzer/pr119278.c
new file mode 100644 (file)
index 0000000..bb1dcb6
--- /dev/null
@@ -0,0 +1,20 @@
+/* PR analyzer/119278 */
+/* { dg-do compile } */
+
+const unsigned char a[] = {
+#define A 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16
+  A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A
+};
+const unsigned char b[] = {
+#define B 16, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 1
+  B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B
+};
+struct S { const unsigned char *s; };
+void bar (struct S *);
+
+void
+foo (void)
+{
+  struct S t[] = { a, b };
+  bar (t);
+}