Added tests for the safestack runtime support library.

http://reviews.llvm.org/D6096

Files:
  CMakeLists.txt
  cmake/config-ix.cmake
  include/CMakeLists.txt
  include/safestack_interface.h
  lib/CMakeLists.txt
  lib/Makefile.mk
  lib/safestack/CMakeLists.txt
  lib/safestack/Makefile.mk
  lib/safestack/safestack.cc
  make/platform/clang_darwin.mk
  make/platform/clang_linux.mk
  test/CMakeLists.txt
  test/safestack/CMakeLists.txt
  test/safestack/check-buffer-copy.c
  test/safestack/check-init.c
  test/safestack/check-overflow.c
  test/safestack/check-pthread-cleanup.c
  test/safestack/check-pthread.c
  test/safestack/lit.cfg
  test/safestack/lit.site.cfg.in
Index: CMakeLists.txt
===================================================================
--- CMakeLists.txt
+++ CMakeLists.txt
@@ -239,6 +239,7 @@
 append_list_if(COMPILER_RT_HAS_FOMIT_FRAME_POINTER_FLAG -fomit-frame-pointer SANITIZER_COMMON_CFLAGS)
 append_list_if(COMPILER_RT_HAS_FUNWIND_TABLES_FLAG -funwind-tables SANITIZER_COMMON_CFLAGS)
 append_list_if(COMPILER_RT_HAS_FNO_STACK_PROTECTOR_FLAG -fno-stack-protector SANITIZER_COMMON_CFLAGS)
+append_list_if(COMPILER_RT_HAS_FNO_SAFE_STACK_FLAG -fno-safe-stack SANITIZER_COMMON_CFLAGS)
 append_list_if(COMPILER_RT_HAS_FVISIBILITY_HIDDEN_FLAG -fvisibility=hidden SANITIZER_COMMON_CFLAGS)
 append_list_if(COMPILER_RT_HAS_FNO_FUNCTION_SECTIONS_FLAG -fno-function-sections SANITIZER_COMMON_CFLAGS)
 
Index: cmake/config-ix.cmake
===================================================================
--- cmake/config-ix.cmake
+++ cmake/config-ix.cmake
@@ -10,6 +10,7 @@
 check_cxx_compiler_flag(-fomit-frame-pointer COMPILER_RT_HAS_FOMIT_FRAME_POINTER_FLAG)
 check_cxx_compiler_flag(-funwind-tables      COMPILER_RT_HAS_FUNWIND_TABLES_FLAG)
 check_cxx_compiler_flag(-fno-stack-protector COMPILER_RT_HAS_FNO_STACK_PROTECTOR_FLAG)
+check_cxx_compiler_flag(-fno-safe-stack      COMPILER_RT_HAS_FNO_SAFE_STACK_FLAG)
 check_cxx_compiler_flag(-fvisibility=hidden  COMPILER_RT_HAS_FVISIBILITY_HIDDEN_FLAG)
 check_cxx_compiler_flag(-fno-rtti            COMPILER_RT_HAS_FNO_RTTI_FLAG)
 check_cxx_compiler_flag(-ffreestanding       COMPILER_RT_HAS_FFREESTANDING_FLAG)
@@ -182,6 +183,7 @@
 filter_available_targets(PROFILE_SUPPORTED_ARCH x86_64 i386 i686 arm mips mips64 mipsel mips64el aarch64)
 filter_available_targets(TSAN_SUPPORTED_ARCH x86_64)
 filter_available_targets(UBSAN_SUPPORTED_ARCH x86_64 i386 i686 arm aarch64 mips mipsel)
+filter_available_targets(SAFESTACK_SUPPORTED_ARCH x86_64 i386 i686)
 
 if(ANDROID)
   set(OS_NAME "Android")
@@ -254,3 +256,9 @@
   set(COMPILER_RT_HAS_UBSAN FALSE)
 endif()
 
+if (SAFESTACK_SUPPORTED_ARCH AND
+    OS_NAME MATCHES "Darwin|Linux|FreeBSD")
+  set(COMPILER_RT_HAS_SAFESTACK TRUE)
+else()
+  set(COMPILER_RT_HAS_SAFESTACK FALSE)
+endif()
Index: include/CMakeLists.txt
===================================================================
--- include/CMakeLists.txt
+++ include/CMakeLists.txt
@@ -6,7 +6,8 @@
   sanitizer/linux_syscall_hooks.h
   sanitizer/lsan_interface.h
   sanitizer/msan_interface.h
