[compiler-rt] r257972 - Introduce stats and stats_client libraries.

Peter Collingbourne via llvm-commits llvm-commits at lists.llvm.org
Fri Jan 15 16:31:30 PST 2016


Author: pcc
Date: Fri Jan 15 18:31:29 2016
New Revision: 257972

URL: http://llvm.org/viewvc/llvm-project?rev=257972&view=rev
Log:
Introduce stats and stats_client libraries.

This is part of a new statistics gathering feature for the sanitizers.
See clang/docs/SanitizerStats.rst for further info and docs.

Differential Revision: http://reviews.llvm.org/D16176

Added:
    compiler-rt/trunk/lib/stats/
    compiler-rt/trunk/lib/stats/CMakeLists.txt
    compiler-rt/trunk/lib/stats/stats.cc
    compiler-rt/trunk/lib/stats/stats.h
    compiler-rt/trunk/lib/stats/stats_client.cc
    compiler-rt/trunk/test/cfi/cross-dso/stats.cpp
    compiler-rt/trunk/test/cfi/stats.cpp
Modified:
    compiler-rt/trunk/lib/CMakeLists.txt
    compiler-rt/trunk/lib/sanitizer_common/sanitizer_common.h
    compiler-rt/trunk/lib/sanitizer_common/sanitizer_flags.cc
    compiler-rt/trunk/lib/sanitizer_common/sanitizer_flags.h
    compiler-rt/trunk/lib/sanitizer_common/sanitizer_internal_defs.h
    compiler-rt/trunk/lib/sanitizer_common/sanitizer_symbolizer.h
    compiler-rt/trunk/test/cfi/CMakeLists.txt

Modified: compiler-rt/trunk/lib/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/CMakeLists.txt?rev=257972&r1=257971&r2=257972&view=diff
==============================================================================
--- compiler-rt/trunk/lib/CMakeLists.txt (original)
+++ compiler-rt/trunk/lib/CMakeLists.txt Fri Jan 15 18:31:29 2016
@@ -15,6 +15,7 @@ if(COMPILER_RT_BUILD_SANITIZERS)
 
   if(COMPILER_RT_HAS_SANITIZER_COMMON)
     add_subdirectory(sanitizer_common)
+    add_subdirectory(stats)
     add_subdirectory(lsan)
     add_subdirectory(ubsan)
   endif()

