Update CStringChecker to take advantage of the new metadata symbols and region change callback. Now does basic tracking of string length for general regions. Currently this is still only used for modeling strlen().


git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@111081 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/test/Analysis/string.c b/test/Analysis/string.c
index f24d71c..af43c4b 100644
--- a/test/Analysis/string.c
+++ b/test/Analysis/string.c
@@ -1,7 +1,7 @@
-// RUN: %clang_cc1 -analyze -Wwrite-strings -analyzer-experimental-internal-checks -analyzer-check-objc-mem -analyzer-store=region -analyzer-experimental-checks -verify %s
-// RUN: %clang_cc1 -analyze -DUSE_BUILTINS -Wwrite-strings -analyzer-experimental-internal-checks -analyzer-check-objc-mem -analyzer-store=region -analyzer-experimental-checks -verify %s
-// RUN: %clang_cc1 -analyze -DVARIANT -Wwrite-strings -analyzer-experimental-internal-checks -analyzer-check-objc-mem -analyzer-store=region -analyzer-experimental-checks -verify %s
-// RUN: %clang_cc1 -analyze -DUSE_BUILTINS -DVARIANT -Wwrite-strings -analyzer-experimental-internal-checks -analyzer-check-objc-mem -analyzer-store=region -analyzer-experimental-checks -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -analyzer-check-objc-mem -analyzer-store=region -analyzer-experimental-checks -verify %s
+// RUN: %clang_cc1 -analyze -DUSE_BUILTINS -analyzer-experimental-internal-checks -analyzer-check-objc-mem -analyzer-store=region -analyzer-experimental-checks -verify %s
+// RUN: %clang_cc1 -analyze -DVARIANT -analyzer-experimental-internal-checks -analyzer-check-objc-mem -analyzer-store=region -analyzer-experimental-checks -verify %s
+// RUN: %clang_cc1 -analyze -DUSE_BUILTINS -DVARIANT -analyzer-experimental-internal-checks -analyzer-check-objc-mem -analyzer-store=region -analyzer-experimental-checks -verify %s
 
 //===----------------------------------------------------------------------===
 // Declarations
@@ -35,17 +35,19 @@
 
 void strlen_constant0() {
   if (strlen("123") != 3)
-    (void)*(char*)0;
+    (void)*(char*)0; // no-warning
 }
 
 void strlen_constant1() {
   const char *a = "123";
   if (strlen(a) != 3)
-    (void)*(char*)0;
+    (void)*(char*)0; // no-warning
 }
 
 void strlen_constant2(char x) {
   char a[] = "123";
+  if (strlen(a) != 3)
+    (void)*(char*)0; // no-warning
   a[0] = x;
   if (strlen(a) != 3)
     (void)*(char*)0; // expected-warning{{null}}
@@ -63,3 +65,75 @@
 label:
   return strlen((char*)&&label); // expected-warning{{Argument to byte string function is the address of the label 'label', which is not a null-terminated string}}
 }
+
+void strlen_subregion() {
+  struct two_strings { char a[2], b[2] };
+  extern void use_two_strings(struct two_strings *);
+
+  struct two_strings z;
+  use_two_strings(&z);
+
+  size_t a = strlen(z.a);
+  z.b[0] = 5;
+  size_t b = strlen(z.a);
+  if (a == 0 && b != 0)
+    (void)*(char*)0; // expected-warning{{never executed}}
+
+  use_two_strings(&z);
+
+  size_t c = strlen(z.a);
+  if (a == 0 && c != 0)
+    (void)*(char*)0; // expected-warning{{null}}
+}
+
+extern void use_string(char *);
+void strlen_argument(char *x) {
+  size_t a = strlen(x);
+  size_t b = strlen(x);
+  if (a == 0 && b != 0)
+    (void)*(char*)0; // expected-warning{{never executed}}
+
+  use_string(x);
+
+  size_t c = strlen(x);
+  if (a == 0 && c != 0)
+    (void)*(char*)0; // expected-warning{{null}}  
+}
+
+extern char global_str[];
+void strlen_global() {
+  size_t a = strlen(global_str);
+  size_t b = strlen(global_str);
+  if (a == 0 && b != 0)
+    (void)*(char*)0; // expected-warning{{never executed}}
+
+  // Call a function with unknown effects, which should invalidate globals.
+  use_string(0);
+
+  size_t c = strlen(global_str);
+  if (a == 0 && c != 0)
+    (void)*(char*)0; // expected-warning{{null}}  
+}
+
+void strlen_indirect(char *x) {
+  size_t a = strlen(x);
+  char *p = x;
+  char **p2 = &p;
+  size_t b = strlen(x);
+  if (a == 0 && b != 0)
+    (void)*(char*)0; // expected-warning{{never executed}}
+
+  extern void use_string_ptr(char*const*);
+  use_string_ptr(p2);
+
+  size_t c = strlen(x);
+  if (a == 0 && c != 0)
+    (void)*(char*)0; // expected-warning{{null}}
+}
+
+void strlen_liveness(const char *x) {
+  if (strlen(x) < 5)
+    return;
+  if (strlen(x) < 5)
+    (void)*(char*)0; // no-warning
+}