-  sanitizer/tsan_interface_atomic.h)
+  sanitizer/tsan_interface_atomic.h
+  safestack_interface.h)
 
 set(output_dir ${COMPILER_RT_OUTPUT_DIR}/include)
 
Index: include/safestack_interface.h
===================================================================
--- /dev/null
+++ include/safestack_interface.h
@@ -0,0 +1,20 @@
+#ifndef SAFESTACK_INTERFACE_H
+#define SAFESTACK_INTERFACE_H
+
+#include <stddef.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void *__safestack_get_unsafe_stack_start();
+void *__safestack_get_unsafe_stack_ptr();
+size_t __safestack_get_unsafe_stack_size();
+
+void *__safestack_get_safe_stack_ptr();
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif // SAFESTACK_INTERFACE_H
Index: lib/CMakeLists.txt
===================================================================
--- lib/CMakeLists.txt
+++ lib/CMakeLists.txt
@@ -41,3 +41,4 @@
   add_subdirectory(ubsan)
 endif()
 
+add_subdirectory(safestack)
Index: lib/Makefile.mk
===================================================================
--- lib/Makefile.mk
+++ lib/Makefile.mk
@@ -20,3 +20,4 @@
 SubDirs += sanitizer_common
 SubDirs += tsan
 SubDirs += ubsan
