[analyzer] Be less pessimistic about invalidation of global variables
as a result of a call.

Problem:
Global variables, which come in from system libraries should not be
invalidated by all calls. Also, non-system globals should not be
invalidated by system calls.

Solution:
The following solution to invalidation of globals seems flexible enough
for taint (does not invalidate stdin) and should not lead to too
many false positives. We split globals into 3 classes:

* immutable - values are preserved by calls (unless the specific
global is passed in as a parameter):
     A :  Most system globals and const scalars

* invalidated by functions defined in system headers:
     B: errno

* invalidated by all other functions (note, these functions may in
turn contain system calls):
     B: errno
     C: all other globals (which are not in A nor B)

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@147569 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/test/Analysis/global-region-invalidation.c b/test/Analysis/global-region-invalidation.c
new file mode 100644
index 0000000..184ffb8
--- /dev/null
+++ b/test/Analysis/global-region-invalidation.c
@@ -0,0 +1,75 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -analyze -disable-free -analyzer-eagerly-assume -analyzer-checker=core,deadcode,experimental.security.taint,debug.TaintTest -verify %s
+
+// Note, we do need to include headers here, since the analyzer checks if the function declaration is located in a system header.
+#include "system-header-simulator.h"
+
+// Test that system header does not invalidate the internal global.
+int size_rdar9373039 = 1;
+int rdar9373039() {
+  int x;
+  int j = 0;
+
+  for (int i = 0 ; i < size_rdar9373039 ; ++i)
+    x = 1;
+
+  // strlen doesn't invalidate the value of 'size_rdar9373039'.
+  int extra = (2 + strlen ("Clang") + ((4 - ((unsigned int) (2 + strlen ("Clang")) % 4)) % 4)) + (2 + strlen ("1.0") + ((4 - ((unsigned int) (2 + strlen ("1.0")) % 4)) % 4));
+
+  for (int i = 0 ; i < size_rdar9373039 ; ++i)
+    j += x; // no-warning
+
+  return j;
+}
+
+// Test stdin does not get invalidated by a system call nor by an internal call.
+void foo();
+int stdinTest() {
+  int i = 0;
+  fscanf(stdin, "%d", &i);
+  foo();
+  int m = i; // expected-warning + {{tainted}}
+  fscanf(stdin, "%d", &i);
+  int j = i; // expected-warning + {{tainted}}
+  return m + j; // expected-warning + {{tainted}}
+}
+
+// Test errno gets invalidated by a system call.
+int testErrnoSystem() {
+  int i;
+  int *p = 0;
+  fscanf(stdin, "%d", &i);
+  if (errno == 0) {
+    fscanf(stdin, "%d", &i); // errno gets invalidated here.
+    return 5 / errno; // no-warning
+  }
+  return 0;
+}
+
+// Test that errno gets invalidated by internal calls.
+int testErrnoInternal() {
+  int i;
+  int *p = 0;
+  fscanf(stdin, "%d", &i);
+  if (errno == 0) {
+    foo(); // errno gets invalidated here.
+    return 5 / errno; // no-warning
+  }
+  return 0;
+}
+
+// Test that const integer does not get invalidated.
+const int x = 0;
+int constIntGlob() {
+  const int *m = &x;
+    foo();
+  return 3 / *m; // expected-warning {{Division by zero}}
+}
+
+extern const int x;
+int constIntGlobExtern() {
+  if (x == 0) {
+    foo();
+    return 5 / x; // expected-warning {{Division by zero}}
+  }
+  return 0;
+}