Modified: compiler-rt/trunk/lib/sanitizer_common/sanitizer_common.h
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/sanitizer_common/sanitizer_common.h?rev=257972&r1=257971&r2=257972&view=diff
==============================================================================
--- compiler-rt/trunk/lib/sanitizer_common/sanitizer_common.h (original)
+++ compiler-rt/trunk/lib/sanitizer_common/sanitizer_common.h Fri Jan 15 18:31:29 2016
@@ -522,6 +522,19 @@ class InternalMmapVectorNoCtor {
   void clear() { size_ = 0; }
   bool empty() const { return size() == 0; }
 
+  const T *begin() const {
+    return data();
+  }
+  T *begin() {
+    return data();
+  }
+  const T *end() const {
+    return data() + size();
+  }
+  T *end() {
+    return data() + size();
+  }
+
  private:
   void Resize(uptr new_capacity) {
     CHECK_GT(new_capacity, 0);

Modified: compiler-rt/trunk/lib/sanitizer_common/sanitizer_flags.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/sanitizer_common/sanitizer_flags.cc?rev=257972&r1=257971&r2=257972&view=diff
==============================================================================
--- compiler-rt/trunk/lib/sanitizer_common/sanitizer_flags.cc (original)
+++ compiler-rt/trunk/lib/sanitizer_common/sanitizer_flags.cc Fri Jan 15 18:31:29 2016
@@ -45,17 +45,44 @@ void CommonFlags::CopyFrom(const CommonF
   internal_memcpy(this, &other, sizeof(*this));
 }
 
-// Copy the string from "s" to "out", replacing "%b" with the binary basename.
-static void SubstituteBinaryName(const char *s, char *out, uptr out_size) {
+// Copy the string from "s" to "out", making the following substitutions:
+// %b = binary basename
+// %p = pid
+void SubstituteForFlagValue(const char *s, char *out, uptr out_size) {
   char *out_end = out + out_size;
   while (*s && out < out_end - 1) {
-    if (s[0] != '%' || s[1] != 'b') { *out++ = *s++; continue; }
-    const char *base = GetProcessName();
-    CHECK(base);
-    while (*base && out < out_end - 1)
-      *out++ = *base++;
-    s += 2; // skip "%b"
+    if (s[0] != '%') {
+      *out++ = *s++;
+      continue;
+    }
+    switch (s[1]) {
+      case 'b': {
+        const char *base = GetProcessName();
+        CHECK(base);
+        while (*base && out < out_end - 1)
+          *out++ = *base++;
+        s += 2; // skip "%b"
+        break;
+      }
+      case 'p': {
+        int pid = internal_getpid();
+        char buf[32];
+        char *buf_pos = buf + 32;
+        do {
+          *--buf_pos = (pid % 10) + '0';
+          pid /= 10;
+        } while (pid);
+        while (buf_pos < buf + 32 && out < out_end - 1)
+          *out++ = *buf_pos++;
+        s += 2; // skip "%p"
+        break;
+      }
+      default:
+        *out++ = *s++;
+        break;
+    }
   }
+  CHECK(out < out_end - 1);
   *out = '\0';
 }
 
@@ -69,7 +96,7 @@ class FlagHandlerInclude : public FlagHa
   bool Parse(const char *value) final {
     if (internal_strchr(value, '%')) {
       char *buf = (char *)MmapOrDie(kMaxPathLength, "FlagHandlerInclude");
-      SubstituteBinaryName(value, buf, kMaxPathLength);
+      SubstituteForFlagValue(value, buf, kMaxPathLength);
       bool res = parser_->ParseFile(buf, ignore_missing_);
       UnmapOrDie(buf, kMaxPathLength);
       return res;

Modified: compiler-rt/trunk/lib/sanitizer_common/sanitizer_flags.h
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/sanitizer_common/sanitizer_flags.h?rev=257972&r1=257971&r2=257972&view=diff
==============================================================================
--- compiler-rt/trunk/lib/sanitizer_common/sanitizer_flags.h (original)
+++ compiler-rt/trunk/lib/sanitizer_common/sanitizer_flags.h Fri Jan 15 18:31:29 2016
@@ -46,6 +46,8 @@ inline void OverrideCommonFlags(const Co
   common_flags_dont_use.CopyFrom(cf);
 }
 
+void SubstituteForFlagValue(const char *s, char *out, uptr out_size);
+
 class FlagParser;
 void RegisterCommonFlags(FlagParser *parser,
                          CommonFlags *cf = &common_flags_dont_use);

Modified: compiler-rt/trunk/lib/sanitizer_common/sanitizer_internal_defs.h
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/sanitizer_common/sanitizer_internal_defs.h?rev=257972&r1=257971&r2=257972&view=diff
==============================================================================
--- compiler-rt/trunk/lib/sanitizer_common/sanitizer_internal_defs.h (original)
+++ compiler-rt/trunk/lib/sanitizer_common/sanitizer_internal_defs.h Fri Jan 15 18:31:29 2016
@@ -107,10 +107,8 @@ typedef uptr operator_new_size_type;
 #else
 typedef u32 operator_new_size_type;
 #endif
-}  // namespace __sanitizer
 
 
-using namespace __sanitizer;  // NOLINT
 // ----------- ATTENTION -------------
 // This header should NOT include any other headers to avoid portability issues.
 
@@ -188,14 +186,12 @@ typedef void* thread_return_t;
 typedef thread_return_t (THREAD_CALLING_CONV *thread_callback_t)(void* arg);
 
 // NOTE: Functions below must be defined in each run-time.
-namespace __sanitizer {
 void NORETURN Die();
 
 // FIXME: No, this shouldn't be in the sanitizer interface.
 SANITIZER_INTERFACE_ATTRIBUTE
 void NORETURN CheckFailed(const char *file, int line, const char *cond,
                           u64 v1, u64 v2);
-}  // namespace __sanitizer
 
 // Check macro
 #define RAW_CHECK_MSG(expr, msg) do { \
@@ -287,6 +283,9 @@ enum LinkerInitialized { LINKER_INITIALI
 #if !defined(_MSC_VER) || defined(__clang__)
 # define GET_CALLER_PC() (uptr)__builtin_return_address(0)
 # define GET_CURRENT_FRAME() (uptr)__builtin_frame_address(0)
+inline void Trap() {
+  __builtin_trap();
+}
 #else
 extern "C" void* _ReturnAddress(void);
 # pragma intrinsic(_ReturnAddress)
@@ -295,6 +294,12 @@ extern "C" void* _ReturnAddress(void);
 // FIXME: This macro is still used when printing error reports though it's not
 // clear if the BP value is needed in the ASan reports on Windows.
 # define GET_CURRENT_FRAME() (uptr)0xDEADBEEF
+
+extern "C" void __ud2(void);
+# pragma intrinsic(__ud2)
+inline void Trap() {
+  __ud2();
+}
 #endif
 
 #define HANDLE_EINTR(res, f)                                       \
@@ -313,4 +318,8 @@ extern "C" void* _ReturnAddress(void);
     (void)enable_fp;                                               \
   } while (0)
 
+}  // namespace __sanitizer
+
+using namespace __sanitizer;  // NOLINT
+
 #endif  // SANITIZER_DEFS_H

Modified: compiler-rt/trunk/lib/sanitizer_common/sanitizer_symbolizer.h
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/sanitizer_common/sanitizer_symbolizer.h?rev=257972&r1=257971&r2=257972&view=diff
==============================================================================
--- compiler-rt/trunk/lib/sanitizer_common/sanitizer_symbolizer.h (original)
+++ compiler-rt/trunk/lib/sanitizer_common/sanitizer_symbolizer.h Fri Jan 15 18:31:29 2016
@@ -113,6 +113,8 @@ class Symbolizer final {
   void AddHooks(StartSymbolizationHook start_hook,
                 EndSymbolizationHook end_hook);
 
+  LoadedModule *FindModuleForAddress(uptr address);
+
  private:
   // GetModuleNameAndOffsetForPC has to return a string to the caller.
   // Since the corresponding module might get unloaded later, we should create
@@ -139,7 +141,6 @@ class Symbolizer final {
 
   bool FindModuleNameAndOffsetForAddress(uptr address, const char **module_name,
                                          uptr *module_offset);
-  LoadedModule *FindModuleForAddress(uptr address);
   LoadedModule modules_[kMaxNumberOfModules];
   uptr n_modules_;
   // If stale, need to reload the modules before looking up addresses.

Added: compiler-rt/trunk/lib/stats/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/stats/CMakeLists.txt?rev=257972&view=auto
==============================================================================
--- compiler-rt/trunk/lib/stats/CMakeLists.txt (added)
+++ compiler-rt/trunk/lib/stats/CMakeLists.txt Fri Jan 15 18:31:29 2016
@@ -0,0 +1,27 @@
+include_directories(..)
+
+add_custom_target(stats)
+
+if(APPLE)
+  set(STATS_LIB_FLAVOR SHARED)
+else()
+  set(STATS_LIB_FLAVOR STATIC)
+endif()
+
+add_compiler_rt_runtime(clang_rt.stats
+  ${STATS_LIB_FLAVOR}
+  ARCHS ${SANITIZER_COMMON_SUPPORTED_ARCH}
+  OS ${SANITIZER_COMMON_SUPPORTED_OS}
+  SOURCES stats.cc
+  OBJECT_LIBS RTSanitizerCommon
+              RTSanitizerCommonLibc
+  CFLAGS ${SANITIZER_COMMON_CFLAGS}
+  PARENT_TARGET stats)
+
+add_compiler_rt_runtime(clang_rt.stats_client
+  STATIC
+  ARCHS ${SANITIZER_COMMON_SUPPORTED_ARCH}
+  OS ${SANITIZER_COMMON_SUPPORTED_OS}
+  SOURCES stats_client.cc
+  CFLAGS ${SANITIZER_COMMON_CFLAGS}
+  PARENT_TARGET stats)

Added: compiler-rt/trunk/lib/stats/stats.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/stats/stats.cc?rev=257972&view=auto
==============================================================================
--- compiler-rt/trunk/lib/stats/stats.cc (added)
+++ compiler-rt/trunk/lib/stats/stats.cc Fri Jan 15 18:31:29 2016
@@ -0,0 +1,136 @@
+//===-- stats.cc ----------------------------------------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Sanitizer statistics gathering. Manages statistics for a process and is
+// responsible for writing the report file.
+//
+//===----------------------------------------------------------------------===//
+
+#include "sanitizer_common/sanitizer_common.h"
+#include "sanitizer_common/sanitizer_internal_defs.h"
+#if SANITIZER_POSIX
+#include "sanitizer_common/sanitizer_posix.h"
+#endif
+#include "sanitizer_common/sanitizer_symbolizer.h"
+#include "stats/stats.h"
+#if SANITIZER_POSIX
+#include <signal.h>
+#endif
+
+using namespace __sanitizer;
+
+namespace {
+
+InternalMmapVectorNoCtor<StatModule **> modules;
+StaticSpinMutex modules_mutex;
+
+fd_t stats_fd;
+
+void WriteLE(fd_t fd, uptr val) {
+  char chars[sizeof(uptr)];
+  for (unsigned i = 0; i != sizeof(uptr); ++i) {
+    chars[i] = val >> (i * 8);
+  }
+  WriteToFile(fd, chars, sizeof(uptr));
+}
+
+void OpenStatsFile(const char *path_env) {
+  InternalScopedBuffer<char> path(kMaxPathLength);
+  SubstituteForFlagValue(path_env, path.data(), kMaxPathLength);
+
+  error_t err;
+  stats_fd = OpenFile(path.data(), WrOnly, &err);
+  if (stats_fd == kInvalidFd) {
+    Report("stats: failed to open %s for writing (reason: %d)\n", path.data(),
+           err);
+    return;
+  }
+  char sizeof_uptr = sizeof(uptr);
+  WriteToFile(stats_fd, &sizeof_uptr, 1);
+}
+
+void WriteModuleReport(StatModule **smodp) {
+  CHECK(smodp);
+  const char *path_env = GetEnv("SANITIZER_STATS_PATH");
+  if (!path_env || stats_fd == kInvalidFd)
+    return;
+  if (!stats_fd)
+    OpenStatsFile(path_env);
+  LoadedModule *mod = Symbolizer::GetOrInit()->FindModuleForAddress(
+      reinterpret_cast<uptr>(smodp));
+  WriteToFile(stats_fd, mod->full_name(),
+              internal_strlen(mod->full_name()) + 1);
+  for (StatModule *smod = *smodp; smod; smod = smod->next) {
+    for (u32 i = 0; i != smod->size; ++i) {
+      StatInfo *s = &smod->infos[i];
+      if (!s->addr)
+        continue;
+      WriteLE(stats_fd, s->addr - mod->base_address());
+      WriteLE(stats_fd, s->data);
+    }
+  }
+  WriteLE(stats_fd, 0);
+  WriteLE(stats_fd, 0);
+}
+
+} // namespace
+
+extern "C"
+SANITIZER_INTERFACE_ATTRIBUTE
+unsigned __sanitizer_stats_register(StatModule **mod) {
+  SpinMutexLock l(&modules_mutex);
+  modules.push_back(mod);
+  return modules.size() - 1;
+}
+
+extern "C"
+SANITIZER_INTERFACE_ATTRIBUTE
+void __sanitizer_stats_unregister(unsigned index) {
+  SpinMutexLock l(&modules_mutex);
+  WriteModuleReport(modules[index]);
+  modules[index] = 0;
+}
+
+namespace {
+
+void WriteFullReport() {
+  SpinMutexLock l(&modules_mutex);
+  for (StatModule **mod : modules) {
+    if (!mod)
+      continue;
+    WriteModuleReport(mod);
+  }
+  if (stats_fd != 0 && stats_fd != kInvalidFd) {
+    CloseFile(stats_fd);
+    stats_fd = kInvalidFd;
+  }
+}
+
+#if SANITIZER_POSIX
+void USR2Handler(int sig) {
+  WriteFullReport();
+}
+#endif
+
+struct WriteReportOnExitOrSignal {
+  WriteReportOnExitOrSignal() {
+#if SANITIZER_POSIX
+    struct sigaction sigact;
+    internal_memset(&sigact, 0, sizeof(sigact));
+    sigact.sa_handler = USR2Handler;
+    internal_sigaction(SIGUSR2, &sigact, nullptr);
+#endif
+  }
+
+  ~WriteReportOnExitOrSignal() {
+    WriteFullReport();
+  }
+} wr;
+
+} // namespace

Added: compiler-rt/trunk/lib/stats/stats.h
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/stats/stats.h?rev=257972&view=auto
==============================================================================
--- compiler-rt/trunk/lib/stats/stats.h (added)
+++ compiler-rt/trunk/lib/stats/stats.h Fri Jan 15 18:31:29 2016
@@ -0,0 +1,43 @@
+//===-- stats.h -------------------------------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Data definitions for sanitizer statistics gathering.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef SANITIZER_STATS_STATS_H
+#define SANITIZER_STATS_STATS_H
+
+#include "sanitizer_common/sanitizer_internal_defs.h"
+
+namespace __sanitizer {
+
+// Number of bits in data that are used for the sanitizer kind. Needs to match
+// llvm::kSanitizerStatKindBits in
+// llvm/include/llvm/Transforms/Utils/SanitizerStats.h
+enum { kKindBits = 3 };
+
+struct StatInfo {
+  uptr addr;
+  uptr data;
+};
+
+struct StatModule {
+  StatModule *next;
+  u32 size;
+  StatInfo infos[1];
+};
+
+inline uptr CountFromData(uptr data) {
+  return data & ((1ull << (sizeof(uptr) * 8 - kKindBits)) - 1);
+}
+
+}
+
+#endif

Added: compiler-rt/trunk/lib/stats/stats_client.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/stats/stats_client.cc?rev=257972&view=auto
==============================================================================
--- compiler-rt/trunk/lib/stats/stats_client.cc (added)
+++ compiler-rt/trunk/lib/stats/stats_client.cc Fri Jan 15 18:31:29 2016
@@ -0,0 +1,83 @@
+//===-- stats_client.cc ---------------------------------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Sanitizer statistics gathering. Manages statistics for a module (executable
+// or DSO) and registers statistics with the process.
+//
+// This is linked into each individual modle and cannot directly use functions
+// declared in sanitizer_common.
+//
+//===----------------------------------------------------------------------===//
+
+#ifdef _WIN32
+#include <windows.h>
+#else
+#include <dlfcn.h>
+#endif
+#include <stdint.h>
+#include <stdio.h>
+
+#include "sanitizer_common/sanitizer_internal_defs.h"
+#include "stats/stats.h"
+
+using namespace __sanitizer;
+
+namespace {
+
+void *LookupSymbolFromMain(const char *name) {
+#ifdef _WIN32
+  return reinterpret_cast<void *>(GetProcAddress(GetModuleHandle(0), name));
+#else
+  return dlsym(RTLD_DEFAULT, name);
+#endif
+}
+
+StatModule *list;
+
+struct RegisterSanStats {
+  unsigned module_id;
+
+  RegisterSanStats() {
+    typedef unsigned (*reg_func_t)(StatModule **);
+    reg_func_t reg_func = reinterpret_cast<reg_func_t>(
+        LookupSymbolFromMain("__sanitizer_stats_register"));
+    if (reg_func)
+      module_id = reg_func(&list);
+  }
+
+  ~RegisterSanStats() {
+    typedef void (*unreg_func_t)(unsigned);
+    unreg_func_t unreg_func = reinterpret_cast<unreg_func_t>(
+        LookupSymbolFromMain("__sanitizer_stats_unregister"));
+    if (unreg_func)
+      unreg_func(module_id);
+  }
+} reg;
+
+}
+
+extern "C" void __sanitizer_stat_init(StatModule *mod) {
+  mod->next = list;
+  list = mod;
+}
+
+extern "C" void __sanitizer_stat_report(StatInfo *s) {
+  s->addr = GET_CALLER_PC();
+#if defined(_WIN64) && !defined(__clang__)
+  uptr old_data = InterlockedIncrement64(reinterpret_cast<LONG64 *>(&s->data));
+#elif defined(_WIN32) && !defined(__clang__)
+  uptr old_data = InterlockedIncrement(&s->data);
+#else
+  uptr old_data = __sync_fetch_and_add(&s->data, 1);
+#endif
+
+  // Overflow check.
+  if (CountFromData(old_data + 1) == 0)
+    Trap();
+}

Modified: compiler-rt/trunk/test/cfi/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/test/cfi/CMakeLists.txt?rev=257972&r1=257971&r2=257972&view=diff
==============================================================================
--- compiler-rt/trunk/test/cfi/CMakeLists.txt (original)
+++ compiler-rt/trunk/test/cfi/CMakeLists.txt Fri Jan 15 18:31:29 2016
@@ -8,6 +8,8 @@ if(NOT COMPILER_RT_STANDALONE_BUILD)
   list(APPEND CFI_TEST_DEPS
     opt
     ubsan
+    stats
+    sanstats
   )
   if(COMPILER_RT_HAS_CFI)
     list(APPEND CFI_TEST_DEPS cfi)

Added: compiler-rt/trunk/test/cfi/cross-dso/stats.cpp
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/test/cfi/cross-dso/stats.cpp?rev=257972&view=auto
==============================================================================
--- compiler-rt/trunk/test/cfi/cross-dso/stats.cpp (added)
+++ compiler-rt/trunk/test/cfi/cross-dso/stats.cpp Fri Jan 15 18:31:29 2016
@@ -0,0 +1,59 @@
+// RUN: %clangxx_cfi_dso -DSHARED_LIB -fPIC -g -fsanitize-stats -shared -o %t.so %s
+// RUN: %clangxx_cfi_dso -g -fsanitize-stats -o %t %s %t.so
+// RUN: env SANITIZER_STATS_PATH=%t.stats %t
+// RUN: sanstats %t.stats | FileCheck %s
+
+struct ABase {};
+
+struct A : ABase {
+  virtual void vf() {}
+  void nvf() {}
+};
+
+extern "C" void vcall(A *a);
+extern "C" void nvcall(A *a);
+
+#ifdef SHARED_LIB
+
+extern "C" __attribute__((noinline)) void vcall(A *a) {
+  // CHECK: stats.cpp:[[@LINE+1]] vcall cfi-vcall 37
+  a->vf();
+}
+
+extern "C" __attribute__((noinline)) void nvcall(A *a) {
+  // CHECK: stats.cpp:[[@LINE+1]] nvcall cfi-nvcall 51
+  a->nvf();
+}
+
+#else
+
+extern "C" __attribute__((noinline)) A *dcast(A *a) {
+  // CHECK: stats.cpp:[[@LINE+1]] dcast cfi-derived-cast 24
+  return (A *)(ABase *)a;
+}
+
+extern "C" __attribute__((noinline)) A *ucast(A *a) {
+  // CHECK: stats.cpp:[[@LINE+1]] ucast cfi-unrelated-cast 81
+  return (A *)(char *)a;
+}
+
+extern "C" __attribute__((noinline)) void unreachable(A *a) {
+  // CHECK-NOT: unreachable
+  a->vf();
+}
+
+int main() {
+  A a;
+  for (unsigned i = 0; i != 37; ++i)
+    vcall(&a);
+  for (unsigned i = 0; i != 51; ++i)
+    nvcall(&a);
+  for (unsigned i = 0; i != 24; ++i)
+    dcast(&a);
+  for (unsigned i = 0; i != 81; ++i)
+    ucast(&a);
+  for (unsigned i = 0; i != 0; ++i)
+    unreachable(&a);
+}
+
+#endif

Added: compiler-rt/trunk/test/cfi/stats.cpp
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/test/cfi/stats.cpp?rev=257972&view=auto
==============================================================================
--- compiler-rt/trunk/test/cfi/stats.cpp (added)
+++ compiler-rt/trunk/test/cfi/stats.cpp Fri Jan 15 18:31:29 2016
@@ -0,0 +1,49 @@
+// RUN: %clangxx_cfi -g -fsanitize-stats -o %t %s
+// RUN: env SANITIZER_STATS_PATH=%t.stats %t
+// RUN: sanstats %t.stats | FileCheck %s
+
+struct ABase {};
+
+struct A : ABase {
+  virtual void vf() {}
+  void nvf() {}
+};
+
+extern "C" __attribute__((noinline)) void vcall(A *a) {
+  // CHECK: stats.cpp:[[@LINE+1]] vcall cfi-vcall 37
+  a->vf();
+}
+
+extern "C" __attribute__((noinline)) void nvcall(A *a) {
+  // CHECK: stats.cpp:[[@LINE+1]] nvcall cfi-nvcall 51
+  a->nvf();
+}
+
+extern "C" __attribute__((noinline)) A *dcast(A *a) {
+  // CHECK: stats.cpp:[[@LINE+1]] dcast cfi-derived-cast 24
+  return (A *)(ABase *)a;
+}
+
+extern "C" __attribute__((noinline)) A *ucast(A *a) {
+  // CHECK: stats.cpp:[[@LINE+1]] ucast cfi-unrelated-cast 81
+  return (A *)(char *)a;
+}
+
+extern "C" __attribute__((noinline)) void unreachable(A *a) {
+  // CHECK-NOT: unreachable
+  a->vf();
+}
+
+int main() {
+  A a;
+  for (unsigned i = 0; i != 37; ++i)
+    vcall(&a);
+  for (unsigned i = 0; i != 51; ++i)
+    nvcall(&a);
+  for (unsigned i = 0; i != 24; ++i)
+    dcast(&a);
+  for (unsigned i = 0; i != 81; ++i)
+    ucast(&a);
+  for (unsigned i = 0; i != 0; ++i)
+    unreachable(&a);
+}




More information about the llvm-commits mailing list