+SubDirs += safestack
Index: lib/safestack/CMakeLists.txt
===================================================================
--- /dev/null
+++ lib/safestack/CMakeLists.txt
@@ -0,0 +1,26 @@
+add_custom_target(safestack)
+
+set(SAFESTACK_SOURCES safestack.cc)
+
+include_directories(..)
+
+set(SAFESTACK_CFLAGS ${SANITIZER_COMMON_CFLAGS})
+
+if(APPLE)
+  # Build universal binary on APPLE.
+  add_compiler_rt_osx_static_runtime(clang_rt.safestack_osx
+    ARCH ${SAFESTACK_SUPPORTED_ARCH}
+    SOURCES ${SAFESTACK_SOURCES}
+            $<TARGET_OBJECTS:RTInterception.osx>
+    CFLAGS ${SAFESTACK_CFLAGS})
+  add_dependencies(safestack clang_rt.safestack_osx)
+else()
+  # Otherwise, build separate libraries for each target.
+  foreach(arch ${SAFESTACK_SUPPORTED_ARCH})
+      add_compiler_rt_runtime(clang_rt.safestack-${arch} ${arch} STATIC
+      SOURCES ${SAFESTACK_SOURCES}
+              $<TARGET_OBJECTS:RTInterception.${arch}>
+      CFLAGS ${SAFESTACK_CFLAGS})
+      add_dependencies(safestack clang_rt.safestack-${arch})
+  endforeach()
+endif()
Index: lib/safestack/Makefile.mk
===================================================================
--- /dev/null
+++ lib/safestack/Makefile.mk
@@ -0,0 +1,23 @@
+#===- lib/safestack/Makefile.mk ------------------------------*- Makefile -*--===#
+#
+#                     The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+#===------------------------------------------------------------------------===#
+
+ModuleName := safestack
+SubDirs :=
+
+Sources := $(foreach file,$(wildcard $(Dir)/*.cc),$(notdir $(file)))
+ObjNames := $(Sources:%.cc=%.o)
+
+Implementation := Generic
+
+# FIXME: use automatic dependencies?
+Dependencies := $(wildcard $(Dir)/*.h)
+Dependencies += $(wildcard $(Dir)/../interception/*.h)
+
+# Define a convenience variable for all the safestack functions.
+SafeStackFunctions := $(Sources:%.cc=%)
Index: lib/safestack/safestack.cc
===================================================================
--- /dev/null
+++ lib/safestack/safestack.cc
@@ -0,0 +1,358 @@
+//===-- safestack.cc --------------------------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements the runtime support for the safe stack protection
+// mechanism. The runtime manages allocation/deallocation of the unsafe stack
+// for the main thread, as well as all pthreads threads that are
+// created/destroyed during program execution.
+//
+//===----------------------------------------------------------------------===//
+
+#include <stdio.h>
+#include <assert.h>
+#include <dlfcn.h>
+#include <limits.h>
+#include <sys/mman.h>
+#include <sys/user.h>
+#include <sys/resource.h>
+#include <pthread.h>
+#include <errno.h>
+#include <stdlib.h>
+
+#if defined(__linux__)
+#include <unistd.h>
+#include <sys/syscall.h>
+#endif
+
+/// Minimum stack alignment for the unsafe stack.
+/// FIXME: is this in some header?
+#define STACK_ALIGN 16
+
+/// Default size of the unsafe stack. This value is only used if the stack
+/// size rlimit is set to infinity.
+#define DEFAULT_UNSAFE_STACK_SIZE 0x2800000
+
+
+// define MAP_STACK if undefined, this flag is used as a hint
+#ifndef MAP_STACK
+# define MAP_STACK 0
+#endif
+
+// define MAP_GROWSDOWN if undefined, this flag is used as a hint
+#ifndef MAP_GROWSDOWN
+# define MAP_GROWSDOWN 0
+#endif
+
+// define mmap wrapper, on Apple you can't override the mmap symbol
+// but on Linux it is possible, so we use syscall to ensure calling
+// kernel's mmap
+#if defined(__APPLE__)
+# define safestack_mmap(Args...) mmap(Args)
+# define safestack_munmap(Args...) munmap(Args)
+#else
+# define safestack_mmap(Args...) (void *)syscall(SYS_mmap, Args)
+# define safestack_munmap(Args...) (int)syscall(SYS_munmap, Args)
+#endif
+
+#include "interception/interception.h"
+
+namespace __llvm__safestack {
+
+// We don't know whether pthread is linked in or not, so we resolve
+// all symbols from pthread that we use dynamically
+#define __DECLARE_WRAPPER(fn) __typeof__(fn)* __d_ ## fn = NULL;
+
+__DECLARE_WRAPPER(pthread_attr_init)
+__DECLARE_WRAPPER(pthread_attr_destroy)
+__DECLARE_WRAPPER(pthread_attr_getstacksize)
+__DECLARE_WRAPPER(pthread_attr_getguardsize)
+__DECLARE_WRAPPER(pthread_key_create)
+__DECLARE_WRAPPER(pthread_setspecific)
+
+// The unsafe stack pointer is stored in the TCB structure on these platforms
+#if defined(__i386__)
+# define MOVPTR "movl"
+# ifdef __pic__
+#  define IMM_MODE "nr"
+# else
+#  define IMM_MODE "ir"
+# endif
+#elif defined(__x86_64__)
+# define MOVPTR "movq"
+# define IMM_MODE "nr"
+#endif
+
+#if defined(__APPLE__) && (defined(__i386__) || defined(__x86_64__))
+
+  /* On Darwin, we store the unsafe stack pointer in one of the
+   * thread-specific data slots that are reserved for system libraries.
+   * Such data slots are directly accessible through the %gs segment, and
+   * are described in detail in pthreads/pthread_machdep.h in Darwin Libc.
+   * As of Libc-825, slots 0 - 255 are reserved, but only slots 0 - 119
+   * are actually used. We use slot 192, which is accessible as
+   * %gs:(192 * sizeof(void*))
+   */
+
+# define __THREAD_GETMEM_L(slot)                            \
+  __extension__ ({ unsigned long  __v;                      \
+      asm volatile (MOVPTR " %%gs:%P1,%q0" : "=r" (__v)     \
+                    : "i" ((slot) * sizeof(void*))); __v; })
+
+# define __THREAD_SETMEM_L(slot, value)               \
+  asm volatile (MOVPTR " %q0,%%gs:%P1" :              \
+                : IMM_MODE ((unsigned long) (value)), \
+                  "i" ((slot) * sizeof(void*)))
+
+// The following locations are platform-specific
+# define __GET_UNSAFE_STACK_PTR()         (void*) __THREAD_GETMEM_L(192)
+# define __SET_UNSAFE_STACK_PTR(value)    __THREAD_SETMEM_L(192, value)
+
+#else
+
+  /* TODO: To make accessing the unsafe stack pointer faster, we plan to
+   * eventually store it directly in the thread control block data structure on
+   * platforms where this structure is pointed to by %fs or %gs. This is exactly
+   * the same mechanism as currently being used by the traditional stack
+   * protector pass to store the stack guard (see getStackCookieLocation()
+   * function above). Doing so requires changing the tcbhead_t struct in glibc
+   * on Linux and tcb struct in libc on FreeBSD.
+   */
+
+// The unsafe stack is stored in a thread-local variable on all other platforms
+extern "C" {
+  __attribute__((visibility ("default")))
+  __thread void  *__llvm__unsafe_stack_ptr = 0;
+}
+
+# define __GET_UNSAFE_STACK_PTR()         __llvm__unsafe_stack_ptr
+# define __SET_UNSAFE_STACK_PTR(value)    __llvm__unsafe_stack_ptr = (value)
+
+#endif
+
+// Per-thread unsafe stack information. It's not frequently accessed, so there
+// it can be kept out of the tcb in normal thread-local variables.
+static __thread void  *unsafe_stack_start = 0;
+static __thread size_t unsafe_stack_size = 0;
+static __thread size_t unsafe_stack_guard = 0;
+
+# define __GET_UNSAFE_STACK_START()       unsafe_stack_start
+# define __SET_UNSAFE_STACK_START(value)  unsafe_stack_start = (value)
+
+# define __GET_UNSAFE_STACK_SIZE()        unsafe_stack_size
+# define __SET_UNSAFE_STACK_SIZE(value)   unsafe_stack_size = (value)
+
+# define __GET_UNSAFE_STACK_GUARD()       unsafe_stack_guard
+# define __SET_UNSAFE_STACK_GUARD(value)  unsafe_stack_guard = (value)
+
+static inline void *unsafe_stack_alloc(size_t size, size_t guard) {
+  // We need the mmap system call without any LD_PRELOAD overrides
+  // (such overrides might crash is they use the unsafe stack themselves)
+  void *addr = safestack_mmap(NULL, size + guard, PROT_WRITE  | PROT_READ,
+                MAP_PRIVATE | MAP_ANON | MAP_STACK | MAP_GROWSDOWN, -1, 0);
+
+  if (addr == MAP_FAILED)
+    return nullptr;
+
+  mprotect(addr, guard, PROT_NONE);
+  return (char*) addr + guard;
+}
+
+static inline void unsafe_stack_setup(void *start, size_t size, size_t guard) {
+  void* stack_ptr = (char*) start + size;
+  assert((((size_t)stack_ptr) & (STACK_ALIGN-1)) == 0);
+
+  __SET_UNSAFE_STACK_PTR(stack_ptr);
+  __SET_UNSAFE_STACK_START(start);
+  __SET_UNSAFE_STACK_SIZE(size);
+  __SET_UNSAFE_STACK_GUARD(guard);
+}
+
+static void unsafe_stack_free() {
+  if (__GET_UNSAFE_STACK_START()) {
+    // We need the munmap system call without any LD_PRELOAD overrides
+    // (such overrides might crash is they use the unsafe stack themselves)
+    (void)safestack_munmap(
+      (char*) __GET_UNSAFE_STACK_START() - __GET_UNSAFE_STACK_GUARD(),
+      __GET_UNSAFE_STACK_SIZE() + __GET_UNSAFE_STACK_GUARD());
+  }
+  __SET_UNSAFE_STACK_START(0);
+}
+
+/// Thread data for the cleanup handler
+pthread_key_t thread_cleanup_key;
+
+/// Safe stack per-thread information passed to the thread_start function
+struct tinfo {
+  void *(*start_routine)(void*);
+  void *start_routine_arg;
+
+  void *unsafe_stack_start;
+  size_t unsafe_stack_size;
+  size_t unsafe_stack_guard;
+};
+
+/// Wrap the thread function in order to deallocate the unsafe stack when the
+/// thread terminates by returning from its main function.
+static void* thread_start(void *arg) {
+  struct tinfo *tinfo = (struct tinfo*) arg;
+
+  void *(*start_routine)(void*) = tinfo->start_routine;
+  void *start_routine_arg = tinfo->start_routine_arg;
+
+  // Setup the unsafe stack; this will destroy tinfo content
+  unsafe_stack_setup(tinfo->unsafe_stack_start,
+                     tinfo->unsafe_stack_size,
+                     tinfo->unsafe_stack_guard);
+
+  // Make sure out thread-specific destructor will be called
+  // FIXME: we can do this only any other specific key is set by
+  // intersepting the pthread_setspecific function itself
+  __d_pthread_setspecific(thread_cleanup_key, (void*) 1);
+
+  // Start the original thread rutine
+  return start_routine(start_routine_arg);
+}
+
+/// Intercept thread creation operation to allocate and setup the unsafe stack
+INTERCEPTOR(int, pthread_create, pthread_t *thread,
+            const pthread_attr_t *attr,
+            void *(*start_routine)(void*), void *arg) {
+
+  size_t size = 0;
+  size_t guard = 0;
+
+  if (attr != NULL) {
+    __d_pthread_attr_getstacksize(attr, &size);
+    __d_pthread_attr_getguardsize(attr, &guard);
+  } else {
+    // get pthread default stack size
+    pthread_attr_t tmpattr;
+    __d_pthread_attr_init(&tmpattr);
+    __d_pthread_attr_getstacksize(&tmpattr, &size);
+    __d_pthread_attr_getguardsize(&tmpattr, &guard);
+    __d_pthread_attr_destroy(&tmpattr);
+  }
+
+  assert(size != 0);
+  assert((size & (STACK_ALIGN-1)) == 0);
+  assert((guard & (PAGE_SIZE-1)) == 0);
+
+  void *addr = unsafe_stack_alloc(size, guard);
+  if (!addr) {
+    // failed to allocate the unsafe stack
+    errno = EAGAIN;
+    return -1;
+  }
+  struct tinfo *tinfo = (struct tinfo*) (
+        ((char*)addr) + size - sizeof(struct tinfo));
+  tinfo->start_routine = start_routine;
+  tinfo->start_routine_arg = arg;
+  tinfo->unsafe_stack_start = addr;
+  tinfo->unsafe_stack_size = size;
+  tinfo->unsafe_stack_guard = guard;
+
+  return REAL(pthread_create)(thread, attr, thread_start, tinfo);
+}
+
+/// Thread-specific data destructor
+void thread_cleanup_handler(void* _iter) {
+  // We want to free the unsafe stack only after all other destructors
+  // have already run. We force this function to be called multiple times.
+  // User destructors that might run more then PTHREAD_DESTRUCTOR_ITERATIONS-1
+  // times might still end up executing after the unsafe stack is deallocated,
+  // so such descructors must have __attribute__((no_safe_stack)).
+  size_t iter = (size_t) _iter;
+  if (iter < PTHREAD_DESTRUCTOR_ITERATIONS) {
+    __d_pthread_setspecific(thread_cleanup_key, (void*) (iter + 1));
+  } else {
+    // This is the last iteration
+    unsafe_stack_free();
+  }
+}
+
+extern "C"
+__attribute__((visibility ("default")))
+#ifndef __ELF__
+// On ELF platforms, the constructor is invoked using .preinit_array (see below)
+__attribute__((constructor(0)))
+#endif
+void __llvm__safestack_init() {
+  static int initialized = 0;
+
+  if (initialized)
+    return;
+
+  initialized = 1;
+
+  // Determine the stack size for the main thread.
+  size_t size = DEFAULT_UNSAFE_STACK_SIZE;
+  size_t guard = 4096;
+
+  struct rlimit limit;
+  if (getrlimit(RLIMIT_STACK, &limit) != 0
+      || limit.rlim_cur == RLIM_INFINITY)
+    size = limit.rlim_cur;
+
+  // Allocate unsafe stack for main thread
+  void *addr = unsafe_stack_alloc(size, guard);
+  if (!addr)
+    // Failed to allocate the unsafe stack.
+    abort();
+
+  unsafe_stack_setup(addr, size, guard);
+
+  // Initialize pthread interceptors for thread allocation
+  INTERCEPT_FUNCTION(pthread_create);
+
+  #define __FIND_FUNCTION(fn) \
+    __d_ ## fn = __extension__ (__typeof__(__d_ ## fn)) dlsym(RTLD_DEFAULT, #fn);
+
+  // Find pthread functions that we need
+  __FIND_FUNCTION(pthread_attr_init)
+  __FIND_FUNCTION(pthread_attr_destroy)
+  __FIND_FUNCTION(pthread_attr_getstacksize)
+  __FIND_FUNCTION(pthread_attr_getguardsize)
+  __FIND_FUNCTION(pthread_key_create)
+  __FIND_FUNCTION(pthread_setspecific)
+
+  if (__d_pthread_key_create != NULL) {
+    // We're using pthreads, setup the cleanup handler
+    __d_pthread_key_create(&thread_cleanup_key, thread_cleanup_handler);
+  }
+}
+
+#ifdef __ELF__
+// Run safestack initialization before any other constructors.
+// FIXME: can we do something similar on non-ELF platforms, e.g., on Mac?
+extern "C" {
+__attribute__((section(".preinit_array"), used))
+void (*__llvm__safestack_preinit)(void) = __llvm__safestack_init;
+}
+#endif
+
+extern "C"
+__attribute__((visibility ("default")))
+void *__safestack_get_unsafe_stack_start() {
+  return __GET_UNSAFE_STACK_START();
+}
+
+extern "C"
+__attribute__((visibility ("default")))
+void *__safestack_get_unsafe_stack_ptr() {
+  return __GET_UNSAFE_STACK_PTR();
+}
+
+extern "C"
+__attribute__((visibility ("default")))
+__attribute__((noinline)) // required for __builtin_frame_address(0) to work
+void *__safestack_get_safe_stack_ptr() {
+  return (char*) __builtin_frame_address(0) + 2*sizeof(void*);
+}
+
+} // namespace __llvm__safestack
Index: make/platform/clang_darwin.mk
===================================================================
--- make/platform/clang_darwin.mk
+++ make/platform/clang_darwin.mk
@@ -106,6 +106,10 @@
 Configs += ubsan_osx
 UniversalArchs.ubsan_osx := $(call CheckArches,i386 x86_64 x86_64h,ubsan_osx)
 
+# Configurations which define the safestack support functions.
+Configs += safestack_osx
+UniversalArchs.safestack_osx = $(call CheckArches,i386 x86_64 x86_64h,safestack_osx)
+
 # Darwin 10.6 has a bug in cctools that makes it unable to use ranlib on our ARM
 # object files. If we are on that platform, strip out all ARM archs. We still
 # build the libraries themselves so that Clang can find them where it expects
@@ -170,6 +174,10 @@
 
 CFLAGS.ubsan_osx := $(CFLAGS) -mmacosx-version-min=10.6 -fno-builtin
 
+CFLAGS.safestack_osx := \
+	$(CFLAGS) -fno-rtti -fno-exceptions -fno-builtin \
+	-fno-stack-protector -fno-safe-stack
+
 CFLAGS.ios.i386		:= $(CFLAGS) $(IOSSIM_DEPLOYMENT_ARGS)
 CFLAGS.ios.x86_64	:= $(CFLAGS) $(IOSSIM_DEPLOYMENT_ARGS)
 CFLAGS.ios.x86_64h	:= $(CFLAGS) $(IOSSIM_DEPLOYMENT_ARGS)
@@ -244,6 +252,8 @@
 FUNCTIONS.ubsan_osx := $(UbsanFunctions) $(UbsanCXXFunctions) \
                        $(SanitizerCommonFunctions)
 
+FUNCTIONS.safestack_osx := $(SafeStackFunctions) $(InterceptionFunctions)
+
 CCKEXT_COMMON_FUNCTIONS := \
 	absvdi2 \
 	absvsi2 \
Index: make/platform/clang_linux.mk
===================================================================
--- make/platform/clang_linux.mk
+++ make/platform/clang_linux.mk
@@ -50,21 +50,22 @@
 # Build runtime libraries for i386.
 ifeq ($(call contains,$(SupportedArches),i386),true)
 Configs += builtins-i386 profile-i386 san-i386 asan-i386 asan_cxx-i386 \
-	   ubsan-i386 ubsan_cxx-i386
+	   ubsan-i386 ubsan_cxx-i386 safestack-i386
 Arch.builtins-i386 := i386
 Arch.profile-i386 := i386
 Arch.san-i386 := i386
 Arch.asan-i386 := i386
 Arch.asan_cxx-i386 := i386
 Arch.ubsan-i386 := i386
 Arch.ubsan_cxx-i386 := i386
+Arch.safestack-i386 := i386
 endif
 
 # Build runtime libraries for x86_64.
 ifeq ($(call contains,$(SupportedArches),x86_64),true)
 Configs += builtins-x86_64 profile-x86_64 san-x86_64 asan-x86_64 asan_cxx-x86_64 \
 	   tsan-x86_64 msan-x86_64 ubsan-x86_64 ubsan_cxx-x86_64 dfsan-x86_64 \
-	   lsan-x86_64
+	   lsan-x86_64 safestack-x86_64
 Arch.builtins-x86_64 := x86_64
 Arch.profile-x86_64 := x86_64
 Arch.san-x86_64 := x86_64
@@ -76,6 +77,7 @@
 Arch.ubsan_cxx-x86_64 := x86_64
 Arch.dfsan-x86_64 := x86_64
 Arch.lsan-x86_64 := x86_64
+Arch.safestack-x86_64 := x86_64
 endif
 
 endif
@@ -110,6 +112,10 @@
 CFLAGS.ubsan_cxx-x86_64 := $(CFLAGS) -m64 $(SANITIZER_CFLAGS)
 CFLAGS.dfsan-x86_64 := $(CFLAGS) -m64 $(SANITIZER_CFLAGS) -fno-rtti
 CFLAGS.lsan-x86_64 := $(CFLAGS) -m64 $(SANITIZER_CFLAGS) -fno-rtti
+CFLAGS.safestack-i386 := $(CFLAGS) -m32 -fPIE -fno-builtin -fno-exceptions \
+				-fno-rtti -fno-stack-protector -fno-safe-stack
+CFLAGS.safestack-x86_64 := $(CFLAGS) -m64 -fPIE -fno-builtin -fno-exceptions \
+				-fno-rtti -fno-stack-protector -fno-safe-stack
 
 SHARED_LIBRARY.asan-arm-android := 1
 ANDROID_COMMON_FLAGS := -target arm-linux-androideabi \
@@ -156,6 +162,8 @@
                                             $(SanitizerCommonFunctions)
 FUNCTIONS.lsan-x86_64 := $(LsanFunctions) $(InterceptionFunctions) \
                                           $(SanitizerCommonFunctions)
+FUNCTIONS.safestack-i386 := $(SafeStackFunctions) $(InterceptionFunctions)
+FUNCTIONS.safestack-x86_64 := $(SafeStackFunctions) $(InterceptionFunctions)
 
 # Always use optimized variants.
 OPTIMIZED := 1
Index: test/CMakeLists.txt
===================================================================
--- test/CMakeLists.txt
+++ test/CMakeLists.txt
@@ -48,6 +48,9 @@
   if(COMPILER_RT_HAS_UBSAN)
     add_subdirectory(ubsan)
   endif()
+  if(COMPILER_RT_HAS_SAFESTACK)
+    add_subdirectory(safestack)
+  endif()
 endif()
 
 if(COMPILER_RT_STANDALONE_BUILD)
Index: test/safestack/CMakeLists.txt
===================================================================
--- /dev/null
+++ test/safestack/CMakeLists.txt
@@ -0,0 +1,16 @@
+set(SAFESTACK_LIT_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR})
+set(SAFESTACK_LIT_BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR})
+
+if(NOT COMPILER_RT_STANDALONE_BUILD)
+  list(APPEND SAFESTACK_TEST_DEPS safetstack)
+endif()
+
+configure_lit_site_cfg(
+  ${CMAKE_CURRENT_SOURCE_DIR}/lit.site.cfg.in
+  ${CMAKE_CURRENT_BINARY_DIR}/lit.site.cfg
+  )
+
+add_lit_testsuite(check-safestack "Running the SafeStack tests"
+  ${CMAKE_CURRENT_BINARY_DIR}
+  DEPENDS ${SAFESTACK_TEST_DEPS})
+set_target_properties(check-safestack PROPERTIES FOLDER "SafeStack tests")
Index: test/safestack/check-buffer-copy.c
===================================================================
--- /dev/null
+++ test/safestack/check-buffer-copy.c
@@ -0,0 +1,19 @@
+// RUN: %clang_safestack %s -o %t
+// RUN: %run %t
+
+int main(int argc, char **argv)
+{
+  int i;
+  char buffer[128];
+
+  // check that we can write to a buffer
+  for (i = 0; argv[0][i] && i < sizeof (buffer) - 1; ++i)
+    buffer[i] = argv[0][i];
+  buffer[i] = '\0';
+
+  // check that we can read from a buffer
+  for (i = 0; argv[0][i] && i < sizeof (buffer) - 1; ++i)
+    if (buffer[i] != argv[0][i])
+      return 1;
+  return 0;
+}
Index: test/safestack/check-init.c
===================================================================
--- /dev/null
+++ test/safestack/check-init.c
@@ -0,0 +1,7 @@
+// RUN: %clang_safestack %s -o %t
+// RUN: %run %t
+
+int main(int argc, char **argv)
+{
+  return 0;
+}
Index: test/safestack/check-overflow.c
===================================================================
--- /dev/null
+++ test/safestack/check-overflow.c
@@ -0,0 +1,20 @@
+// RUN: %clang_safestack %s -o %t
+// RUN: %run %t
+
+// RUN: %clang_nosafestack -fno-stack-protector %s -o %t
+// RUN: %run ! %t
+
+void fct(int *buffer)
+{
+  buffer[-1] = 36;
+  buffer[6] = 36;
+}
+
+int main(int argc, char **argv)
+{
+  int value1 = 42;
+  int buffer[5];
+  int value2 = 42;
+  fct(buffer);
+  return value1 != 42 || value2 != 42;
+}
Index: test/safestack/check-pthread-cleanup.c
===================================================================
--- /dev/null
+++ test/safestack/check-pthread-cleanup.c
@@ -0,0 +1,29 @@
+// RUN: %clang_safestack %s -pthread -o %t
+// RUN: %run ! %t
+
+#include <stdlib.h>
+#include <string.h>
+#include <pthread.h>
+
+#define BUFFER_SIZE (1 << 15)
+
+void *t1_start(void *ptr)
+{
+  char buffer[BUFFER_SIZE];
+  return buffer;
+}
+
+int main(int argc, char **argv)
+{
+  pthread_t t1;
+  char *buffer = NULL;
+
+  if (pthread_create(&t1, NULL, t1_start, NULL))
+    abort();
+  if (pthread_join(t1, &buffer))
+    abort();
+
+  // should segfault here
+  memset(buffer, 0, BUFFER_SIZE);
+  return 0;
+}
Index: test/safestack/check-pthread.c
===================================================================
--- /dev/null
+++ test/safestack/check-pthread.c
@@ -0,0 +1,36 @@
+// RUN: %clang_safestack %s -pthread -o %t
+// RUN: %run %t
+
+#include <stdlib.h>
+#include <string.h>
+#include <pthread.h>
+
+static int ptr_test = 42;
+
+void *t1_start(void *ptr)
+{
+  if (ptr != &ptr_test)
+    abort();
+
+  // safe stack
+  int val = ptr_test * 5;
+
+  // unsafe stack
+  char buffer[8096]; // two pages
+  memset(buffer, val, sizeof (buffer));
+
+  return ptr;
+}
+
+int main(int argc, char **argv)
+{
+  pthread_t t1;
+  void *ptr = NULL;
+  if (pthread_create(&t1, NULL, t1_start, &ptr_test))
+    abort();
+  if (pthread_join(t1, &ptr))
+    abort();
+  if (ptr != &ptr_test)
+    abort();
+  return 0;
+}
Index: test/safestack/lit.cfg
===================================================================
--- /dev/null
+++ test/safestack/lit.cfg
@@ -0,0 +1,20 @@
+# -*- Python -*-
+
+import os
+
+# Setup config name.
+config.name = 'SafeStack'
+
+# Setup source root.
+config.test_source_root = os.path.dirname(__file__)
+
+# Test suffixes.
+config.suffixes = ['.c', '.cc', '.cpp', '.m', '.mm', '.ll', '.test']
+
+# Add clang substitutions.
+config.substitutions.append( ("%clang_nosafestack ", config.clang + " -O0 -fno-safe-stack ") )
+config.substitutions.append( ("%clang_safestack ", config.clang + " -O0 -fsafe-stack ") )
+
+# SafeStack tests are currently supported on Linux, FreeBSD and Darwin only.
+if config.host_os not in ['Linux', 'FreeBSD', 'Darwin']:
+   config.unsupported = True
Index: test/safestack/lit.site.cfg.in
===================================================================
--- /dev/null
+++ test/safestack/lit.site.cfg.in
@@ -0,0 +1,11 @@
+## Autogenerated by LLVM/Clang configuration.
+# Do not edit!
+
+# Tool-specific config options.
+config.safestack_lit_binary_dir = "@SAFESTACK_LIT_BINARY_DIR@"
+
+# Load common config for all compiler-rt lit tests.
+lit_config.load_config(config, "@COMPILER_RT_BINARY_DIR@/test/lit.common.configured")
+
+# Load tool-specific config that would do the real work.
+lit_config.load_config(config, "@SAFESTACK_LIT_SOURCE_DIR@/lit.cfg")
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits

Reply via email to