Add CStringChecker support for strnlen.  Patch by Lenny Maiorani!

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@126187 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/test/Analysis/string.c b/test/Analysis/string.c
index baf4893..d19439f 100644
--- a/test/Analysis/string.c
+++ b/test/Analysis/string.c
@@ -140,6 +140,138 @@
 }
 
 //===----------------------------------------------------------------------===
+// strnlen()
+//===----------------------------------------------------------------------===
+
+#define strnlen BUILTIN(strnlen)
+size_t strnlen(const char *s, size_t maxlen);
+
+void strnlen_constant0() {
+  if (strnlen("123", 10) != 3)
+    (void)*(char*)0; // no-warning
+}
+
+void strnlen_constant1() {
+  const char *a = "123";
+  if (strnlen(a, 10) != 3)
+    (void)*(char*)0; // no-warning
+}
+
+void strnlen_constant2(char x) {
+  char a[] = "123";
+  if (strnlen(a, 10) != 3)
+    (void)*(char*)0; // no-warning
+  a[0] = x;
+  if (strnlen(a, 10) != 3)
+    (void)*(char*)0; // expected-warning{{null}}
+}
+
+void strnlen_constant4() {
+  if (strnlen("123456", 3) != 3)
+    (void)*(char*)0; // no-warning
+}
+
+void strnlen_constant5() {
+  const char *a = "123456";
+  if (strnlen(a, 3) != 3)
+    (void)*(char*)0; // no-warning
+}
+
+void strnlen_constant6(char x) {
+  char a[] = "123456";
+  if (strnlen(a, 3) != 3)
+    (void)*(char*)0; // no-warning
+  a[0] = x;
+  if (strnlen(a, 3) != 3)
+    (void)*(char*)0; // expected-warning{{null}}
+}
+
+size_t strnlen_null() {
+  return strnlen(0, 3); // expected-warning{{Null pointer argument in call to byte string function}}
+}
+
+size_t strnlen_fn() {
+  return strnlen((char*)&strlen_fn, 3); // expected-warning{{Argument to byte string function is the address of the function 'strlen_fn', which is not a null-terminated string}}
+}
+
+size_t strnlen_nonloc() {
+label:
+  return strnlen((char*)&&label, 3); // expected-warning{{Argument to byte string function is the address of the label 'label', which is not a null-terminated string}}
+}
+
+void strnlen_subregion() {
+  struct two_stringsn { char a[2], b[2] };
+  extern void use_two_stringsn(struct two_stringsn *);
+
+  struct two_stringsn z;
+  use_two_stringsn(&z);
+
+  size_t a = strnlen(z.a, 10);
+  z.b[0] = 5;
+  size_t b = strnlen(z.a, 10);
+  if (a == 0 && b != 0)
+    (void)*(char*)0; // expected-warning{{never executed}}
+
+  use_two_stringsn(&z);
+
+  size_t c = strnlen(z.a, 10);
+  if (a == 0 && c != 0)
+    (void)*(char*)0; // expected-warning{{null}}
+}
+
+extern void use_stringn(char *);
+void strnlen_argument(char *x) {
+  size_t a = strnlen(x, 10);
+  size_t b = strnlen(x, 10);
+  if (a == 0 && b != 0)
+    (void)*(char*)0; // expected-warning{{never executed}}
+
+  use_stringn(x);
+
+  size_t c = strnlen(x, 10);
+  if (a == 0 && c != 0)
+    (void)*(char*)0; // expected-warning{{null}}  
+}
+
+extern char global_strn[];
+void strnlen_global() {
+  size_t a = strnlen(global_strn, 10);
+  size_t b = strnlen(global_strn, 10);
+  if (a == 0 && b != 0)
+    (void)*(char*)0; // expected-warning{{never executed}}
+
+  // Call a function with unknown effects, which should invalidate globals.
+  use_stringn(0);
+
+  size_t c = strnlen(global_str, 10);
+  if (a == 0 && c != 0)
+    (void)*(char*)0; // expected-warning{{null}}  
+}
+
+void strnlen_indirect(char *x) {
+  size_t a = strnlen(x, 10);
+  char *p = x;
+  char **p2 = &p;
+  size_t b = strnlen(x, 10);
+  if (a == 0 && b != 0)
+    (void)*(char*)0; // expected-warning{{never executed}}
+
+  extern void use_stringn_ptr(char*const*);
+  use_stringn_ptr(p2);
+
+  size_t c = strnlen(x, 10);
+  if (a == 0 && c != 0)
+    (void)*(char*)0; // expected-warning{{null}}
+}
+
+void strnlen_liveness(const char *x) {
+  if (strnlen(x, 10) < 5)
+    return;
+  if (strnlen(x, 10) < 5)
+    (void)*(char*)0; // no-warning
+}
+
+//===----------------------------------------------------------------------===
 // strcpy()
 //===----------------------------------------------------------------------===