DataFlowSanitizer; compiler-rt changes.

DataFlowSanitizer is a generalised dynamic data flow analysis.

Unlike other Sanitizer tools, this tool is not designed to detect a
specific class of bugs on its own.  Instead, it provides a generic
dynamic data flow analysis framework to be used by clients to help
detect application-specific issues within their own code.

Differential Revision: http://llvm-reviews.chandlerc.com/D967

llvm-svn: 187924
diff --git a/compiler-rt/lib/dfsan/lit_tests/CMakeLists.txt b/compiler-rt/lib/dfsan/lit_tests/CMakeLists.txt
new file mode 100644
index 0000000..7b800fe
--- /dev/null
+++ b/compiler-rt/lib/dfsan/lit_tests/CMakeLists.txt
@@ -0,0 +1,23 @@
+set(DFSAN_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/..)
+set(DFSAN_BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}/..)
+
+configure_lit_site_cfg(
+  ${CMAKE_CURRENT_SOURCE_DIR}/lit.site.cfg.in
+  ${CMAKE_CURRENT_BINARY_DIR}/lit.site.cfg
+  )
+
+if(COMPILER_RT_CAN_EXECUTE_TESTS)
+  # Run DFSan tests only if we're sure we may produce working binaries.
+  set(DFSAN_TEST_DEPS
+    ${SANITIZER_COMMON_LIT_TEST_DEPS}
+    ${DFSAN_RUNTIME_LIBRARIES})
+  set(DFSAN_TEST_PARAMS
+    dfsan_site_config=${CMAKE_CURRENT_BINARY_DIR}/lit.site.cfg
+    )
+  add_lit_testsuite(check-dfsan "Running the DataFlowSanitizer tests"
+    ${CMAKE_CURRENT_BINARY_DIR}
+    PARAMS ${DFSAN_TEST_PARAMS}
+    DEPENDS ${DFSAN_TEST_DEPS}
+    )
+  set_target_properties(check-dfsan PROPERTIES FOLDER "DFSan tests")
+endif()
diff --git a/compiler-rt/lib/dfsan/lit_tests/basic.c b/compiler-rt/lib/dfsan/lit_tests/basic.c
new file mode 100644
index 0000000..db1acb7
--- /dev/null
+++ b/compiler-rt/lib/dfsan/lit_tests/basic.c
@@ -0,0 +1,17 @@
+// RUN: %clang_dfsan -m64 %s -o %t && %t
+
+// Tests that labels are propagated through loads and stores.
+
+#include <sanitizer/dfsan_interface.h>
+#include <assert.h>
+
+int main(void) {
+  int i = 1;
+  dfsan_label i_label = dfsan_create_label("i", 0);
+  dfsan_set_label(i_label, &i, sizeof(i));
+
+  dfsan_label new_label = dfsan_get_label(i);
+  assert(i_label == new_label);
+
+  return 0;
+}
diff --git a/compiler-rt/lib/dfsan/lit_tests/fncall.c b/compiler-rt/lib/dfsan/lit_tests/fncall.c
new file mode 100644
index 0000000..7d4706f
--- /dev/null
+++ b/compiler-rt/lib/dfsan/lit_tests/fncall.c
@@ -0,0 +1,25 @@
+// RUN: %clang_dfsan -m64 %s -o %t && %t
+
+// Tests that labels are propagated through function calls.
+
+#include <sanitizer/dfsan_interface.h>
+#include <assert.h>
+
+int f(int x) {
+  int j = 2;
+  dfsan_label j_label = dfsan_create_label("j", 0);
+  dfsan_set_label(j_label, &j, sizeof(j));
+  return x + j;
+}
+
+int main(void) {
+  int i = 1;
+  dfsan_label i_label = dfsan_create_label("i", 0);
+  dfsan_set_label(i_label, &i, sizeof(i));
+
+  dfsan_label ij_label = dfsan_get_label(f(i));
+  assert(dfsan_has_label(ij_label, i_label));
+  assert(dfsan_has_label_with_desc(ij_label, "j"));
+
+  return 0;
+}
diff --git a/compiler-rt/lib/dfsan/lit_tests/lit.cfg b/compiler-rt/lib/dfsan/lit_tests/lit.cfg
new file mode 100644
index 0000000..ce39f4a
--- /dev/null
+++ b/compiler-rt/lib/dfsan/lit_tests/lit.cfg
@@ -0,0 +1,66 @@
+# -*- Python -*-
+
+import os
+
+def get_required_attr(config, attr_name):
+  attr_value = getattr(config, attr_name, None)
+  if not attr_value:
+    lit.fatal("No attribute %r in test configuration! You may need to run "
+              "tests from your build directory or add this attribute "
+              "to lit.site.cfg " % attr_name)
+  return attr_value
+
+# Setup config name.
+config.name = 'DataFlowSanitizer'
+
+# Setup source root.
+config.test_source_root = os.path.dirname(__file__)
+
+def DisplayNoConfigMessage():
+  lit.fatal("No site specific configuration available! " +
+            "Try running your test from the build tree or running " +
+            "make check-dfsan")
+
+# Figure out LLVM source root.
+llvm_src_root = getattr(config, 'llvm_src_root', None)
+if llvm_src_root is None:
+  # We probably haven't loaded the site-specific configuration: the user
+  # is likely trying to run a test file directly, and the site configuration
+  # wasn't created by the build system.
+  dfsan_site_cfg = lit.params.get('dfsan_site_config', None)
+  if (dfsan_site_cfg) and (os.path.exists(dfsan_site_cfg)):
+    lit.load_config(config, dfsan_site_cfg)
+    raise SystemExit
+
+  # Try to guess the location of site-specific configuration using llvm-config
+  # util that can point where the build tree is.
+  llvm_config = lit.util.which("llvm-config", config.environment["PATH"])
+  if not llvm_config:
+    DisplayNoConfigMessage()
+
+  # Find out the presumed location of generated site config.
+  llvm_obj_root = lit.util.capture(["llvm-config", "--obj-root"]).strip()
+  dfsan_site_cfg = os.path.join(llvm_obj_root, "projects", "compiler-rt",
+                               "lib", "dfsan", "lit_tests", "lit.site.cfg")
+  if (not dfsan_site_cfg) or (not os.path.exists(dfsan_site_cfg)):
+    DisplayNoConfigMessage()
+
+  lit.load_config(config, dfsan_site_cfg)
+  raise SystemExit
+
+# Setup default compiler flags used with -fsanitize=dataflow option.
+clang_dfsan_cflags = ["-fsanitize=dataflow"]
+clang_dfsan_cxxflags = ["-ccc-cxx "] + clang_dfsan_cflags
+config.substitutions.append( ("%clang_dfsan ",
+                              " ".join([config.clang] + clang_dfsan_cflags) + 
+                              " ") )
+config.substitutions.append( ("%clangxx_dfsan ",
+                              " ".join([config.clang] + clang_dfsan_cxxflags) + 
+                              " ") )
+
+# Default test suffixes.
+config.suffixes = ['.c', '.cc', '.cpp']
+
+# DataFlowSanitizer tests are currently supported on Linux only.
+if config.host_os not in ['Linux']:
+  config.unsupported = True
diff --git a/compiler-rt/lib/dfsan/lit_tests/lit.site.cfg.in b/compiler-rt/lib/dfsan/lit_tests/lit.site.cfg.in
new file mode 100644
index 0000000..7586c14
--- /dev/null
+++ b/compiler-rt/lib/dfsan/lit_tests/lit.site.cfg.in
@@ -0,0 +1,17 @@
+config.target_triple = "@TARGET_TRIPLE@"
+config.host_os = "@HOST_OS@"
+config.llvm_src_root = "@LLVM_SOURCE_DIR@"
+config.llvm_obj_root = "@LLVM_BINARY_DIR@"
+config.llvm_tools_dir = "@LLVM_TOOLS_DIR@"
+config.clang = "@LLVM_BINARY_DIR@/bin/clang"
+
+# LLVM tools dir can be passed in lit parameters, so try to
+# apply substitution.
+try:
+  config.llvm_tools_dir = config.llvm_tools_dir % lit.params
+except KeyError,e:
+  key, = e.args
+  lit.fatal("unable to find %r parameter, use '--param=%s=VALUE'" % (key, key))
+
+# Let the main config do the real work.
+lit.load_config(config, "@DFSAN_SOURCE_DIR@/lit_tests/lit.cfg")
diff --git a/compiler-rt/lib/dfsan/lit_tests/propagate.c b/compiler-rt/lib/dfsan/lit_tests/propagate.c
new file mode 100644
index 0000000..8cc67b8
--- /dev/null
+++ b/compiler-rt/lib/dfsan/lit_tests/propagate.c
@@ -0,0 +1,33 @@
+// RUN: %clang_dfsan -m64 %s -o %t && %t
+
+// Tests that labels are propagated through computation and that union labels
+// are properly created.
+
+#include <sanitizer/dfsan_interface.h>
+#include <assert.h>
+
+int main(void) {
+  int i = 1;
+  dfsan_label i_label = dfsan_create_label("i", 0);
+  dfsan_set_label(i_label, &i, sizeof(i));
+
+  int j = 2;
+  dfsan_label j_label = dfsan_create_label("j", 0);
+  dfsan_set_label(j_label, &j, sizeof(j));
+
+  int k = 3;
+  dfsan_label k_label = dfsan_create_label("k", 0);
+  dfsan_set_label(k_label, &k, sizeof(k));
+
+  dfsan_label ij_label = dfsan_get_label(i + j);
+  assert(dfsan_has_label(ij_label, i_label));
+  assert(dfsan_has_label(ij_label, j_label));
+  assert(!dfsan_has_label(ij_label, k_label));
+
+  dfsan_label ijk_label = dfsan_get_label(i + j + k);
+  assert(dfsan_has_label(ijk_label, i_label));
+  assert(dfsan_has_label(ijk_label, j_label));
+  assert(dfsan_has_label(ijk_label, k_label));
+
+  return 0;
+}