summaryrefslogtreecommitdiffstats
path: root/lib/sanitizer_common
diff options
context:
space:
mode:
authorandrew <andrew@FreeBSD.org>2012-07-30 10:58:13 +0000
committerandrew <andrew@FreeBSD.org>2012-07-30 10:58:13 +0000
commitcfeab007a554034f0b3ab4a677cf9dd2696c12f9 (patch)
tree40cc44a3d02ed86de24f2117a55680e4f0eb01a0 /lib/sanitizer_common
parent07af089f1449ec5506ca7ede5b593e11a0f48603 (diff)
downloadFreeBSD-src-cfeab007a554034f0b3ab4a677cf9dd2696c12f9.zip
FreeBSD-src-cfeab007a554034f0b3ab4a677cf9dd2696c12f9.tar.gz
Import compiler-rt r160957.
Diffstat (limited to 'lib/sanitizer_common')
-rw-r--r--lib/sanitizer_common/CMakeLists.txt35
-rw-r--r--lib/sanitizer_common/Makefile.mk22
-rw-r--r--lib/sanitizer_common/sanitizer_allocator.cc59
-rw-r--r--lib/sanitizer_common/sanitizer_allocator64.h488
-rw-r--r--lib/sanitizer_common/sanitizer_atomic.h65
-rw-r--r--lib/sanitizer_common/sanitizer_atomic_clang.h122
-rw-r--r--lib/sanitizer_common/sanitizer_atomic_msvc.h112
-rw-r--r--lib/sanitizer_common/sanitizer_common.cc100
-rw-r--r--lib/sanitizer_common/sanitizer_common.h123
-rw-r--r--lib/sanitizer_common/sanitizer_flags.cc82
-rw-r--r--lib/sanitizer_common/sanitizer_flags.h27
-rw-r--r--lib/sanitizer_common/sanitizer_interface_defs.h56
-rw-r--r--lib/sanitizer_common/sanitizer_internal_defs.h163
-rw-r--r--lib/sanitizer_common/sanitizer_libc.cc182
-rw-r--r--lib/sanitizer_common/sanitizer_libc.h69
-rw-r--r--lib/sanitizer_common/sanitizer_linux.cc348
-rw-r--r--lib/sanitizer_common/sanitizer_list.h120
-rw-r--r--lib/sanitizer_common/sanitizer_mac.cc243
-rw-r--r--lib/sanitizer_common/sanitizer_mutex.h100
-rw-r--r--lib/sanitizer_common/sanitizer_placement_new.h33
-rw-r--r--lib/sanitizer_common/sanitizer_posix.cc164
-rw-r--r--lib/sanitizer_common/sanitizer_printf.cc185
-rw-r--r--lib/sanitizer_common/sanitizer_procmaps.h82
-rw-r--r--lib/sanitizer_common/sanitizer_symbolizer.cc144
-rw-r--r--lib/sanitizer_common/sanitizer_symbolizer.h100
-rw-r--r--lib/sanitizer_common/sanitizer_win.cc200
-rw-r--r--lib/sanitizer_common/tests/sanitizer_allocator64_test.cc257
-rw-r--r--lib/sanitizer_common/tests/sanitizer_allocator64_testlib.cc99
-rw-r--r--lib/sanitizer_common/tests/sanitizer_allocator_test.cc56
-rw-r--r--lib/sanitizer_common/tests/sanitizer_common_test.cc66
-rw-r--r--lib/sanitizer_common/tests/sanitizer_flags_test.cc72
-rw-r--r--lib/sanitizer_common/tests/sanitizer_list_test.cc157
32 files changed, 4131 insertions, 0 deletions
diff --git a/lib/sanitizer_common/CMakeLists.txt b/lib/sanitizer_common/CMakeLists.txt
new file mode 100644
index 0000000..d797a56
--- /dev/null
+++ b/lib/sanitizer_common/CMakeLists.txt
@@ -0,0 +1,35 @@
+# Build system for the common Sanitizer runtime support library components.
+# These components are shared between AddressSanitizer and ThreadSanitizer.
+
+set(SANITIZER_SOURCES
+ sanitizer_allocator.cc
+ sanitizer_common.cc
+ sanitizer_flags.cc
+ sanitizer_libc.cc
+ sanitizer_linux.cc
+ sanitizer_mac.cc
+ sanitizer_posix.cc
+ sanitizer_printf.cc
+ sanitizer_symbolizer.cc
+ sanitizer_win.cc
+ )
+
+set(SANITIZER_CFLAGS "-fPIC -fno-exceptions -funwind-tables -fvisibility=hidden")
+
+set(SANITIZER_COMMON_DEFINITIONS
+ SANITIZER_HAS_EXCEPTIONS=1)
+
+if(CAN_TARGET_X86_64)
+ add_library(RTSanitizerCommon.x86_64 OBJECT ${SANITIZER_SOURCES})
+ set_property(TARGET RTSanitizerCommon.x86_64 PROPERTY COMPILE_FLAGS
+ "${SANITIZER_CFLAGS} ${TARGET_X86_64_CFLAGS}")
+ set_property(TARGET RTSanitizerCommon.x86_64 APPEND PROPERTY COMPILE_DEFINITIONS
+ ${SANITIZER_COMMON_DEFINITIONS})
+endif()
+if(CAN_TARGET_I386)
+ add_library(RTSanitizerCommon.i386 OBJECT ${SANITIZER_SOURCES})
+ set_property(TARGET RTSanitizerCommon.i386 PROPERTY COMPILE_FLAGS
+ "${SANITIZER_CFLAGS} ${TARGET_I386_CFLAGS}")
+ set_property(TARGET RTSanitizerCommon.i386 APPEND PROPERTY COMPILE_DEFINITIONS
+ ${SANITIZER_COMMON_DEFINITIONS})
+endif()
diff --git a/lib/sanitizer_common/Makefile.mk b/lib/sanitizer_common/Makefile.mk
new file mode 100644
index 0000000..da83c2d
--- /dev/null
+++ b/lib/sanitizer_common/Makefile.mk
@@ -0,0 +1,22 @@
+#===- lib/sanitizer_common/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 := sanitizer_common
+SubDirs :=
+
+Sources := $(foreach file,$(wildcard $(Dir)/*.cc),$(notdir $(file)))
+ObjNames := $(Sources:%.cc=%.o)
+
+Implementation := Generic
+
+# FIXME: use automatic dependencies?
+Dependencies := $(wildcard $(Dir)/*.h)
+
+# Define a convenience variable for all the sanitizer_common functions.
+SanitizerCommonFunctions := $(Sources:%.cc=%)
diff --git a/lib/sanitizer_common/sanitizer_allocator.cc b/lib/sanitizer_common/sanitizer_allocator.cc
new file mode 100644
index 0000000..816fddf
--- /dev/null
+++ b/lib/sanitizer_common/sanitizer_allocator.cc
@@ -0,0 +1,59 @@
+//===-- sanitizer_allocator.cc --------------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is shared between AddressSanitizer and ThreadSanitizer
+// run-time libraries.
+// This allocator that is used inside run-times.
+//===----------------------------------------------------------------------===//
+#include "sanitizer_common.h"
+
+// FIXME: We should probably use more low-level allocator that would
+// mmap some pages and split them into chunks to fulfill requests.
+#ifdef __linux__
+extern "C" void *__libc_malloc(__sanitizer::uptr size);
+extern "C" void __libc_free(void *ptr);
+# define LIBC_MALLOC __libc_malloc
+# define LIBC_FREE __libc_free
+#else // __linux__
+# include <stdlib.h>
+# define LIBC_MALLOC malloc
+# define LIBC_FREE free
+#endif // __linux__
+
+namespace __sanitizer {
+
+const u64 kBlockMagic = 0x6A6CB03ABCEBC041ull;
+
+void *InternalAlloc(uptr size) {
+ if (size + sizeof(u64) < size)
+ return 0;
+ void *p = LIBC_MALLOC(size + sizeof(u64));
+ if (p == 0)
+ return 0;
+ ((u64*)p)[0] = kBlockMagic;
+ return (char*)p + sizeof(u64);
+}
+
+void InternalFree(void *addr) {
+ if (addr == 0)
+ return;
+ addr = (char*)addr - sizeof(u64);
+ CHECK_EQ(((u64*)addr)[0], kBlockMagic);
+ ((u64*)addr)[0] = 0;
+ LIBC_FREE(addr);
+}
+
+void *InternalAllocBlock(void *p) {
+ CHECK_NE(p, (void*)0);
+ u64 *pp = (u64*)((uptr)p & ~0x7);
+ for (; pp[0] != kBlockMagic; pp--) {}
+ return pp + 1;
+}
+
+} // namespace __sanitizer
diff --git a/lib/sanitizer_common/sanitizer_allocator64.h b/lib/sanitizer_common/sanitizer_allocator64.h
new file mode 100644
index 0000000..eb79a12
--- /dev/null
+++ b/lib/sanitizer_common/sanitizer_allocator64.h
@@ -0,0 +1,488 @@
+//===-- sanitizer_allocator64.h ---------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+// Specialized allocator which works only in 64-bit address space.
+// To be used by ThreadSanitizer, MemorySanitizer and possibly other tools.
+// The main feature of this allocator is that the header is located far away
+// from the user memory region, so that the tool does not use extra shadow
+// for the header.
+//
+// Status: not yet ready.
+//===----------------------------------------------------------------------===//
+#ifndef SANITIZER_ALLOCATOR_H
+#define SANITIZER_ALLOCATOR_H
+
+#include "sanitizer_common.h"
+#include "sanitizer_internal_defs.h"
+#include "sanitizer_libc.h"
+#include "sanitizer_list.h"
+#include "sanitizer_mutex.h"
+
+namespace __sanitizer {
+
+// Maps size class id to size and back.
+class DefaultSizeClassMap {
+ private:
+ // Here we use a spline composed of 5 polynomials of oder 1.
+ // The first size class is l0, then the classes go with step s0
+ // untill they reach l1, after which they go with step s1 and so on.
+ // Steps should be powers of two for cheap division.
+ // The size of the last size class should be a power of two.
+ // There should be at most 256 size classes.
+ static const uptr l0 = 1 << 4;
+ static const uptr l1 = 1 << 9;
+ static const uptr l2 = 1 << 12;
+ static const uptr l3 = 1 << 15;
+ static const uptr l4 = 1 << 18;
+ static const uptr l5 = 1 << 21;
+
+ static const uptr s0 = 1 << 4;
+ static const uptr s1 = 1 << 6;
+ static const uptr s2 = 1 << 9;
+ static const uptr s3 = 1 << 12;
+ static const uptr s4 = 1 << 15;
+
+ static const uptr u0 = 0 + (l1 - l0) / s0;
+ static const uptr u1 = u0 + (l2 - l1) / s1;
+ static const uptr u2 = u1 + (l3 - l2) / s2;
+ static const uptr u3 = u2 + (l4 - l3) / s3;
+ static const uptr u4 = u3 + (l5 - l4) / s4;
+
+ public:
+ static const uptr kNumClasses = u4 + 1;
+ static const uptr kMaxSize = l5;
+ static const uptr kMinSize = l0;
+
+ COMPILER_CHECK(kNumClasses <= 256);
+ COMPILER_CHECK((kMaxSize & (kMaxSize - 1)) == 0);
+
+ static uptr Size(uptr class_id) {
+ if (class_id <= u0) return l0 + s0 * (class_id - 0);
+ if (class_id <= u1) return l1 + s1 * (class_id - u0);
+ if (class_id <= u2) return l2 + s2 * (class_id - u1);
+ if (class_id <= u3) return l3 + s3 * (class_id - u2);
+ if (class_id <= u4) return l4 + s4 * (class_id - u3);
+ return 0;
+ }
+ static uptr ClassID(uptr size) {
+ if (size <= l1) return 0 + (size - l0 + s0 - 1) / s0;
+ if (size <= l2) return u0 + (size - l1 + s1 - 1) / s1;
+ if (size <= l3) return u1 + (size - l2 + s2 - 1) / s2;
+ if (size <= l4) return u2 + (size - l3 + s3 - 1) / s3;
+ if (size <= l5) return u3 + (size - l4 + s4 - 1) / s4;
+ return 0;
+ }
+};
+
+struct AllocatorListNode {
+ AllocatorListNode *next;
+};
+
+typedef IntrusiveList<AllocatorListNode> AllocatorFreeList;
+
+
+// Space: a portion of address space of kSpaceSize bytes starting at
+// a fixed address (kSpaceBeg). Both constants are powers of two and
+// kSpaceBeg is kSpaceSize-aligned.
+//
+// Region: a part of Space dedicated to a single size class.
+// There are kNumClasses Regions of equal size.
+//
+// UserChunk: a piece of memory returned to user.
+// MetaChunk: kMetadataSize bytes of metadata associated with a UserChunk.
+//
+// A Region looks like this:
+// UserChunk1 ... UserChunkN <gap> MetaChunkN ... MetaChunk1
+template <const uptr kSpaceBeg, const uptr kSpaceSize,
+ const uptr kMetadataSize, class SizeClassMap>
+class SizeClassAllocator64 {
+ public:
+ void Init() {
+ CHECK_EQ(AllocBeg(), reinterpret_cast<uptr>(MmapFixedNoReserve(
+ AllocBeg(), AllocSize())));
+ }
+
+ bool CanAllocate(uptr size, uptr alignment) {
+ return size <= SizeClassMap::kMaxSize &&
+ alignment <= SizeClassMap::kMaxSize;
+ }
+
+ void *Allocate(uptr size, uptr alignment) {
+ CHECK(CanAllocate(size, alignment));
+ return AllocateBySizeClass(SizeClassMap::ClassID(size));
+ }
+
+ void Deallocate(void *p) {
+ CHECK(PointerIsMine(p));
+ DeallocateBySizeClass(p, GetSizeClass(p));
+ }
+
+ // Allocate several chunks of the given class_id.
+ void BulkAllocate(uptr class_id, AllocatorFreeList *free_list) {
+ CHECK_LT(class_id, kNumClasses);
+ RegionInfo *region = GetRegionInfo(class_id);
+ SpinMutexLock l(&region->mutex);
+ if (region->free_list.empty()) {
+ PopulateFreeList(class_id, region);
+ }
+ CHECK(!region->free_list.empty());
+ // Just take as many chunks as we have in the free list now.
+ // FIXME: this might be too much.
+ free_list->append_front(&region->free_list);
+ CHECK(region->free_list.empty());
+ }
+
+ // Swallow the entire free_list for the given class_id.
+ void BulkDeallocate(uptr class_id, AllocatorFreeList *free_list) {
+ CHECK_LT(class_id, kNumClasses);
+ RegionInfo *region = GetRegionInfo(class_id);
+ SpinMutexLock l(&region->mutex);
+ region->free_list.append_front(free_list);
+ }
+
+ bool PointerIsMine(void *p) {
+ return reinterpret_cast<uptr>(p) / kSpaceSize == kSpaceBeg / kSpaceSize;
+ }
+ uptr GetSizeClass(void *p) {
+ return (reinterpret_cast<uptr>(p) / kRegionSize) % kNumClasses;
+ }
+
+ uptr GetActuallyAllocatedSize(void *p) {
+ CHECK(PointerIsMine(p));
+ return SizeClassMap::Size(GetSizeClass(p));
+ }
+
+ uptr ClassID(uptr size) { return SizeClassMap::ClassID(size); }
+
+ void *GetMetaData(void *p) {
+ uptr class_id = GetSizeClass(p);
+ uptr chunk_idx = GetChunkIdx(reinterpret_cast<uptr>(p), class_id);
+ return reinterpret_cast<void*>(kSpaceBeg + (kRegionSize * (class_id + 1)) -
+ (1 + chunk_idx) * kMetadataSize);
+ }
+
+ uptr TotalMemoryUsed() {
+ uptr res = 0;
+ for (uptr i = 0; i < kNumClasses; i++)
+ res += GetRegionInfo(i)->allocated_user;
+ return res;
+ }
+
+ // Test-only.
+ void TestOnlyUnmap() {
+ UnmapOrDie(reinterpret_cast<void*>(AllocBeg()), AllocSize());
+ }
+
+ static const uptr kNumClasses = 256; // Power of two <= 256
+
+ private:
+ COMPILER_CHECK(kNumClasses <= SizeClassMap::kNumClasses);
+ static const uptr kRegionSize = kSpaceSize / kNumClasses;
+ COMPILER_CHECK((kRegionSize >> 32) > 0); // kRegionSize must be >= 2^32.
+ // Populate the free list with at most this number of bytes at once
+ // or with one element if its size is greater.
+ static const uptr kPopulateSize = 1 << 18;
+
+ struct RegionInfo {
+ SpinMutex mutex;
+ AllocatorFreeList free_list;
+ uptr allocated_user; // Bytes allocated for user memory.
+ uptr allocated_meta; // Bytes allocated for metadata.
+ char padding[kCacheLineSize - 3 * sizeof(uptr) - sizeof(AllocatorFreeList)];
+ };
+ COMPILER_CHECK(sizeof(RegionInfo) == kCacheLineSize);
+
+ uptr AdditionalSize() {
+ uptr res = sizeof(RegionInfo) * kNumClasses;
+ CHECK_EQ(res % kPageSize, 0);
+ return res;
+ }
+ uptr AllocBeg() { return kSpaceBeg - AdditionalSize(); }
+ uptr AllocSize() { return kSpaceSize + AdditionalSize(); }
+
+ RegionInfo *GetRegionInfo(uptr class_id) {
+ CHECK_LT(class_id, kNumClasses);
+ RegionInfo *regions = reinterpret_cast<RegionInfo*>(kSpaceBeg);
+ return &regions[-1 - class_id];
+ }
+
+ uptr GetChunkIdx(uptr chunk, uptr class_id) {
+ u32 offset = chunk % kRegionSize;
+ // Here we divide by a non-constant. This is costly.
+ // We require that kRegionSize is at least 2^32 so that offset is 32-bit.
+ // We save 2x by using 32-bit div, but may need to use a 256-way switch.
+ return offset / (u32)SizeClassMap::Size(class_id);
+ }
+
+ void PopulateFreeList(uptr class_id, RegionInfo *region) {
+ uptr size = SizeClassMap::Size(class_id);
+ uptr beg_idx = region->allocated_user;
+ uptr end_idx = beg_idx + kPopulateSize;
+ region->free_list.clear();
+ uptr region_beg = kSpaceBeg + kRegionSize * class_id;
+ uptr idx = beg_idx;
+ uptr i = 0;
+ do { // do-while loop because we need to put at least one item.
+ uptr p = region_beg + idx;
+ region->free_list.push_front(reinterpret_cast<AllocatorListNode*>(p));
+ idx += size;
+ i++;
+ } while (idx < end_idx);
+ region->allocated_user += idx - beg_idx;
+ region->allocated_meta += i * kMetadataSize;
+ CHECK_LT(region->allocated_user + region->allocated_meta, kRegionSize);
+ }
+
+ void *AllocateBySizeClass(uptr class_id) {
+ CHECK_LT(class_id, kNumClasses);
+ RegionInfo *region = GetRegionInfo(class_id);
+ SpinMutexLock l(&region->mutex);
+ if (region->free_list.empty()) {
+ PopulateFreeList(class_id, region);
+ }
+ CHECK(!region->free_list.empty());
+ AllocatorListNode *node = region->free_list.front();
+ region->free_list.pop_front();
+ return reinterpret_cast<void*>(node);
+ }
+
+ void DeallocateBySizeClass(void *p, uptr class_id) {
+ RegionInfo *region = GetRegionInfo(class_id);
+ SpinMutexLock l(&region->mutex);
+ region->free_list.push_front(reinterpret_cast<AllocatorListNode*>(p));
+ }
+};
+
+// Objects of this type should be used as local caches for SizeClassAllocator64.
+// Since the typical use of this class is to have one object per thread in TLS,
+// is has to be POD.
+template<const uptr kNumClasses, class SizeClassAllocator>
+struct SizeClassAllocatorLocalCache {
+ // Don't need to call Init if the object is a global (i.e. zero-initialized).
+ void Init() {
+ internal_memset(this, 0, sizeof(*this));
+ }
+
+ void *Allocate(SizeClassAllocator *allocator, uptr class_id) {
+ CHECK_LT(class_id, kNumClasses);
+ AllocatorFreeList *free_list = &free_lists_[class_id];
+ if (free_list->empty())
+ allocator->BulkAllocate(class_id, free_list);
+ CHECK(!free_list->empty());
+ void *res = free_list->front();
+ free_list->pop_front();
+ return res;
+ }
+
+ void Deallocate(SizeClassAllocator *allocator, uptr class_id, void *p) {
+ CHECK_LT(class_id, kNumClasses);
+ free_lists_[class_id].push_front(reinterpret_cast<AllocatorListNode*>(p));
+ }
+
+ void Drain(SizeClassAllocator *allocator) {
+ for (uptr i = 0; i < kNumClasses; i++) {
+ allocator->BulkDeallocate(i, &free_lists_[i]);
+ CHECK(free_lists_[i].empty());
+ }
+ }
+
+ // private:
+ AllocatorFreeList free_lists_[kNumClasses];
+};
+
+// This class can (de)allocate only large chunks of memory using mmap/unmap.
+// The main purpose of this allocator is to cover large and rare allocation
+// sizes not covered by more efficient allocators (e.g. SizeClassAllocator64).
+// The result is always page-aligned.
+class LargeMmapAllocator {
+ public:
+ void Init() {
+ internal_memset(this, 0, sizeof(*this));
+ }
+ void *Allocate(uptr size, uptr alignment) {
+ CHECK_LE(alignment, kPageSize); // Not implemented. Do we need it?
+ uptr map_size = RoundUpMapSize(size);
+ void *map = MmapOrDie(map_size, "LargeMmapAllocator");
+ void *res = reinterpret_cast<void*>(reinterpret_cast<uptr>(map)
+ + kPageSize);
+ Header *h = GetHeader(res);
+ h->size = size;
+ {
+ SpinMutexLock l(&mutex_);
+ h->next = list_;
+ h->prev = 0;
+ if (list_)
+ list_->prev = h;
+ list_ = h;
+ }
+ return res;
+ }
+
+ void Deallocate(void *p) {
+ Header *h = GetHeader(p);
+ uptr map_size = RoundUpMapSize(h->size);
+ {
+ SpinMutexLock l(&mutex_);
+ Header *prev = h->prev;
+ Header *next = h->next;
+ if (prev)
+ prev->next = next;
+ if (next)
+ next->prev = prev;
+ if (h == list_)
+ list_ = next;
+ }
+ UnmapOrDie(h, map_size);
+ }
+
+ uptr TotalMemoryUsed() {
+ SpinMutexLock l(&mutex_);
+ uptr res = 0;
+ for (Header *l = list_; l; l = l->next) {
+ res += RoundUpMapSize(l->size);
+ }
+ return res;
+ }
+
+ bool PointerIsMine(void *p) {
+ // Fast check.
+ if ((reinterpret_cast<uptr>(p) % kPageSize) != 0) return false;
+ SpinMutexLock l(&mutex_);
+ for (Header *l = list_; l; l = l->next) {
+ if (GetUser(l) == p) return true;
+ }
+ return false;
+ }
+
+ uptr GetActuallyAllocatedSize(void *p) {
+ return RoundUpMapSize(GetHeader(p)->size) - kPageSize;
+ }
+
+ // At least kPageSize/2 metadata bytes is available.
+ void *GetMetaData(void *p) {
+ return GetHeader(p) + 1;
+ }
+
+ private:
+ struct Header {
+ uptr size;
+ Header *next;
+ Header *prev;
+ };
+
+ Header *GetHeader(void *p) {
+ return reinterpret_cast<Header*>(reinterpret_cast<uptr>(p) - kPageSize);
+ }
+
+ void *GetUser(Header *h) {
+ return reinterpret_cast<void*>(reinterpret_cast<uptr>(h) + kPageSize);
+ }
+
+ uptr RoundUpMapSize(uptr size) {
+ return RoundUpTo(size, kPageSize) + kPageSize;
+ }
+
+ Header *list_;
+ SpinMutex mutex_;
+};
+
+// This class implements a complete memory allocator by using two
+// internal allocators:
+// PrimaryAllocator is efficient, but may not allocate some sizes (alignments).
+// When allocating 2^x bytes it should return 2^x aligned chunk.
+// PrimaryAllocator is used via a local AllocatorCache.
+// SecondaryAllocator can allocate anything, but is not efficient.
+template <class PrimaryAllocator, class AllocatorCache,
+ class SecondaryAllocator> // NOLINT
+class CombinedAllocator {
+ public:
+ void Init() {
+ primary_.Init();
+ secondary_.Init();
+ }
+
+ void *Allocate(AllocatorCache *cache, uptr size, uptr alignment,
+ bool cleared = false) {
+ // Returning 0 on malloc(0) may break a lot of code.
+ if (size == 0) size = 1;
+ if (alignment > 8)
+ size = RoundUpTo(size, alignment);
+ void *res;
+ if (primary_.CanAllocate(size, alignment))
+ res = cache->Allocate(&primary_, primary_.ClassID(size));
+ else
+ res = secondary_.Allocate(size, alignment);
+ if (alignment > 8)
+ CHECK_EQ(reinterpret_cast<uptr>(res) & (alignment - 1), 0);
+ if (cleared)
+ internal_memset(res, 0, size);
+ return res;
+ }
+
+ void Deallocate(AllocatorCache *cache, void *p) {
+ if (!p) return;
+ if (primary_.PointerIsMine(p))
+ cache->Deallocate(&primary_, primary_.GetSizeClass(p), p);
+ else
+ secondary_.Deallocate(p);
+ }
+
+ void *Reallocate(AllocatorCache *cache, void *p, uptr new_size,
+ uptr alignment) {
+ if (!p)
+ return Allocate(cache, new_size, alignment);
+ if (!new_size) {
+ Deallocate(cache, p);
+ return 0;
+ }
+ CHECK(PointerIsMine(p));
+ uptr old_size = GetActuallyAllocatedSize(p);
+ uptr memcpy_size = Min(new_size, old_size);
+ void *new_p = Allocate(cache, new_size, alignment);
+ if (new_p)
+ internal_memcpy(new_p, p, memcpy_size);
+ Deallocate(cache, p);
+ return new_p;
+ }
+
+ bool PointerIsMine(void *p) {
+ if (primary_.PointerIsMine(p))
+ return true;
+ return secondary_.PointerIsMine(p);
+ }
+
+ void *GetMetaData(void *p) {
+ if (primary_.PointerIsMine(p))
+ return primary_.GetMetaData(p);
+ return secondary_.GetMetaData(p);
+ }
+
+ uptr GetActuallyAllocatedSize(void *p) {
+ if (primary_.PointerIsMine(p))
+ return primary_.GetActuallyAllocatedSize(p);
+ return secondary_.GetActuallyAllocatedSize(p);
+ }
+
+ uptr TotalMemoryUsed() {
+ return primary_.TotalMemoryUsed() + secondary_.TotalMemoryUsed();
+ }
+
+ void TestOnlyUnmap() { primary_.TestOnlyUnmap(); }
+
+ void SwallowCache(AllocatorCache *cache) {
+ cache->Drain(&primary_);
+ }
+
+ private:
+ PrimaryAllocator primary_;
+ SecondaryAllocator secondary_;
+};
+
+} // namespace __sanitizer
+
+#endif // SANITIZER_ALLOCATOR_H
diff --git a/lib/sanitizer_common/sanitizer_atomic.h b/lib/sanitizer_common/sanitizer_atomic.h
new file mode 100644
index 0000000..61e6dfd
--- /dev/null
+++ b/lib/sanitizer_common/sanitizer_atomic.h
@@ -0,0 +1,65 @@
+//===-- sanitizer_atomic.h --------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of ThreadSanitizer/AddressSanitizer runtime.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef SANITIZER_ATOMIC_H
+#define SANITIZER_ATOMIC_H
+
+#include "sanitizer_internal_defs.h"
+
+namespace __sanitizer {
+
+enum memory_order {
+ memory_order_relaxed = 1 << 0,
+ memory_order_consume = 1 << 1,
+ memory_order_acquire = 1 << 2,
+ memory_order_release = 1 << 3,
+ memory_order_acq_rel = 1 << 4,
+ memory_order_seq_cst = 1 << 5
+};
+
+struct atomic_uint8_t {
+ typedef u8 Type;
+ volatile Type val_dont_use;
+};
+
+struct atomic_uint16_t {
+ typedef u16 Type;
+ volatile Type val_dont_use;
+};
+
+struct atomic_uint32_t {
+ typedef u32 Type;
+ volatile Type val_dont_use;
+};
+
+struct atomic_uint64_t {
+ typedef u64 Type;
+ volatile Type val_dont_use;
+};
+
+struct atomic_uintptr_t {
+ typedef uptr Type;
+ volatile Type val_dont_use;
+};
+
+} // namespace __sanitizer
+
+#if defined(__GNUC__)
+# include "sanitizer_atomic_clang.h"
+#elif defined(_MSC_VER)
+# include "sanitizer_atomic_msvc.h"
+#else
+# error "Unsupported compiler"
+#endif
+
+#endif // SANITIZER_ATOMIC_H
diff --git a/lib/sanitizer_common/sanitizer_atomic_clang.h b/lib/sanitizer_common/sanitizer_atomic_clang.h
new file mode 100644
index 0000000..af70441
--- /dev/null
+++ b/lib/sanitizer_common/sanitizer_atomic_clang.h
@@ -0,0 +1,122 @@
+//===-- sanitizer_atomic_clang.h --------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of ThreadSanitizer/AddressSanitizer runtime.
+// Not intended for direct inclusion. Include sanitizer_atomic.h.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef SANITIZER_ATOMIC_CLANG_H
+#define SANITIZER_ATOMIC_CLANG_H
+
+namespace __sanitizer {
+
+INLINE void atomic_signal_fence(memory_order) {
+ __asm__ __volatile__("" ::: "memory");
+}
+
+INLINE void atomic_thread_fence(memory_order) {
+ __sync_synchronize();
+}
+
+INLINE void proc_yield(int cnt) {
+ __asm__ __volatile__("" ::: "memory");
+#if defined(__i386__) || defined(__x86_64__)
+ for (int i = 0; i < cnt; i++)
+ __asm__ __volatile__("pause");
+#endif
+ __asm__ __volatile__("" ::: "memory");
+}
+
+template<typename T>
+INLINE typename T::Type atomic_load(
+ const volatile T *a, memory_order mo) {
+ DCHECK(mo & (memory_order_relaxed | memory_order_consume
+ | memory_order_acquire | memory_order_seq_cst));
+ DCHECK(!((uptr)a % sizeof(*a)));
+ typename T::Type v;
+ if (mo == memory_order_relaxed) {
+ v = a->val_dont_use;
+ } else {
+ atomic_signal_fence(memory_order_seq_cst);
+ v = a->val_dont_use;
+ atomic_signal_fence(memory_order_seq_cst);
+ }
+ return v;
+}
+
+template<typename T>
+INLINE void atomic_store(volatile T *a, typename T::Type v, memory_order mo) {
+ DCHECK(mo & (memory_order_relaxed | memory_order_release
+ | memory_order_seq_cst));
+ DCHECK(!((uptr)a % sizeof(*a)));
+ if (mo == memory_order_relaxed) {
+ a->val_dont_use = v;
+ } else {
+ atomic_signal_fence(memory_order_seq_cst);
+ a->val_dont_use = v;
+ atomic_signal_fence(memory_order_seq_cst);
+ }
+ if (mo == memory_order_seq_cst)
+ atomic_thread_fence(memory_order_seq_cst);
+}
+
+template<typename T>
+INLINE typename T::Type atomic_fetch_add(volatile T *a,
+ typename T::Type v, memory_order mo) {
+ (void)mo;
+ DCHECK(!((uptr)a % sizeof(*a)));
+ return __sync_fetch_and_add(&a->val_dont_use, v);
+}
+
+template<typename T>
+INLINE typename T::Type atomic_fetch_sub(volatile T *a,
+ typename T::Type v, memory_order mo) {
+ (void)mo;
+ DCHECK(!((uptr)a % sizeof(*a)));
+ return __sync_fetch_and_add(&a->val_dont_use, -v);
+}
+
+template<typename T>
+INLINE typename T::Type atomic_exchange(volatile T *a,
+ typename T::Type v, memory_order mo) {
+ DCHECK(!((uptr)a % sizeof(*a)));
+ if (mo & (memory_order_release | memory_order_acq_rel | memory_order_seq_cst))
+ __sync_synchronize();
+ v = __sync_lock_test_and_set(&a->val_dont_use, v);
+ if (mo == memory_order_seq_cst)
+ __sync_synchronize();
+ return v;
+}
+
+template<typename T>
+INLINE bool atomic_compare_exchange_strong(volatile T *a,
+ typename T::Type *cmp,
+ typename T::Type xchg,
+ memory_order mo) {
+ typedef typename T::Type Type;
+ Type cmpv = *cmp;
+ Type prev = __sync_val_compare_and_swap(&a->val_dont_use, cmpv, xchg);
+ if (prev == cmpv)
+ return true;
+ *cmp = prev;
+ return false;
+}
+
+template<typename T>
+INLINE bool atomic_compare_exchange_weak(volatile T *a,
+ typename T::Type *cmp,
+ typename T::Type xchg,
+ memory_order mo) {
+ return atomic_compare_exchange_strong(a, cmp, xchg, mo);
+}
+
+} // namespace __sanitizer
+
+#endif // SANITIZER_ATOMIC_CLANG_H
diff --git a/lib/sanitizer_common/sanitizer_atomic_msvc.h b/lib/sanitizer_common/sanitizer_atomic_msvc.h
new file mode 100644
index 0000000..2a15b59
--- /dev/null
+++ b/lib/sanitizer_common/sanitizer_atomic_msvc.h
@@ -0,0 +1,112 @@
+//===-- sanitizer_atomic_msvc.h ---------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of ThreadSanitizer/AddressSanitizer runtime.
+// Not intended for direct inclusion. Include sanitizer_atomic.h.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef SANITIZER_ATOMIC_MSVC_H
+#define SANITIZER_ATOMIC_MSVC_H
+
+extern "C" void _ReadWriteBarrier();
+#pragma intrinsic(_ReadWriteBarrier)
+extern "C" void _mm_mfence();
+#pragma intrinsic(_mm_mfence)
+extern "C" void _mm_pause();
+#pragma intrinsic(_mm_pause)
+extern "C" long _InterlockedExchangeAdd( // NOLINT
+ long volatile * Addend, long Value); // NOLINT
+#pragma intrinsic(_InterlockedExchangeAdd)
+
+namespace __sanitizer {
+
+INLINE void atomic_signal_fence(memory_order) {
+ _ReadWriteBarrier();
+}
+
+INLINE void atomic_thread_fence(memory_order) {
+ _mm_mfence();
+}
+
+INLINE void proc_yield(int cnt) {
+ for (int i = 0; i < cnt; i++)
+ _mm_pause();
+}
+
+template<typename T>
+INLINE typename T::Type atomic_load(
+ const volatile T *a, memory_order mo) {
+ DCHECK(mo & (memory_order_relaxed | memory_order_consume
+ | memory_order_acquire | memory_order_seq_cst));
+ DCHECK(!((uptr)a % sizeof(*a)));
+ typename T::Type v;
+ if (mo == memory_order_relaxed) {
+ v = a->val_dont_use;
+ } else {
+ atomic_signal_fence(memory_order_seq_cst);
+ v = a->val_dont_use;
+ atomic_signal_fence(memory_order_seq_cst);
+ }
+ return v;
+}
+
+template<typename T>
+INLINE void atomic_store(volatile T *a, typename T::Type v, memory_order mo) {
+ DCHECK(mo & (memory_order_relaxed | memory_order_release
+ | memory_order_seq_cst));
+ DCHECK(!((uptr)a % sizeof(*a)));
+ if (mo == memory_order_relaxed) {
+ a->val_dont_use = v;
+ } else {
+ atomic_signal_fence(memory_order_seq_cst);
+ a->val_dont_use = v;
+ atomic_signal_fence(memory_order_seq_cst);
+ }
+ if (mo == memory_order_seq_cst)
+ atomic_thread_fence(memory_order_seq_cst);
+}
+
+INLINE u32 atomic_fetch_add(volatile atomic_uint32_t *a,
+ u32 v, memory_order mo) {
+ (void)mo;
+ DCHECK(!((uptr)a % sizeof(*a)));
+ return (u32)_InterlockedExchangeAdd(
+ (volatile long*)&a->val_dont_use, (long)v); // NOLINT
+}
+
+INLINE u8 atomic_exchange(volatile atomic_uint8_t *a,
+ u8 v, memory_order mo) {
+ (void)mo;
+ DCHECK(!((uptr)a % sizeof(*a)));
+ __asm {
+ mov eax, a
+ mov cl, v
+ xchg [eax], cl // NOLINT
+ mov v, cl
+ }
+ return v;
+}
+
+INLINE u16 atomic_exchange(volatile atomic_uint16_t *a,
+ u16 v, memory_order mo) {
+ (void)mo;
+ DCHECK(!((uptr)a % sizeof(*a)));
+ __asm {
+ mov eax, a
+ mov cx, v
+ xchg [eax], cx // NOLINT
+ mov v, cx
+ }
+ return v;
+}
+
+} // namespace __sanitizer
+
+#endif // SANITIZER_ATOMIC_CLANG_H
diff --git a/lib/sanitizer_common/sanitizer_common.cc b/lib/sanitizer_common/sanitizer_common.cc
new file mode 100644
index 0000000..6dd1ff9
--- /dev/null
+++ b/lib/sanitizer_common/sanitizer_common.cc
@@ -0,0 +1,100 @@
+//===-- sanitizer_common.cc -----------------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is shared between AddressSanitizer and ThreadSanitizer
+// run-time libraries.
+//===----------------------------------------------------------------------===//
+
+#include "sanitizer_common.h"
+#include "sanitizer_libc.h"
+
+namespace __sanitizer {
+
+void RawWrite(const char *buffer) {
+ static const char *kRawWriteError = "RawWrite can't output requested buffer!";
+ uptr length = (uptr)internal_strlen(buffer);
+ if (length != internal_write(2, buffer, length)) {
+ internal_write(2, kRawWriteError, internal_strlen(kRawWriteError));
+ Die();
+ }
+}
+
+uptr ReadFileToBuffer(const char *file_name, char **buff,
+ uptr *buff_size, uptr max_len) {
+ const uptr kMinFileLen = kPageSize;
+ uptr read_len = 0;
+ *buff = 0;
+ *buff_size = 0;
+ // The files we usually open are not seekable, so try different buffer sizes.
+ for (uptr size = kMinFileLen; size <= max_len; size *= 2) {
+ fd_t fd = internal_open(file_name, /*write*/ false);
+ if (fd == kInvalidFd) return 0;
+ UnmapOrDie(*buff, *buff_size);
+ *buff = (char*)MmapOrDie(size, __FUNCTION__);
+ *buff_size = size;
+ // Read up to one page at a time.
+ read_len = 0;
+ bool reached_eof = false;
+ while (read_len + kPageSize <= size) {
+ uptr just_read = internal_read(fd, *buff + read_len, kPageSize);
+ if (just_read == 0) {
+ reached_eof = true;
+ break;
+ }
+ read_len += just_read;
+ }
+ internal_close(fd);
+ if (reached_eof) // We've read the whole file.
+ break;
+ }
+ return read_len;
+}
+
+// We don't want to use std::sort to avoid including <algorithm>, as
+// we may end up with two implementation of std::sort - one in instrumented
+// code, and the other in runtime.
+// qsort() from stdlib won't work as it calls malloc(), which results
+// in deadlock in ASan allocator.
+// We re-implement in-place sorting w/o recursion as straightforward heapsort.
+void SortArray(uptr *array, uptr size) {
+ if (size < 2)
+ return;
+ // Stage 1: insert elements to the heap.
+ for (uptr i = 1; i < size; i++) {
+ uptr j, p;
+ for (j = i; j > 0; j = p) {
+ p = (j - 1) / 2;
+ if (array[j] > array[p])
+ Swap(array[j], array[p]);
+ else
+ break;
+ }
+ }
+ // Stage 2: swap largest element with the last one,
+ // and sink the new top.
+ for (uptr i = size - 1; i > 0; i--) {
+ Swap(array[0], array[i]);
+ uptr j, max_ind;
+ for (j = 0; j < i; j = max_ind) {
+ uptr left = 2 * j + 1;
+ uptr right = 2 * j + 2;
+ max_ind = j;
+ if (left < i && array[left] > array[max_ind])
+ max_ind = left;
+ if (right < i && array[right] > array[max_ind])
+ max_ind = right;
+ if (max_ind != j)
+ Swap(array[j], array[max_ind]);
+ else
+ break;
+ }
+ }
+}
+
+} // namespace __sanitizer
diff --git a/lib/sanitizer_common/sanitizer_common.h b/lib/sanitizer_common/sanitizer_common.h
new file mode 100644
index 0000000..4c7c1e9
--- /dev/null
+++ b/lib/sanitizer_common/sanitizer_common.h
@@ -0,0 +1,123 @@
+//===-- sanitizer_common.h --------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is shared between AddressSanitizer and ThreadSanitizer
+// run-time libraries.
+// It declares common functions and classes that are used in both runtimes.
+// Implementation of some functions are provided in sanitizer_common, while
+// others must be defined by run-time library itself.
+//===----------------------------------------------------------------------===//
+#ifndef SANITIZER_COMMON_H
+#define SANITIZER_COMMON_H
+
+#include "sanitizer_internal_defs.h"
+
+namespace __sanitizer {
+
+// Constants.
+const uptr kWordSize = __WORDSIZE / 8;
+const uptr kWordSizeInBits = 8 * kWordSize;
+const uptr kPageSizeBits = 12;
+const uptr kPageSize = 1UL << kPageSizeBits;
+const uptr kCacheLineSize = 64;
+#ifndef _WIN32
+const uptr kMmapGranularity = kPageSize;
+#else
+const uptr kMmapGranularity = 1UL << 16;
+#endif
+
+// Threads
+int GetPid();
+uptr GetThreadSelf();
+void GetThreadStackTopAndBottom(bool at_initialization, uptr *stack_top,
+ uptr *stack_bottom);
+
+// Memory management
+void *MmapOrDie(uptr size, const char *mem_type);
+void UnmapOrDie(void *addr, uptr size);
+void *MmapFixedNoReserve(uptr fixed_addr, uptr size);
+void *Mprotect(uptr fixed_addr, uptr size);
+// Used to check if we can map shadow memory to a fixed location.
+bool MemoryRangeIsAvailable(uptr range_start, uptr range_end);
+
+// Internal allocator
+void *InternalAlloc(uptr size);
+void InternalFree(void *p);
+// Given the pointer p into a valid allocated block,
+// returns a pointer to the beginning of the block.
+void *InternalAllocBlock(void *p);
+
+// IO
+void RawWrite(const char *buffer);
+void Printf(const char *format, ...);
+void Report(const char *format, ...);
+
+// Opens the file 'file_name" and reads up to 'max_len' bytes.
+// The resulting buffer is mmaped and stored in '*buff'.
+// The size of the mmaped region is stored in '*buff_size',
+// Returns the number of read bytes or 0 if file can not be opened.
+uptr ReadFileToBuffer(const char *file_name, char **buff,
+ uptr *buff_size, uptr max_len);
+// Maps given file to virtual memory, and returns pointer to it
+// (or NULL if the mapping failes). Stores the size of mmaped region
+// in '*buff_size'.
+void *MapFileToMemory(const char *file_name, uptr *buff_size);
+
+const char *GetEnv(const char *name);
+const char *GetPwd();
+
+// Other
+void DisableCoreDumper();
+void DumpProcessMap();
+void SleepForSeconds(int seconds);
+void SleepForMillis(int millis);
+void NORETURN Exit(int exitcode);
+void NORETURN Abort();
+int Atexit(void (*function)(void));
+void SortArray(uptr *array, uptr size);
+
+// Math
+INLINE bool IsPowerOfTwo(uptr x) {
+ return (x & (x - 1)) == 0;
+}
+INLINE uptr RoundUpTo(uptr size, uptr boundary) {
+ CHECK(IsPowerOfTwo(boundary));
+ return (size + boundary - 1) & ~(boundary - 1);
+}
+// Don't use std::min, std::max or std::swap, to minimize dependency
+// on libstdc++.
+template<class T> T Min(T a, T b) { return a < b ? a : b; }
+template<class T> T Max(T a, T b) { return a > b ? a : b; }
+template<class T> void Swap(T& a, T& b) {
+ T tmp = a;
+ a = b;
+ b = tmp;
+}
+
+// Char handling
+INLINE bool IsSpace(int c) {
+ return (c == ' ') || (c == '\n') || (c == '\t') ||
+ (c == '\f') || (c == '\r') || (c == '\v');
+}
+INLINE bool IsDigit(int c) {
+ return (c >= '0') && (c <= '9');
+}
+INLINE int ToLower(int c) {
+ return (c >= 'A' && c <= 'Z') ? (c + 'a' - 'A') : c;
+}
+
+#if __WORDSIZE == 64
+# define FIRST_32_SECOND_64(a, b) (b)
+#else
+# define FIRST_32_SECOND_64(a, b) (a)
+#endif
+
+} // namespace __sanitizer
+
+#endif // SANITIZER_COMMON_H
diff --git a/lib/sanitizer_common/sanitizer_flags.cc b/lib/sanitizer_common/sanitizer_flags.cc
new file mode 100644
index 0000000..cdeeb78
--- /dev/null
+++ b/lib/sanitizer_common/sanitizer_flags.cc
@@ -0,0 +1,82 @@
+//===-- sanitizer_flags.cc ------------------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of ThreadSanitizer/AddressSanitizer runtime.
+//
+//===----------------------------------------------------------------------===//
+
+#include "sanitizer_flags.h"
+
+#include "sanitizer_common.h"
+#include "sanitizer_libc.h"
+
+namespace __sanitizer {
+
+static char *GetFlagValue(const char *env, const char *name) {
+ if (env == 0)
+ return 0;
+ const char *pos = internal_strstr(env, name);
+ const char *end;
+ if (pos == 0)
+ return 0;
+ pos += internal_strlen(name);
+ if (pos[0] != '=') {
+ end = pos;
+ } else {
+ pos += 1;
+ if (pos[0] == '"') {
+ pos += 1;
+ end = internal_strchr(pos, '"');
+ } else if (pos[0] == '\'') {
+ pos += 1;
+ end = internal_strchr(pos, '\'');
+ } else {
+ end = internal_strchr(pos, ' ');
+ }
+ if (end == 0)
+ end = pos + internal_strlen(pos);
+ }
+ int len = end - pos;
+ char *f = (char*)InternalAlloc(len + 1);
+ internal_memcpy(f, pos, len);
+ f[len] = '\0';
+ return f;
+}
+
+void ParseFlag(const char *env, bool *flag, const char *name) {
+ char *val = GetFlagValue(env, name);
+ if (val == 0)
+ return;
+ if (0 == internal_strcmp(val, "0") ||
+ 0 == internal_strcmp(val, "no") ||
+ 0 == internal_strcmp(val, "false"))
+ *flag = false;
+ if (0 == internal_strcmp(val, "1") ||
+ 0 == internal_strcmp(val, "yes") ||
+ 0 == internal_strcmp(val, "true"))
+ *flag = true;
+ InternalFree(val);
+}
+
+void ParseFlag(const char *env, int *flag, const char *name) {
+ char *val = GetFlagValue(env, name);
+ if (val == 0)
+ return;
+ *flag = internal_atoll(val);
+ InternalFree(val);
+}
+
+void ParseFlag(const char *env, const char **flag, const char *name) {
+ const char *val = GetFlagValue(env, name);
+ if (val == 0)
+ return;
+ *flag = val;
+}
+
+} // namespace __sanitizer
diff --git a/lib/sanitizer_common/sanitizer_flags.h b/lib/sanitizer_common/sanitizer_flags.h
new file mode 100644
index 0000000..b7ce452
--- /dev/null
+++ b/lib/sanitizer_common/sanitizer_flags.h
@@ -0,0 +1,27 @@
+//===-- sanitizer_flags.h ---------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of ThreadSanitizer/AddressSanitizer runtime.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef SANITIZER_FLAGS_H
+#define SANITIZER_FLAGS_H
+
+#include "sanitizer_internal_defs.h"
+
+namespace __sanitizer {
+
+void ParseFlag(const char *env, bool *flag, const char *name);
+void ParseFlag(const char *env, int *flag, const char *name);
+void ParseFlag(const char *env, const char **flag, const char *name);
+
+} // namespace __sanitizer
+
+#endif // SANITIZER_FLAGS_H
diff --git a/lib/sanitizer_common/sanitizer_interface_defs.h b/lib/sanitizer_common/sanitizer_interface_defs.h
new file mode 100644
index 0000000..2395ea5
--- /dev/null
+++ b/lib/sanitizer_common/sanitizer_interface_defs.h
@@ -0,0 +1,56 @@
+//===-- sanitizer_interface_defs.h -----------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is shared between AddressSanitizer and ThreadSanitizer.
+// It contains basic macro and types.
+// NOTE: This file may be included into user code.
+//===----------------------------------------------------------------------===//
+
+#ifndef SANITIZER_INTERFACE_DEFS_H
+#define SANITIZER_INTERFACE_DEFS_H
+
+// ----------- ATTENTION -------------
+// This header should NOT include any other headers to avoid portability issues.
+
+#if defined(_WIN32)
+// FIXME find out what we need on Windows. __declspec(dllexport) ?
+# define SANITIZER_INTERFACE_ATTRIBUTE
+# define SANITIZER_WEAK_ATTRIBUTE
+#elif defined(SANITIZER_GO)
+# define SANITIZER_INTERFACE_ATTRIBUTE
+# define SANITIZER_WEAK_ATTRIBUTE
+#else
+# define SANITIZER_INTERFACE_ATTRIBUTE __attribute__((visibility("default")))
+# define SANITIZER_WEAK_ATTRIBUTE __attribute__((weak))
+#endif
+
+// __has_feature
+#if !defined(__has_feature)
+# define __has_feature(x) 0
+#endif
+
+// For portability reasons we do not include stddef.h, stdint.h or any other
+// system header, but we do need some basic types that are not defined
+// in a portable way by the language itself.
+namespace __sanitizer {
+
+typedef unsigned long uptr; // NOLINT
+typedef signed long sptr; // NOLINT
+typedef unsigned char u8;
+typedef unsigned short u16; // NOLINT
+typedef unsigned int u32;
+typedef unsigned long long u64; // NOLINT
+typedef signed char s8;
+typedef signed short s16; // NOLINT
+typedef signed int s32;
+typedef signed long long s64; // NOLINT
+
+} // namespace __sanitizer
+
+#endif // SANITIZER_INTERFACE_DEFS_H
diff --git a/lib/sanitizer_common/sanitizer_internal_defs.h b/lib/sanitizer_common/sanitizer_internal_defs.h
new file mode 100644
index 0000000..b8cf61f
--- /dev/null
+++ b/lib/sanitizer_common/sanitizer_internal_defs.h
@@ -0,0 +1,163 @@
+//===-- sanitizer_internal_defs.h -------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is shared between AddressSanitizer and ThreadSanitizer.
+// It contains macro used in run-time libraries code.
+//===----------------------------------------------------------------------===//
+#ifndef SANITIZER_DEFS_H
+#define SANITIZER_DEFS_H
+
+#include "sanitizer_interface_defs.h"
+using namespace __sanitizer; // NOLINT
+// ----------- ATTENTION -------------
+// This header should NOT include any other headers to avoid portability issues.
+
+// Common defs.
+#define INLINE static inline
+#define INTERFACE_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE
+#define WEAK SANITIZER_WEAK_ATTRIBUTE
+
+// Platform-specific defs.
+#if defined(_WIN32)
+typedef unsigned long DWORD; // NOLINT
+# define ALWAYS_INLINE __declspec(forceinline)
+// FIXME(timurrrr): do we need this on Windows?
+# define ALIAS(x)
+# define ALIGNED(x) __declspec(align(x))
+# define FORMAT(f, a)
+# define NOINLINE __declspec(noinline)
+# define NORETURN __declspec(noreturn)
+# define THREADLOCAL __declspec(thread)
+# define NOTHROW
+#else // _WIN32
+# define ALWAYS_INLINE __attribute__((always_inline))
+# define ALIAS(x) __attribute__((alias(x)))
+# define ALIGNED(x) __attribute__((aligned(x)))
+# define FORMAT(f, a) __attribute__((format(printf, f, a)))
+# define NOINLINE __attribute__((noinline))
+# define NORETURN __attribute__((noreturn))
+# define THREADLOCAL __thread
+# ifdef __cplusplus
+# define NOTHROW throw()
+# else
+# define NOTHROW __attribute__((__nothrow__))
+#endif
+#endif // _WIN32
+
+// We have no equivalent of these on Windows.
+#ifndef _WIN32
+# define LIKELY(x) __builtin_expect(!!(x), 1)
+# define UNLIKELY(x) __builtin_expect(!!(x), 0)
+# define UNUSED __attribute__((unused))
+# define USED __attribute__((used))
+#endif
+
+#if defined(_WIN32)
+typedef DWORD thread_return_t;
+# define THREAD_CALLING_CONV __stdcall
+#else // _WIN32
+typedef void* thread_return_t;
+# define THREAD_CALLING_CONV
+#endif // _WIN32
+typedef thread_return_t (THREAD_CALLING_CONV *thread_callback_t)(void* arg);
+
+// If __WORDSIZE was undefined by the platform, define it in terms of the
+// compiler built-ins __LP64__ and _WIN64.
+#ifndef __WORDSIZE
+# if __LP64__ || defined(_WIN64)
+# define __WORDSIZE 64
+# else
+# define __WORDSIZE 32
+# endif
+#endif // __WORDSIZE
+
+// NOTE: Functions below must be defined in each run-time.
+namespace __sanitizer {
+void NORETURN Die();
+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 { \
+ if (!(expr)) { \
+ RawWrite(msg); \
+ Die(); \
+ } \
+} while (0)
+
+#define RAW_CHECK(expr) RAW_CHECK_MSG(expr, #expr)
+
+#define CHECK_IMPL(c1, op, c2) \
+ do { \
+ __sanitizer::u64 v1 = (u64)(c1); \
+ __sanitizer::u64 v2 = (u64)(c2); \
+ if (!(v1 op v2)) \
+ __sanitizer::CheckFailed(__FILE__, __LINE__, \
+ "(" #c1 ") " #op " (" #c2 ")", v1, v2); \
+ } while (false) \
+/**/
+
+#define CHECK(a) CHECK_IMPL((a), !=, 0)
+#define CHECK_EQ(a, b) CHECK_IMPL((a), ==, (b))
+#define CHECK_NE(a, b) CHECK_IMPL((a), !=, (b))
+#define CHECK_LT(a, b) CHECK_IMPL((a), <, (b))
+#define CHECK_LE(a, b) CHECK_IMPL((a), <=, (b))
+#define CHECK_GT(a, b) CHECK_IMPL((a), >, (b))
+#define CHECK_GE(a, b) CHECK_IMPL((a), >=, (b))
+
+#if TSAN_DEBUG
+#define DCHECK(a) CHECK(a)
+#define DCHECK_EQ(a, b) CHECK_EQ(a, b)
+#define DCHECK_NE(a, b) CHECK_NE(a, b)
+#define DCHECK_LT(a, b) CHECK_LT(a, b)
+#define DCHECK_LE(a, b) CHECK_LE(a, b)
+#define DCHECK_GT(a, b) CHECK_GT(a, b)
+#define DCHECK_GE(a, b) CHECK_GE(a, b)
+#else
+#define DCHECK(a)
+#define DCHECK_EQ(a, b)
+#define DCHECK_NE(a, b)
+#define DCHECK_LT(a, b)
+#define DCHECK_LE(a, b)
+#define DCHECK_GT(a, b)
+#define DCHECK_GE(a, b)
+#endif
+
+#define UNIMPLEMENTED() CHECK("unimplemented" && 0)
+
+#define COMPILER_CHECK(pred) IMPL_COMPILER_ASSERT(pred, __LINE__)
+
+#define IMPL_PASTE(a, b) a##b
+#define IMPL_COMPILER_ASSERT(pred, line) \
+ typedef char IMPL_PASTE(assertion_failed_##_, line)[2*(int)(pred)-1];
+
+// Limits for integral types. We have to redefine it in case we don't
+// have stdint.h (like in Visual Studio 9).
+#if __WORDSIZE == 64
+# define __INT64_C(c) c ## L
+# define __UINT64_C(c) c ## UL
+#else
+# define __INT64_C(c) c ## LL
+# define __UINT64_C(c) c ## ULL
+#endif // __WORDSIZE == 64
+#undef INT32_MIN
+#define INT32_MIN (-2147483647-1)
+#undef INT32_MAX
+#define INT32_MAX (2147483647)
+#undef UINT32_MAX
+#define UINT32_MAX (4294967295U)
+#undef INT64_MIN
+#define INT64_MIN (-__INT64_C(9223372036854775807)-1)
+#undef INT64_MAX
+#define INT64_MAX (__INT64_C(9223372036854775807))
+#undef UINT64_MAX
+#define UINT64_MAX (__UINT64_C(18446744073709551615))
+
+#endif // SANITIZER_DEFS_H
diff --git a/lib/sanitizer_common/sanitizer_libc.cc b/lib/sanitizer_common/sanitizer_libc.cc
new file mode 100644
index 0000000..c433242
--- /dev/null
+++ b/lib/sanitizer_common/sanitizer_libc.cc
@@ -0,0 +1,182 @@
+//===-- sanitizer_libc.cc -------------------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is shared between AddressSanitizer and ThreadSanitizer
+// run-time libraries. See sanitizer_libc.h for details.
+//===----------------------------------------------------------------------===//
+#include "sanitizer_common.h"
+#include "sanitizer_libc.h"
+
+namespace __sanitizer {
+
+s64 internal_atoll(const char *nptr) {
+ return internal_simple_strtoll(nptr, (char**)0, 10);
+}
+
+void *internal_memchr(const void *s, int c, uptr n) {
+ const char* t = (char*)s;
+ for (uptr i = 0; i < n; ++i, ++t)
+ if (*t == c)
+ return (void*)t;
+ return 0;
+}
+
+int internal_memcmp(const void* s1, const void* s2, uptr n) {
+ const char* t1 = (char*)s1;
+ const char* t2 = (char*)s2;
+ for (uptr i = 0; i < n; ++i, ++t1, ++t2)
+ if (*t1 != *t2)
+ return *t1 < *t2 ? -1 : 1;
+ return 0;
+}
+
+void *internal_memcpy(void *dest, const void *src, uptr n) {
+ char *d = (char*)dest;
+ char *s = (char*)src;
+ for (uptr i = 0; i < n; ++i)
+ d[i] = s[i];
+ return dest;
+}
+
+void *internal_memset(void* s, int c, uptr n) {
+ // The next line prevents Clang from making a call to memset() instead of the
+ // loop below.
+ // FIXME: building the runtime with -ffreestanding is a better idea. However
+ // there currently are linktime problems due to PR12396.
+ char volatile *t = (char*)s;
+ for (uptr i = 0; i < n; ++i, ++t) {
+ *t = c;
+ }
+ return s;
+}
+
+char* internal_strdup(const char *s) {
+ uptr len = internal_strlen(s);
+ char *s2 = (char*)InternalAlloc(len + 1);
+ internal_memcpy(s2, s, len);
+ s2[len] = 0;
+ return s2;
+}
+
+int internal_strcmp(const char *s1, const char *s2) {
+ while (true) {
+ unsigned c1 = *s1;
+ unsigned c2 = *s2;
+ if (c1 != c2) return (c1 < c2) ? -1 : 1;
+ if (c1 == 0) break;
+ s1++;
+ s2++;
+ }
+ return 0;
+}
+
+int internal_strncmp(const char *s1, const char *s2, uptr n) {
+ for (uptr i = 0; i < n; i++) {
+ unsigned c1 = *s1;
+ unsigned c2 = *s2;
+ if (c1 != c2) return (c1 < c2) ? -1 : 1;
+ if (c1 == 0) break;
+ s1++;
+ s2++;
+ }
+ return 0;
+}
+
+char* internal_strchr(const char *s, int c) {
+ while (true) {
+ if (*s == (char)c)
+ return (char*)s;
+ if (*s == 0)
+ return 0;
+ s++;
+ }
+}
+
+char *internal_strrchr(const char *s, int c) {
+ const char *res = 0;
+ for (uptr i = 0; s[i]; i++) {
+ if (s[i] == c) res = s + i;
+ }
+ return (char*)res;
+}
+
+uptr internal_strlen(const char *s) {
+ uptr i = 0;
+ while (s[i]) i++;
+ return i;
+}
+
+char *internal_strncat(char *dst, const char *src, uptr n) {
+ uptr len = internal_strlen(dst);
+ uptr i;
+ for (i = 0; i < n && src[i]; i++)
+ dst[len + i] = src[i];
+ dst[len + i] = 0;
+ return dst;
+}
+
+char *internal_strncpy(char *dst, const char *src, uptr n) {
+ uptr i;
+ for (i = 0; i < n && src[i]; i++)
+ dst[i] = src[i];
+ for (; i < n; i++)
+ dst[i] = '\0';
+ return dst;
+}
+
+uptr internal_strnlen(const char *s, uptr maxlen) {
+ uptr i = 0;
+ while (i < maxlen && s[i]) i++;
+ return i;
+}
+
+char *internal_strstr(const char *haystack, const char *needle) {
+ // This is O(N^2), but we are not using it in hot places.
+ uptr len1 = internal_strlen(haystack);
+ uptr len2 = internal_strlen(needle);
+ if (len1 < len2) return 0;
+ for (uptr pos = 0; pos <= len1 - len2; pos++) {
+ if (internal_memcmp(haystack + pos, needle, len2) == 0)
+ return (char*)haystack + pos;
+ }
+ return 0;
+}
+
+s64 internal_simple_strtoll(const char *nptr, char **endptr, int base) {
+ CHECK_EQ(base, 10);
+ while (IsSpace(*nptr)) nptr++;
+ int sgn = 1;
+ u64 res = 0;
+ bool have_digits = false;
+ char *old_nptr = (char*)nptr;
+ if (*nptr == '+') {
+ sgn = 1;
+ nptr++;
+ } else if (*nptr == '-') {
+ sgn = -1;
+ nptr++;
+ }
+ while (IsDigit(*nptr)) {
+ res = (res <= UINT64_MAX / 10) ? res * 10 : UINT64_MAX;
+ int digit = ((*nptr) - '0');
+ res = (res <= UINT64_MAX - digit) ? res + digit : UINT64_MAX;
+ have_digits = true;
+ nptr++;
+ }
+ if (endptr != 0) {
+ *endptr = (have_digits) ? (char*)nptr : old_nptr;
+ }
+ if (sgn > 0) {
+ return (s64)(Min((u64)INT64_MAX, res));
+ } else {
+ return (res > INT64_MAX) ? INT64_MIN : ((s64)res * -1);
+ }
+}
+
+} // namespace __sanitizer
diff --git a/lib/sanitizer_common/sanitizer_libc.h b/lib/sanitizer_common/sanitizer_libc.h
new file mode 100644
index 0000000..8da4286c
--- /dev/null
+++ b/lib/sanitizer_common/sanitizer_libc.h
@@ -0,0 +1,69 @@
+//===-- sanitizer_libc.h ----------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is shared between AddressSanitizer and ThreadSanitizer
+// run-time libraries.
+// These tools can not use some of the libc functions directly because those
+// functions are intercepted. Instead, we implement a tiny subset of libc here.
+// NOTE: This file may be included into user code.
+//===----------------------------------------------------------------------===//
+#ifndef SANITIZER_LIBC_H
+#define SANITIZER_LIBC_H
+
+// ----------- ATTENTION -------------
+// This header should NOT include any other headers from sanitizer runtime.
+#include "sanitizer_interface_defs.h"
+
+namespace __sanitizer {
+
+// internal_X() is a custom implementation of X() for use in RTL.
+
+// String functions
+s64 internal_atoll(const char *nptr);
+void *internal_memchr(const void *s, int c, uptr n);
+int internal_memcmp(const void* s1, const void* s2, uptr n);
+void *internal_memcpy(void *dest, const void *src, uptr n);
+// Should not be used in performance-critical places.
+void *internal_memset(void *s, int c, uptr n);
+char* internal_strchr(const char *s, int c);
+int internal_strcmp(const char *s1, const char *s2);
+char *internal_strdup(const char *s);
+uptr internal_strlen(const char *s);
+char *internal_strncat(char *dst, const char *src, uptr n);
+int internal_strncmp(const char *s1, const char *s2, uptr n);
+char *internal_strncpy(char *dst, const char *src, uptr n);
+uptr internal_strnlen(const char *s, uptr maxlen);
+char *internal_strrchr(const char *s, int c);
+// This is O(N^2), but we are not using it in hot places.
+char *internal_strstr(const char *haystack, const char *needle);
+// Works only for base=10 and doesn't set errno.
+s64 internal_simple_strtoll(const char *nptr, char **endptr, int base);
+
+// Memory
+void *internal_mmap(void *addr, uptr length, int prot, int flags,
+ int fd, u64 offset);
+int internal_munmap(void *addr, uptr length);
+
+// I/O
+typedef int fd_t;
+const fd_t kInvalidFd = -1;
+int internal_close(fd_t fd);
+fd_t internal_open(const char *filename, bool write);
+uptr internal_read(fd_t fd, void *buf, uptr count);
+uptr internal_write(fd_t fd, const void *buf, uptr count);
+uptr internal_filesize(fd_t fd); // -1 on error.
+int internal_dup2(int oldfd, int newfd);
+int internal_snprintf(char *buffer, uptr length, const char *format, ...);
+
+// Threading
+int internal_sched_yield();
+
+} // namespace __sanitizer
+
+#endif // SANITIZER_LIBC_H
diff --git a/lib/sanitizer_common/sanitizer_linux.cc b/lib/sanitizer_common/sanitizer_linux.cc
new file mode 100644
index 0000000..70e2eb3
--- /dev/null
+++ b/lib/sanitizer_common/sanitizer_linux.cc
@@ -0,0 +1,348 @@
+//===-- sanitizer_linux.cc ------------------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is shared between AddressSanitizer and ThreadSanitizer
+// run-time libraries and implements linux-specific functions from
+// sanitizer_libc.h.
+//===----------------------------------------------------------------------===//
+#ifdef __linux__
+
+#include "sanitizer_common.h"
+#include "sanitizer_internal_defs.h"
+#include "sanitizer_libc.h"
+#include "sanitizer_placement_new.h"
+#include "sanitizer_procmaps.h"
+#include "sanitizer_symbolizer.h"
+
+#include <elf.h>
+#include <fcntl.h>
+#include <link.h>
+#include <pthread.h>
+#include <sched.h>
+#include <sys/mman.h>
+#include <sys/resource.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+namespace __sanitizer {
+
+// --------------- sanitizer_libc.h
+void *internal_mmap(void *addr, uptr length, int prot, int flags,
+ int fd, u64 offset) {
+#if __WORDSIZE == 64
+ return (void *)syscall(__NR_mmap, addr, length, prot, flags, fd, offset);
+#else
+ return (void *)syscall(__NR_mmap2, addr, length, prot, flags, fd, offset);
+#endif
+}
+
+int internal_munmap(void *addr, uptr length) {
+ return syscall(__NR_munmap, addr, length);
+}
+
+int internal_close(fd_t fd) {
+ return syscall(__NR_close, fd);
+}
+
+fd_t internal_open(const char *filename, bool write) {
+ return syscall(__NR_open, filename,
+ write ? O_WRONLY | O_CREAT /*| O_CLOEXEC*/ : O_RDONLY, 0660);
+}
+
+uptr internal_read(fd_t fd, void *buf, uptr count) {
+ return (uptr)syscall(__NR_read, fd, buf, count);
+}
+
+uptr internal_write(fd_t fd, const void *buf, uptr count) {
+ return (uptr)syscall(__NR_write, fd, buf, count);
+}
+
+uptr internal_filesize(fd_t fd) {
+#if __WORDSIZE == 64
+ struct stat st;
+ if (syscall(__NR_fstat, fd, &st))
+ return -1;
+#else
+ struct stat64 st;
+ if (syscall(__NR_fstat64, fd, &st))
+ return -1;
+#endif
+ return (uptr)st.st_size;
+}
+
+int internal_dup2(int oldfd, int newfd) {
+ return syscall(__NR_dup2, oldfd, newfd);
+}
+
+int internal_sched_yield() {
+ return syscall(__NR_sched_yield);
+}
+
+// ----------------- sanitizer_common.h
+void GetThreadStackTopAndBottom(bool at_initialization, uptr *stack_top,
+ uptr *stack_bottom) {
+ static const uptr kMaxThreadStackSize = 256 * (1 << 20); // 256M
+ CHECK(stack_top);
+ CHECK(stack_bottom);
+ if (at_initialization) {
+ // This is the main thread. Libpthread may not be initialized yet.
+ struct rlimit rl;
+ CHECK_EQ(getrlimit(RLIMIT_STACK, &rl), 0);
+
+ // Find the mapping that contains a stack variable.
+ ProcessMaps proc_maps;
+ uptr start, end, offset;
+ uptr prev_end = 0;
+ while (proc_maps.Next(&start, &end, &offset, 0, 0)) {
+ if ((uptr)&rl < end)
+ break;
+ prev_end = end;
+ }
+ CHECK((uptr)&rl >= start && (uptr)&rl < end);
+
+ // Get stacksize from rlimit, but clip it so that it does not overlap
+ // with other mappings.
+ uptr stacksize = rl.rlim_cur;
+ if (stacksize > end - prev_end)
+ stacksize = end - prev_end;
+ // When running with unlimited stack size, we still want to set some limit.
+ // The unlimited stack size is caused by 'ulimit -s unlimited'.
+ // Also, for some reason, GNU make spawns subprocesses with unlimited stack.
+ if (stacksize > kMaxThreadStackSize)
+ stacksize = kMaxThreadStackSize;
+ *stack_top = end;
+ *stack_bottom = end - stacksize;
+ return;
+ }
+ pthread_attr_t attr;
+ CHECK_EQ(pthread_getattr_np(pthread_self(), &attr), 0);
+ uptr stacksize = 0;
+ void *stackaddr = 0;
+ pthread_attr_getstack(&attr, &stackaddr, (size_t*)&stacksize);
+ pthread_attr_destroy(&attr);
+
+ *stack_top = (uptr)stackaddr + stacksize;
+ *stack_bottom = (uptr)stackaddr;
+ CHECK(stacksize < kMaxThreadStackSize); // Sanity check.
+}
+
+// Like getenv, but reads env directly from /proc and does not use libc.
+// This function should be called first inside __asan_init.
+const char *GetEnv(const char *name) {
+ static char *environ;
+ static uptr len;
+ static bool inited;
+ if (!inited) {
+ inited = true;
+ uptr environ_size;
+ len = ReadFileToBuffer("/proc/self/environ",
+ &environ, &environ_size, 1 << 26);
+ }
+ if (!environ || len == 0) return 0;
+ uptr namelen = internal_strlen(name);
+ const char *p = environ;
+ while (*p != '\0') { // will happen at the \0\0 that terminates the buffer
+ // proc file has the format NAME=value\0NAME=value\0NAME=value\0...
+ const char* endp =
+ (char*)internal_memchr(p, '\0', len - (p - environ));
+ if (endp == 0) // this entry isn't NUL terminated
+ return 0;
+ else if (!internal_memcmp(p, name, namelen) && p[namelen] == '=') // Match.
+ return p + namelen + 1; // point after =
+ p = endp + 1;
+ }
+ return 0; // Not found.
+}
+
+// ------------------ sanitizer_symbolizer.h
+typedef ElfW(Ehdr) Elf_Ehdr;
+typedef ElfW(Shdr) Elf_Shdr;
+typedef ElfW(Phdr) Elf_Phdr;
+
+bool FindDWARFSection(uptr object_file_addr, const char *section_name,
+ DWARFSection *section) {
+ Elf_Ehdr *exe = (Elf_Ehdr*)object_file_addr;
+ Elf_Shdr *sections = (Elf_Shdr*)(object_file_addr + exe->e_shoff);
+ uptr section_names = object_file_addr +
+ sections[exe->e_shstrndx].sh_offset;
+ for (int i = 0; i < exe->e_shnum; i++) {
+ Elf_Shdr *current_section = &sections[i];
+ const char *current_name = (const char*)section_names +
+ current_section->sh_name;
+ if (IsFullNameOfDWARFSection(current_name, section_name)) {
+ section->data = (const char*)object_file_addr +
+ current_section->sh_offset;
+ section->size = current_section->sh_size;
+ return true;
+ }
+ }
+ return false;
+}
+
+#ifdef ANDROID
+uptr GetListOfModules(ModuleDIContext *modules, uptr max_modules) {
+ UNIMPLEMENTED();
+}
+#else // ANDROID
+struct DlIteratePhdrData {
+ ModuleDIContext *modules;
+ uptr current_n;
+ uptr max_n;
+};
+
+static const uptr kMaxPathLength = 512;
+
+static int dl_iterate_phdr_cb(dl_phdr_info *info, size_t size, void *arg) {
+ DlIteratePhdrData *data = (DlIteratePhdrData*)arg;
+ if (data->current_n == data->max_n)
+ return 0;
+ char *module_name = 0;
+ if (data->current_n == 0) {
+ // First module is the binary itself.
+ module_name = (char*)InternalAlloc(kMaxPathLength);
+ uptr module_name_len = readlink("/proc/self/exe",
+ module_name, kMaxPathLength);
+ CHECK_NE(module_name_len, (uptr)-1);
+ CHECK_LT(module_name_len, kMaxPathLength);
+ module_name[module_name_len] = '\0';
+ } else if (info->dlpi_name) {
+ module_name = internal_strdup(info->dlpi_name);
+ }
+ if (module_name == 0 || module_name[0] == '\0')
+ return 0;
+ void *mem = &data->modules[data->current_n];
+ ModuleDIContext *cur_module = new(mem) ModuleDIContext(module_name,
+ info->dlpi_addr);
+ data->current_n++;
+ for (int i = 0; i < info->dlpi_phnum; i++) {
+ const Elf_Phdr *phdr = &info->dlpi_phdr[i];
+ if (phdr->p_type == PT_LOAD) {
+ uptr cur_beg = info->dlpi_addr + phdr->p_vaddr;
+ uptr cur_end = cur_beg + phdr->p_memsz;
+ cur_module->addAddressRange(cur_beg, cur_end);
+ }
+ }
+ InternalFree(module_name);
+ return 0;
+}
+
+uptr GetListOfModules(ModuleDIContext *modules, uptr max_modules) {
+ CHECK(modules);
+ DlIteratePhdrData data = {modules, 0, max_modules};
+ dl_iterate_phdr(dl_iterate_phdr_cb, &data);
+ return data.current_n;
+}
+#endif // ANDROID
+
+// ----------------- sanitizer_procmaps.h
+ProcessMaps::ProcessMaps() {
+ proc_self_maps_buff_len_ =
+ ReadFileToBuffer("/proc/self/maps", &proc_self_maps_buff_,
+ &proc_self_maps_buff_mmaped_size_, 1 << 26);
+ CHECK_GT(proc_self_maps_buff_len_, 0);
+ // internal_write(2, proc_self_maps_buff_, proc_self_maps_buff_len_);
+ Reset();
+}
+
+ProcessMaps::~ProcessMaps() {
+ UnmapOrDie(proc_self_maps_buff_, proc_self_maps_buff_mmaped_size_);
+}
+
+void ProcessMaps::Reset() {
+ current_ = proc_self_maps_buff_;
+}
+
+// Parse a hex value in str and update str.
+static uptr ParseHex(char **str) {
+ uptr x = 0;
+ char *s;
+ for (s = *str; ; s++) {
+ char c = *s;
+ uptr v = 0;
+ if (c >= '0' && c <= '9')
+ v = c - '0';
+ else if (c >= 'a' && c <= 'f')
+ v = c - 'a' + 10;
+ else if (c >= 'A' && c <= 'F')
+ v = c - 'A' + 10;
+ else
+ break;
+ x = x * 16 + v;
+ }
+ *str = s;
+ return x;
+}
+
+static bool IsOnOf(char c, char c1, char c2) {
+ return c == c1 || c == c2;
+}
+
+static bool IsDecimal(char c) {
+ return c >= '0' && c <= '9';
+}
+
+bool ProcessMaps::Next(uptr *start, uptr *end, uptr *offset,
+ char filename[], uptr filename_size) {
+ char *last = proc_self_maps_buff_ + proc_self_maps_buff_len_;
+ if (current_ >= last) return false;
+ uptr dummy;
+ if (!start) start = &dummy;
+ if (!end) end = &dummy;
+ if (!offset) offset = &dummy;
+ char *next_line = (char*)internal_memchr(current_, '\n', last - current_);
+ if (next_line == 0)
+ next_line = last;
+ // Example: 08048000-08056000 r-xp 00000000 03:0c 64593 /foo/bar
+ *start = ParseHex(&current_);
+ CHECK_EQ(*current_++, '-');
+ *end = ParseHex(&current_);
+ CHECK_EQ(*current_++, ' ');
+ CHECK(IsOnOf(*current_++, '-', 'r'));
+ CHECK(IsOnOf(*current_++, '-', 'w'));
+ CHECK(IsOnOf(*current_++, '-', 'x'));
+ CHECK(IsOnOf(*current_++, 's', 'p'));
+ CHECK_EQ(*current_++, ' ');
+ *offset = ParseHex(&current_);
+ CHECK_EQ(*current_++, ' ');
+ ParseHex(&current_);
+ CHECK_EQ(*current_++, ':');
+ ParseHex(&current_);
+ CHECK_EQ(*current_++, ' ');
+ while (IsDecimal(*current_))
+ current_++;
+ CHECK_EQ(*current_++, ' ');
+ // Skip spaces.
+ while (current_ < next_line && *current_ == ' ')
+ current_++;
+ // Fill in the filename.
+ uptr i = 0;
+ while (current_ < next_line) {
+ if (filename && i < filename_size - 1)
+ filename[i++] = *current_;
+ current_++;
+ }
+ if (filename && i < filename_size)
+ filename[i] = 0;
+ current_ = next_line + 1;
+ return true;
+}
+
+// Gets the object name and the offset by walking ProcessMaps.
+bool ProcessMaps::GetObjectNameAndOffset(uptr addr, uptr *offset,
+ char filename[],
+ uptr filename_size) {
+ return IterateForObjectNameAndOffset(addr, offset, filename, filename_size);
+}
+
+} // namespace __sanitizer
+
+#endif // __linux__
diff --git a/lib/sanitizer_common/sanitizer_list.h b/lib/sanitizer_common/sanitizer_list.h
new file mode 100644
index 0000000..ef98eee
--- /dev/null
+++ b/lib/sanitizer_common/sanitizer_list.h
@@ -0,0 +1,120 @@
+//===-- sanitizer_list.h ----------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file contains implementation of a list class to be used by
+// ThreadSanitizer, etc run-times.
+//
+//===----------------------------------------------------------------------===//
+#ifndef SANITIZER_LIST_H
+#define SANITIZER_LIST_H
+
+#include "sanitizer_internal_defs.h"
+
+namespace __sanitizer {
+
+// Intrusive singly-linked list with size(), push_back(), push_front()
+// pop_front(), append_front() and append_back().
+// This class should be a POD (so that it can be put into TLS)
+// and an object with all zero fields should represent a valid empty list.
+// This class does not have a CTOR, so clear() should be called on all
+// non-zero-initialized objects before using.
+template<class Item>
+struct IntrusiveList {
+ void clear() {
+ first_ = last_ = 0;
+ size_ = 0;
+ }
+
+ bool empty() const { return size_ == 0; }
+ uptr size() const { return size_; }
+
+ void push_back(Item *x) {
+ if (empty()) {
+ x->next = 0;
+ first_ = last_ = x;
+ size_ = 1;
+ } else {
+ x->next = 0;
+ last_->next = x;
+ last_ = x;
+ size_++;
+ }
+ }
+
+ void push_front(Item *x) {
+ if (empty()) {
+ x->next = 0;
+ first_ = last_ = x;
+ size_ = 1;
+ } else {
+ x->next = first_;
+ first_ = x;
+ size_++;
+ }
+ }
+
+ void pop_front() {
+ CHECK(!empty());
+ first_ = first_->next;
+ if (first_ == 0)
+ last_ = 0;
+ size_--;
+ }
+
+ Item *front() { return first_; }
+ Item *back() { return last_; }
+
+ void append_front(IntrusiveList<Item> *l) {
+ CHECK_NE(this, l);
+ if (empty()) {
+ *this = *l;
+ } else if (!l->empty()) {
+ l->last_->next = first_;
+ first_ = l->first_;
+ size_ += l->size();
+ }
+ l->clear();
+ }
+
+ void append_back(IntrusiveList<Item> *l) {
+ CHECK_NE(this, l);
+ if (empty()) {
+ *this = *l;
+ } else {
+ last_->next = l->first_;
+ last_ = l->last_;
+ size_ += l->size();
+ }
+ l->clear();
+ }
+
+ void CheckConsistency() {
+ if (size_ == 0) {
+ CHECK_EQ(first_, 0);
+ CHECK_EQ(last_, 0);
+ } else {
+ uptr count = 0;
+ for (Item *i = first_; ; i = i->next) {
+ count++;
+ if (i == last_) break;
+ }
+ CHECK_EQ(size(), count);
+ CHECK_EQ(last_->next, 0);
+ }
+ }
+
+// private, don't use directly.
+ uptr size_;
+ Item *first_;
+ Item *last_;
+};
+
+} // namespace __sanitizer
+
+#endif // SANITIZER_LIST_H
diff --git a/lib/sanitizer_common/sanitizer_mac.cc b/lib/sanitizer_common/sanitizer_mac.cc
new file mode 100644
index 0000000..e64c2de
--- /dev/null
+++ b/lib/sanitizer_common/sanitizer_mac.cc
@@ -0,0 +1,243 @@
+//===-- sanitizer_mac.cc --------------------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is shared between AddressSanitizer and ThreadSanitizer
+// run-time libraries and implements mac-specific functions from
+// sanitizer_libc.h.
+//===----------------------------------------------------------------------===//
+
+#ifdef __APPLE__
+
+#include "sanitizer_common.h"
+#include "sanitizer_internal_defs.h"
+#include "sanitizer_libc.h"
+#include "sanitizer_procmaps.h"
+#include "sanitizer_symbolizer.h"
+
+#include <crt_externs.h> // for _NSGetEnviron
+#include <fcntl.h>
+#include <mach-o/dyld.h>
+#include <mach-o/loader.h>
+#include <pthread.h>
+#include <sched.h>
+#include <sys/mman.h>
+#include <sys/resource.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+namespace __sanitizer {
+
+// ---------------------- sanitizer_libc.h
+void *internal_mmap(void *addr, size_t length, int prot, int flags,
+ int fd, u64 offset) {
+ return mmap(addr, length, prot, flags, fd, offset);
+}
+
+int internal_munmap(void *addr, uptr length) {
+ return munmap(addr, length);
+}
+
+int internal_close(fd_t fd) {
+ return close(fd);
+}
+
+fd_t internal_open(const char *filename, bool write) {
+ return open(filename,
+ write ? O_WRONLY | O_CREAT : O_RDONLY, 0660);
+}
+
+uptr internal_read(fd_t fd, void *buf, uptr count) {
+ return read(fd, buf, count);
+}
+
+uptr internal_write(fd_t fd, const void *buf, uptr count) {
+ return write(fd, buf, count);
+}
+
+uptr internal_filesize(fd_t fd) {
+ struct stat st = {};
+ if (fstat(fd, &st))
+ return -1;
+ return (uptr)st.st_size;
+}
+
+int internal_dup2(int oldfd, int newfd) {
+ return dup2(oldfd, newfd);
+}
+
+int internal_sched_yield() {
+ return sched_yield();
+}
+
+// ----------------- sanitizer_common.h
+void GetThreadStackTopAndBottom(bool at_initialization, uptr *stack_top,
+ uptr *stack_bottom) {
+ CHECK(stack_top);
+ CHECK(stack_bottom);
+ uptr stacksize = pthread_get_stacksize_np(pthread_self());
+ void *stackaddr = pthread_get_stackaddr_np(pthread_self());
+ *stack_top = (uptr)stackaddr;
+ *stack_bottom = *stack_top - stacksize;
+}
+
+const char *GetEnv(const char *name) {
+ char ***env_ptr = _NSGetEnviron();
+ CHECK(env_ptr);
+ char **environ = *env_ptr;
+ CHECK(environ);
+ uptr name_len = internal_strlen(name);
+ while (*environ != 0) {
+ uptr len = internal_strlen(*environ);
+ if (len > name_len) {
+ const char *p = *environ;
+ if (!internal_memcmp(p, name, name_len) &&
+ p[name_len] == '=') { // Match.
+ return *environ + name_len + 1; // String starting after =.
+ }
+ }
+ environ++;
+ }
+ return 0;
+}
+
+// ------------------ sanitizer_symbolizer.h
+bool FindDWARFSection(uptr object_file_addr, const char *section_name,
+ DWARFSection *section) {
+ UNIMPLEMENTED();
+ return false;
+}
+
+uptr GetListOfModules(ModuleDIContext *modules, uptr max_modules) {
+ UNIMPLEMENTED();
+ return 0;
+};
+
+// ----------------- sanitizer_procmaps.h
+
+ProcessMaps::ProcessMaps() {
+ Reset();
+}
+
+ProcessMaps::~ProcessMaps() {
+}
+
+// More information about Mach-O headers can be found in mach-o/loader.h
+// Each Mach-O image has a header (mach_header or mach_header_64) starting with
+// a magic number, and a list of linker load commands directly following the
+// header.
+// A load command is at least two 32-bit words: the command type and the
+// command size in bytes. We're interested only in segment load commands
+// (LC_SEGMENT and LC_SEGMENT_64), which tell that a part of the file is mapped
+// into the task's address space.
+// The |vmaddr|, |vmsize| and |fileoff| fields of segment_command or
+// segment_command_64 correspond to the memory address, memory size and the
+// file offset of the current memory segment.
+// Because these fields are taken from the images as is, one needs to add
+// _dyld_get_image_vmaddr_slide() to get the actual addresses at runtime.
+
+void ProcessMaps::Reset() {
+ // Count down from the top.
+ // TODO(glider): as per man 3 dyld, iterating over the headers with
+ // _dyld_image_count is thread-unsafe. We need to register callbacks for
+ // adding and removing images which will invalidate the ProcessMaps state.
+ current_image_ = _dyld_image_count();
+ current_load_cmd_count_ = -1;
+ current_load_cmd_addr_ = 0;
+ current_magic_ = 0;
+}
+
+// Next and NextSegmentLoad were inspired by base/sysinfo.cc in
+// Google Perftools, http://code.google.com/p/google-perftools.
+
+// NextSegmentLoad scans the current image for the next segment load command
+// and returns the start and end addresses and file offset of the corresponding
+// segment.
+// Note that the segment addresses are not necessarily sorted.
+template<u32 kLCSegment, typename SegmentCommand>
+bool ProcessMaps::NextSegmentLoad(
+ uptr *start, uptr *end, uptr *offset,
+ char filename[], uptr filename_size) {
+ const char* lc = current_load_cmd_addr_;
+ current_load_cmd_addr_ += ((const load_command *)lc)->cmdsize;
+ if (((const load_command *)lc)->cmd == kLCSegment) {
+ const sptr dlloff = _dyld_get_image_vmaddr_slide(current_image_);
+ const SegmentCommand* sc = (const SegmentCommand *)lc;
+ if (start) *start = sc->vmaddr + dlloff;
+ if (end) *end = sc->vmaddr + sc->vmsize + dlloff;
+ if (offset) *offset = sc->fileoff;
+ if (filename) {
+ internal_strncpy(filename, _dyld_get_image_name(current_image_),
+ filename_size);
+ }
+ return true;
+ }
+ return false;
+}
+
+bool ProcessMaps::Next(uptr *start, uptr *end, uptr *offset,
+ char filename[], uptr filename_size) {
+ for (; current_image_ >= 0; current_image_--) {
+ const mach_header* hdr = _dyld_get_image_header(current_image_);
+ if (!hdr) continue;
+ if (current_load_cmd_count_ < 0) {
+ // Set up for this image;
+ current_load_cmd_count_ = hdr->ncmds;
+ current_magic_ = hdr->magic;
+ switch (current_magic_) {
+#ifdef MH_MAGIC_64
+ case MH_MAGIC_64: {
+ current_load_cmd_addr_ = (char*)hdr + sizeof(mach_header_64);
+ break;
+ }
+#endif
+ case MH_MAGIC: {
+ current_load_cmd_addr_ = (char*)hdr + sizeof(mach_header);
+ break;
+ }
+ default: {
+ continue;
+ }
+ }
+ }
+
+ for (; current_load_cmd_count_ >= 0; current_load_cmd_count_--) {
+ switch (current_magic_) {
+ // current_magic_ may be only one of MH_MAGIC, MH_MAGIC_64.
+#ifdef MH_MAGIC_64
+ case MH_MAGIC_64: {
+ if (NextSegmentLoad<LC_SEGMENT_64, struct segment_command_64>(
+ start, end, offset, filename, filename_size))
+ return true;
+ break;
+ }
+#endif
+ case MH_MAGIC: {
+ if (NextSegmentLoad<LC_SEGMENT, struct segment_command>(
+ start, end, offset, filename, filename_size))
+ return true;
+ break;
+ }
+ }
+ }
+ // If we get here, no more load_cmd's in this image talk about
+ // segments. Go on to the next image.
+ }
+ return false;
+}
+
+bool ProcessMaps::GetObjectNameAndOffset(uptr addr, uptr *offset,
+ char filename[],
+ uptr filename_size) {
+ return IterateForObjectNameAndOffset(addr, offset, filename, filename_size);
+}
+
+} // namespace __sanitizer
+
+#endif // __APPLE__
diff --git a/lib/sanitizer_common/sanitizer_mutex.h b/lib/sanitizer_common/sanitizer_mutex.h
new file mode 100644
index 0000000..ca3e2f9
--- /dev/null
+++ b/lib/sanitizer_common/sanitizer_mutex.h
@@ -0,0 +1,100 @@
+//===-- sanitizer_mutex.h ---------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of ThreadSanitizer/AddressSanitizer runtime.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef SANITIZER_MUTEX_H
+#define SANITIZER_MUTEX_H
+
+#include "sanitizer_atomic.h"
+#include "sanitizer_internal_defs.h"
+#include "sanitizer_libc.h"
+
+namespace __sanitizer {
+
+class SpinMutex {
+ public:
+ SpinMutex() {
+ atomic_store(&state_, 0, memory_order_relaxed);
+ }
+
+ void Lock() {
+ if (atomic_exchange(&state_, 1, memory_order_acquire) == 0)
+ return;
+ LockSlow();
+ }
+
+ void Unlock() {
+ atomic_store(&state_, 0, memory_order_release);
+ }
+
+ private:
+ atomic_uint8_t state_;
+
+ void NOINLINE LockSlow() {
+ for (int i = 0;; i++) {
+ if (i < 10)
+ proc_yield(10);
+ else
+ internal_sched_yield();
+ if (atomic_load(&state_, memory_order_relaxed) == 0
+ && atomic_exchange(&state_, 1, memory_order_acquire) == 0)
+ return;
+ }
+ }
+
+ SpinMutex(const SpinMutex&);
+ void operator=(const SpinMutex&);
+};
+
+template<typename MutexType>
+class GenericScopedLock {
+ public:
+ explicit GenericScopedLock(MutexType *mu)
+ : mu_(mu) {
+ mu_->Lock();
+ }
+
+ ~GenericScopedLock() {
+ mu_->Unlock();
+ }
+
+ private:
+ MutexType *mu_;
+
+ GenericScopedLock(const GenericScopedLock&);
+ void operator=(const GenericScopedLock&);
+};
+
+template<typename MutexType>
+class GenericScopedReadLock {
+ public:
+ explicit GenericScopedReadLock(MutexType *mu)
+ : mu_(mu) {
+ mu_->ReadLock();
+ }
+
+ ~GenericScopedReadLock() {
+ mu_->ReadUnlock();
+ }
+
+ private:
+ MutexType *mu_;
+
+ GenericScopedReadLock(const GenericScopedReadLock&);
+ void operator=(const GenericScopedReadLock&);
+};
+
+typedef GenericScopedLock<SpinMutex> SpinMutexLock;
+
+} // namespace __sanitizer
+
+#endif // SANITIZER_MUTEX_H
diff --git a/lib/sanitizer_common/sanitizer_placement_new.h b/lib/sanitizer_common/sanitizer_placement_new.h
new file mode 100644
index 0000000..f133a6f
--- /dev/null
+++ b/lib/sanitizer_common/sanitizer_placement_new.h
@@ -0,0 +1,33 @@
+//===-- sanitizer_placement_new.h -------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is shared between AddressSanitizer and ThreadSanitizer
+// run-time libraries.
+//
+// The file provides 'placement new'.
+// Do not include it into header files, only into source files.
+//===----------------------------------------------------------------------===//
+#ifndef SANITIZER_PLACEMENT_NEW_H
+#define SANITIZER_PLACEMENT_NEW_H
+
+#include "sanitizer_internal_defs.h"
+
+namespace __sanitizer {
+#if (__WORDSIZE == 64) || defined(__APPLE__)
+typedef uptr operator_new_ptr_type;
+#else
+typedef u32 operator_new_ptr_type;
+#endif
+} // namespace __sanitizer
+
+inline void *operator new(__sanitizer::operator_new_ptr_type sz, void *p) {
+ return p;
+}
+
+#endif // SANITIZER_PLACEMENT_NEW_H
diff --git a/lib/sanitizer_common/sanitizer_posix.cc b/lib/sanitizer_common/sanitizer_posix.cc
new file mode 100644
index 0000000..4caee3b
--- /dev/null
+++ b/lib/sanitizer_common/sanitizer_posix.cc
@@ -0,0 +1,164 @@
+//===-- sanitizer_posix.cc ------------------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is shared between AddressSanitizer and ThreadSanitizer
+// run-time libraries and implements POSIX-specific functions from
+// sanitizer_libc.h.
+//===----------------------------------------------------------------------===//
+#if defined(__linux__) || defined(__APPLE__)
+
+#include "sanitizer_common.h"
+#include "sanitizer_libc.h"
+#include "sanitizer_procmaps.h"
+
+#include <pthread.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/mman.h>
+#include <sys/resource.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+namespace __sanitizer {
+
+// ------------- sanitizer_common.h
+
+int GetPid() {
+ return getpid();
+}
+
+uptr GetThreadSelf() {
+ return (uptr)pthread_self();
+}
+
+void *MmapOrDie(uptr size, const char *mem_type) {
+ size = RoundUpTo(size, kPageSize);
+ void *res = internal_mmap(0, size,
+ PROT_READ | PROT_WRITE,
+ MAP_PRIVATE | MAP_ANON, -1, 0);
+ if (res == (void*)-1) {
+ Report("ERROR: Failed to allocate 0x%zx (%zd) bytes of %s\n",
+ size, size, mem_type);
+ CHECK("unable to mmap" && 0);
+ }
+ return res;
+}
+
+void UnmapOrDie(void *addr, uptr size) {
+ if (!addr || !size) return;
+ int res = internal_munmap(addr, size);
+ if (res != 0) {
+ Report("ERROR: Failed to deallocate 0x%zx (%zd) bytes at address %p\n",
+ size, size, addr);
+ CHECK("unable to unmap" && 0);
+ }
+}
+
+void *MmapFixedNoReserve(uptr fixed_addr, uptr size) {
+ return internal_mmap((void*)fixed_addr, size,
+ PROT_READ | PROT_WRITE,
+ MAP_PRIVATE | MAP_ANON | MAP_FIXED | MAP_NORESERVE,
+ -1, 0);
+}
+
+void *Mprotect(uptr fixed_addr, uptr size) {
+ return internal_mmap((void*)fixed_addr, size,
+ PROT_NONE,
+ MAP_PRIVATE | MAP_ANON | MAP_FIXED | MAP_NORESERVE,
+ -1, 0);
+}
+
+void *MapFileToMemory(const char *file_name, uptr *buff_size) {
+ fd_t fd = internal_open(file_name, false);
+ CHECK_NE(fd, kInvalidFd);
+ uptr fsize = internal_filesize(fd);
+ CHECK_NE(fsize, (uptr)-1);
+ CHECK_GT(fsize, 0);
+ *buff_size = RoundUpTo(fsize, kPageSize);
+ void *map = internal_mmap(0, *buff_size, PROT_READ, MAP_PRIVATE, fd, 0);
+ return (map == MAP_FAILED) ? 0 : map;
+}
+
+
+static inline bool IntervalsAreSeparate(uptr start1, uptr end1,
+ uptr start2, uptr end2) {
+ CHECK(start1 <= end1);
+ CHECK(start2 <= end2);
+ return (end1 < start2) || (end2 < start1);
+}
+
+// FIXME: this is thread-unsafe, but should not cause problems most of the time.
+// When the shadow is mapped only a single thread usually exists (plus maybe
+// several worker threads on Mac, which aren't expected to map big chunks of
+// memory).
+bool MemoryRangeIsAvailable(uptr range_start, uptr range_end) {
+ ProcessMaps procmaps;
+ uptr start, end;
+ while (procmaps.Next(&start, &end,
+ /*offset*/0, /*filename*/0, /*filename_size*/0)) {
+ if (!IntervalsAreSeparate(start, end, range_start, range_end))
+ return false;
+ }
+ return true;
+}
+
+void DumpProcessMap() {
+ ProcessMaps proc_maps;
+ uptr start, end;
+ const sptr kBufSize = 4095;
+ char *filename = (char*)MmapOrDie(kBufSize, __FUNCTION__);
+ Report("Process memory map follows:\n");
+ while (proc_maps.Next(&start, &end, /* file_offset */0,
+ filename, kBufSize)) {
+ Printf("\t%p-%p\t%s\n", (void*)start, (void*)end, filename);
+ }
+ Report("End of process memory map.\n");
+ UnmapOrDie(filename, kBufSize);
+}
+
+const char *GetPwd() {
+ return GetEnv("PWD");
+}
+
+void DisableCoreDumper() {
+ struct rlimit nocore;
+ nocore.rlim_cur = 0;
+ nocore.rlim_max = 0;
+ setrlimit(RLIMIT_CORE, &nocore);
+}
+
+void SleepForSeconds(int seconds) {
+ sleep(seconds);
+}
+
+void SleepForMillis(int millis) {
+ usleep(millis * 1000);
+}
+
+void Exit(int exitcode) {
+ _exit(exitcode);
+}
+
+void Abort() {
+ abort();
+}
+
+int Atexit(void (*function)(void)) {
+#ifndef SANITIZER_GO
+ return atexit(function);
+#else
+ return 0;
+#endif
+}
+
+} // namespace __sanitizer
+
+#endif // __linux__ || __APPLE_
diff --git a/lib/sanitizer_common/sanitizer_printf.cc b/lib/sanitizer_common/sanitizer_printf.cc
new file mode 100644
index 0000000..7b70c3a
--- /dev/null
+++ b/lib/sanitizer_common/sanitizer_printf.cc
@@ -0,0 +1,185 @@
+//===-- sanitizer_printf.cc -----------------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is shared between AddressSanitizer and ThreadSanitizer.
+//
+// Internal printf function, used inside run-time libraries.
+// We can't use libc printf because we intercept some of the functions used
+// inside it.
+//===----------------------------------------------------------------------===//
+
+
+#include "sanitizer_common.h"
+#include "sanitizer_libc.h"
+
+#include <stdio.h>
+#include <stdarg.h>
+
+namespace __sanitizer {
+
+static int AppendChar(char **buff, const char *buff_end, char c) {
+ if (*buff < buff_end) {
+ **buff = c;
+ (*buff)++;
+ }
+ return 1;
+}
+
+// Appends number in a given base to buffer. If its length is less than
+// "minimal_num_length", it is padded with leading zeroes.
+static int AppendUnsigned(char **buff, const char *buff_end, u64 num,
+ u8 base, u8 minimal_num_length) {
+ uptr const kMaxLen = 30;
+ RAW_CHECK(base == 10 || base == 16);
+ RAW_CHECK(minimal_num_length < kMaxLen);
+ uptr num_buffer[kMaxLen];
+ uptr pos = 0;
+ do {
+ RAW_CHECK_MSG(pos < kMaxLen, "appendNumber buffer overflow");
+ num_buffer[pos++] = num % base;
+ num /= base;
+ } while (num > 0);
+ while (pos < minimal_num_length) num_buffer[pos++] = 0;
+ int result = 0;
+ while (pos-- > 0) {
+ uptr digit = num_buffer[pos];
+ result += AppendChar(buff, buff_end, (digit < 10) ? '0' + digit
+ : 'a' + digit - 10);
+ }
+ return result;
+}
+
+static int AppendSignedDecimal(char **buff, const char *buff_end, s64 num) {
+ int result = 0;
+ if (num < 0) {
+ result += AppendChar(buff, buff_end, '-');
+ num = -num;
+ }
+ result += AppendUnsigned(buff, buff_end, (u64)num, 10, 0);
+ return result;
+}
+
+static int AppendString(char **buff, const char *buff_end, const char *s) {
+ if (s == 0)
+ s = "<null>";
+ int result = 0;
+ for (; *s; s++) {
+ result += AppendChar(buff, buff_end, *s);
+ }
+ return result;
+}
+
+static int AppendPointer(char **buff, const char *buff_end, u64 ptr_value) {
+ int result = 0;
+ result += AppendString(buff, buff_end, "0x");
+ result += AppendUnsigned(buff, buff_end, ptr_value, 16,
+ (__WORDSIZE == 64) ? 12 : 8);
+ return result;
+}
+
+int VSNPrintf(char *buff, int buff_length,
+ const char *format, va_list args) {
+ static const char *kPrintfFormatsHelp = "Supported Printf formats: "
+ "%%[z]{d,u,x}; %%p; %%s\n";
+ RAW_CHECK(format);
+ RAW_CHECK(buff_length > 0);
+ const char *buff_end = &buff[buff_length - 1];
+ const char *cur = format;
+ int result = 0;
+ for (; *cur; cur++) {
+ if (*cur != '%') {
+ result += AppendChar(&buff, buff_end, *cur);
+ continue;
+ }
+ cur++;
+ bool have_z = (*cur == 'z');
+ cur += have_z;
+ s64 dval;
+ u64 uval;
+ switch (*cur) {
+ case 'd': {
+ dval = have_z ? va_arg(args, sptr)
+ : va_arg(args, int);
+ result += AppendSignedDecimal(&buff, buff_end, dval);
+ break;
+ }
+ case 'u':
+ case 'x': {
+ uval = have_z ? va_arg(args, uptr)
+ : va_arg(args, unsigned);
+ result += AppendUnsigned(&buff, buff_end, uval,
+ (*cur == 'u') ? 10 : 16, 0);
+ break;
+ }
+ case 'p': {
+ RAW_CHECK_MSG(!have_z, kPrintfFormatsHelp);
+ result += AppendPointer(&buff, buff_end, va_arg(args, uptr));
+ break;
+ }
+ case 's': {
+ RAW_CHECK_MSG(!have_z, kPrintfFormatsHelp);
+ result += AppendString(&buff, buff_end, va_arg(args, char*));
+ break;
+ }
+ case '%' : {
+ RAW_CHECK_MSG(!have_z, kPrintfFormatsHelp);
+ result += AppendChar(&buff, buff_end, '%');
+ break;
+ }
+ default: {
+ RAW_CHECK_MSG(false, kPrintfFormatsHelp);
+ }
+ }
+ }
+ RAW_CHECK(buff <= buff_end);
+ AppendChar(&buff, buff_end + 1, '\0');
+ return result;
+}
+
+void Printf(const char *format, ...) {
+ const int kLen = 1024 * 4;
+ char *buffer = (char*)MmapOrDie(kLen, __FUNCTION__);
+ va_list args;
+ va_start(args, format);
+ int needed_length = VSNPrintf(buffer, kLen, format, args);
+ va_end(args);
+ RAW_CHECK_MSG(needed_length < kLen, "Buffer in Printf is too short!\n");
+ RawWrite(buffer);
+ UnmapOrDie(buffer, kLen);
+}
+
+// Writes at most "length" symbols to "buffer" (including trailing '\0').
+// Returns the number of symbols that should have been written to buffer
+// (not including trailing '\0'). Thus, the string is truncated
+// iff return value is not less than "length".
+int internal_snprintf(char *buffer, uptr length, const char *format, ...) {
+ va_list args;
+ va_start(args, format);
+ int needed_length = VSNPrintf(buffer, length, format, args);
+ va_end(args);
+ return needed_length;
+}
+
+// Like Printf, but prints the current PID before the output string.
+void Report(const char *format, ...) {
+ const int kLen = 1024 * 4;
+ char *buffer = (char*)MmapOrDie(kLen, __FUNCTION__);
+ int needed_length = internal_snprintf(buffer, kLen, "==%d== ", GetPid());
+ RAW_CHECK_MSG(needed_length < kLen, "Buffer in Report is too short!\n");
+ va_list args;
+ va_start(args, format);
+ needed_length += VSNPrintf(buffer + needed_length, kLen - needed_length,
+ format, args);
+ va_end(args);
+ RAW_CHECK_MSG(needed_length < kLen, "Buffer in Report is too short!\n");
+ RawWrite(buffer);
+ UnmapOrDie(buffer, kLen);
+}
+
+} // namespace __sanitizer
diff --git a/lib/sanitizer_common/sanitizer_procmaps.h b/lib/sanitizer_common/sanitizer_procmaps.h
new file mode 100644
index 0000000..e7f9cac
--- /dev/null
+++ b/lib/sanitizer_common/sanitizer_procmaps.h
@@ -0,0 +1,82 @@
+//===-- sanitizer_procmaps.h ------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is shared between AddressSanitizer and ThreadSanitizer.
+//
+// Information about the process mappings.
+//===----------------------------------------------------------------------===//
+#ifndef SANITIZER_PROCMAPS_H
+#define SANITIZER_PROCMAPS_H
+
+#include "sanitizer_internal_defs.h"
+
+namespace __sanitizer {
+
+class ProcessMaps {
+ public:
+ ProcessMaps();
+ bool Next(uptr *start, uptr *end, uptr *offset,
+ char filename[], uptr filename_size);
+ void Reset();
+ // Gets the object file name and the offset in that object for a given
+ // address 'addr'. Returns true on success.
+ bool GetObjectNameAndOffset(uptr addr, uptr *offset,
+ char filename[], uptr filename_size);
+ ~ProcessMaps();
+
+ private:
+ // Default implementation of GetObjectNameAndOffset.
+ // Quite slow, because it iterates through the whole process map for each
+ // lookup.
+ bool IterateForObjectNameAndOffset(uptr addr, uptr *offset,
+ char filename[], uptr filename_size) {
+ Reset();
+ uptr start, end, file_offset;
+ for (int i = 0; Next(&start, &end, &file_offset, filename, filename_size);
+ i++) {
+ if (addr >= start && addr < end) {
+ // Don't subtract 'start' for the first entry:
+ // * If a binary is compiled w/o -pie, then the first entry in
+ // process maps is likely the binary itself (all dynamic libs
+ // are mapped higher in address space). For such a binary,
+ // instruction offset in binary coincides with the actual
+ // instruction address in virtual memory (as code section
+ // is mapped to a fixed memory range).
+ // * If a binary is compiled with -pie, all the modules are
+ // mapped high at address space (in particular, higher than
+ // shadow memory of the tool), so the module can't be the
+ // first entry.
+ *offset = (addr - (i ? start : 0)) + file_offset;
+ return true;
+ }
+ }
+ if (filename_size)
+ filename[0] = '\0';
+ return false;
+ }
+
+#if defined __linux__
+ char *proc_self_maps_buff_;
+ uptr proc_self_maps_buff_mmaped_size_;
+ uptr proc_self_maps_buff_len_;
+ char *current_;
+#elif defined __APPLE__
+ template<u32 kLCSegment, typename SegmentCommand>
+ bool NextSegmentLoad(uptr *start, uptr *end, uptr *offset,
+ char filename[], uptr filename_size);
+ int current_image_;
+ u32 current_magic_;
+ int current_load_cmd_count_;
+ char *current_load_cmd_addr_;
+#endif
+};
+
+} // namespace __sanitizer
+
+#endif // SANITIZER_PROCMAPS_H
diff --git a/lib/sanitizer_common/sanitizer_symbolizer.cc b/lib/sanitizer_common/sanitizer_symbolizer.cc
new file mode 100644
index 0000000..85eb076
--- /dev/null
+++ b/lib/sanitizer_common/sanitizer_symbolizer.cc
@@ -0,0 +1,144 @@
+//===-- sanitizer_symbolizer.cc -------------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This is a stub for LLVM-based symbolizer.
+// This file is shared between AddressSanitizer and ThreadSanitizer
+// run-time libraries. See sanitizer.h for details.
+//===----------------------------------------------------------------------===//
+
+#include "sanitizer_common.h"
+#include "sanitizer_placement_new.h"
+#include "sanitizer_procmaps.h"
+#include "sanitizer_symbolizer.h"
+
+namespace __sanitizer {
+
+bool IsFullNameOfDWARFSection(const char *full_name, const char *short_name) {
+ // Skip "__DWARF," prefix.
+ if (0 == internal_strncmp(full_name, "__DWARF,", 8)) {
+ full_name += 8;
+ }
+ // Skip . and _ prefices.
+ while (*full_name == '.' || *full_name == '_') {
+ full_name++;
+ }
+ return 0 == internal_strcmp(full_name, short_name);
+}
+
+void AddressInfo::Clear() {
+ InternalFree(module);
+ InternalFree(function);
+ InternalFree(file);
+ internal_memset(this, 0, sizeof(AddressInfo));
+}
+
+ModuleDIContext::ModuleDIContext(const char *module_name, uptr base_address) {
+ full_name_ = internal_strdup(module_name);
+ short_name_ = internal_strrchr(module_name, '/');
+ if (short_name_ == 0) {
+ short_name_ = full_name_;
+ } else {
+ short_name_++;
+ }
+ base_address_ = base_address;
+ n_ranges_ = 0;
+ mapped_addr_ = 0;
+ mapped_size_ = 0;
+}
+
+void ModuleDIContext::addAddressRange(uptr beg, uptr end) {
+ CHECK_LT(n_ranges_, kMaxNumberOfAddressRanges);
+ ranges_[n_ranges_].beg = beg;
+ ranges_[n_ranges_].end = end;
+ n_ranges_++;
+}
+
+bool ModuleDIContext::containsAddress(uptr address) const {
+ for (uptr i = 0; i < n_ranges_; i++) {
+ if (ranges_[i].beg <= address && address < ranges_[i].end)
+ return true;
+ }
+ return false;
+}
+
+void ModuleDIContext::getAddressInfo(AddressInfo *info) {
+ info->module = internal_strdup(full_name_);
+ info->module_offset = info->address - base_address_;
+ if (mapped_addr_ == 0)
+ CreateDIContext();
+ // FIXME: Use the actual debug info context here.
+ info->function = 0;
+ info->file = 0;
+ info->line = 0;
+ info->column = 0;
+}
+
+void ModuleDIContext::CreateDIContext() {
+ mapped_addr_ = (uptr)MapFileToMemory(full_name_, &mapped_size_);
+ CHECK(mapped_addr_);
+ DWARFSection debug_info;
+ DWARFSection debug_abbrev;
+ DWARFSection debug_line;
+ DWARFSection debug_aranges;
+ DWARFSection debug_str;
+ FindDWARFSection(mapped_addr_, "debug_info", &debug_info);
+ FindDWARFSection(mapped_addr_, "debug_abbrev", &debug_abbrev);
+ FindDWARFSection(mapped_addr_, "debug_line", &debug_line);
+ FindDWARFSection(mapped_addr_, "debug_aranges", &debug_aranges);
+ FindDWARFSection(mapped_addr_, "debug_str", &debug_str);
+ // FIXME: Construct actual debug info context using mapped_addr,
+ // mapped_size and pointers to DWARF sections in memory.
+}
+
+class Symbolizer {
+ public:
+ uptr SymbolizeCode(uptr addr, AddressInfo *frames, uptr max_frames) {
+ if (max_frames == 0)
+ return 0;
+ AddressInfo *info = &frames[0];
+ info->Clear();
+ info->address = addr;
+ ModuleDIContext *module = FindModuleForAddress(addr);
+ if (module) {
+ module->getAddressInfo(info);
+ return 1;
+ }
+ return 0;
+ }
+
+ private:
+ ModuleDIContext *FindModuleForAddress(uptr address) {
+ if (modules_ == 0) {
+ modules_ = (ModuleDIContext*)InternalAlloc(
+ kMaxNumberOfModuleContexts * sizeof(ModuleDIContext));
+ CHECK(modules_);
+ n_modules_ = GetListOfModules(modules_, kMaxNumberOfModuleContexts);
+ CHECK_GT(n_modules_, 0);
+ CHECK_LT(n_modules_, kMaxNumberOfModuleContexts);
+ }
+ for (uptr i = 0; i < n_modules_; i++) {
+ if (modules_[i].containsAddress(address)) {
+ return &modules_[i];
+ }
+ }
+ return 0;
+ }
+ static const uptr kMaxNumberOfModuleContexts = 4096;
+ // Array of module debug info contexts is leaked.
+ ModuleDIContext *modules_;
+ uptr n_modules_;
+};
+
+static Symbolizer symbolizer; // Linker initialized.
+
+uptr SymbolizeCode(uptr address, AddressInfo *frames, uptr max_frames) {
+ return symbolizer.SymbolizeCode(address, frames, max_frames);
+}
+
+} // namespace __sanitizer
diff --git a/lib/sanitizer_common/sanitizer_symbolizer.h b/lib/sanitizer_common/sanitizer_symbolizer.h
new file mode 100644
index 0000000..c813e80
--- /dev/null
+++ b/lib/sanitizer_common/sanitizer_symbolizer.h
@@ -0,0 +1,100 @@
+//===-- sanitizer_symbolizer.h ----------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Symbolizer is intended to be used by both
+// AddressSanitizer and ThreadSanitizer to symbolize a given
+// address. It is an analogue of addr2line utility and allows to map
+// instruction address to a location in source code at run-time.
+//
+// Symbolizer is planned to use debug information (in DWARF format)
+// in a binary via interface defined in "llvm/DebugInfo/DIContext.h"
+//
+// Symbolizer code should be called from the run-time library of
+// dynamic tools, and generally should not call memory allocation
+// routines or other system library functions intercepted by those tools.
+// Instead, Symbolizer code should use their replacements, defined in
+// "compiler-rt/lib/sanitizer_common/sanitizer_libc.h".
+//===----------------------------------------------------------------------===//
+#ifndef SANITIZER_SYMBOLIZER_H
+#define SANITIZER_SYMBOLIZER_H
+
+#include "sanitizer_internal_defs.h"
+#include "sanitizer_libc.h"
+// WARNING: Do not include system headers here. See details above.
+
+namespace __sanitizer {
+
+struct AddressInfo {
+ uptr address;
+ char *module;
+ uptr module_offset;
+ char *function;
+ char *file;
+ int line;
+ int column;
+
+ AddressInfo() {
+ internal_memset(this, 0, sizeof(AddressInfo));
+ }
+ // Deletes all strings and sets all fields to zero.
+ void Clear();
+};
+
+// Fills at most "max_frames" elements of "frames" with descriptions
+// for a given address (in all inlined functions). Returns the number
+// of descriptions actually filled.
+// This function should NOT be called from two threads simultaneously.
+uptr SymbolizeCode(uptr address, AddressInfo *frames, uptr max_frames);
+
+// Debug info routines
+struct DWARFSection {
+ const char *data;
+ uptr size;
+ DWARFSection() {
+ data = 0;
+ size = 0;
+ }
+};
+// Returns true on success.
+bool FindDWARFSection(uptr object_file_addr, const char *section_name,
+ DWARFSection *section);
+bool IsFullNameOfDWARFSection(const char *full_name, const char *short_name);
+
+class ModuleDIContext {
+ public:
+ ModuleDIContext(const char *module_name, uptr base_address);
+ void addAddressRange(uptr beg, uptr end);
+ bool containsAddress(uptr address) const;
+ void getAddressInfo(AddressInfo *info);
+
+ const char *full_name() const { return full_name_; }
+
+ private:
+ void CreateDIContext();
+
+ struct AddressRange {
+ uptr beg;
+ uptr end;
+ };
+ char *full_name_;
+ char *short_name_;
+ uptr base_address_;
+ static const uptr kMaxNumberOfAddressRanges = 8;
+ AddressRange ranges_[kMaxNumberOfAddressRanges];
+ uptr n_ranges_;
+ uptr mapped_addr_;
+ uptr mapped_size_;
+};
+
+// OS-dependent function that gets the linked list of all loaded modules.
+uptr GetListOfModules(ModuleDIContext *modules, uptr max_modules);
+
+} // namespace __sanitizer
+
+#endif // SANITIZER_SYMBOLIZER_H
diff --git a/lib/sanitizer_common/sanitizer_win.cc b/lib/sanitizer_common/sanitizer_win.cc
new file mode 100644
index 0000000..c68a1fe
--- /dev/null
+++ b/lib/sanitizer_common/sanitizer_win.cc
@@ -0,0 +1,200 @@
+//===-- sanitizer_win.cc --------------------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is shared between AddressSanitizer and ThreadSanitizer
+// run-time libraries and implements windows-specific functions from
+// sanitizer_libc.h.
+//===----------------------------------------------------------------------===//
+#ifdef _WIN32
+#include <windows.h>
+
+#include "sanitizer_common.h"
+#include "sanitizer_libc.h"
+#include "sanitizer_symbolizer.h"
+
+namespace __sanitizer {
+
+// --------------------- sanitizer_common.h
+int GetPid() {
+ return GetProcessId(GetCurrentProcess());
+}
+
+uptr GetThreadSelf() {
+ return GetCurrentThreadId();
+}
+
+void GetThreadStackTopAndBottom(bool at_initialization, uptr *stack_top,
+ uptr *stack_bottom) {
+ CHECK(stack_top);
+ CHECK(stack_bottom);
+ MEMORY_BASIC_INFORMATION mbi;
+ CHECK_NE(VirtualQuery(&mbi /* on stack */, &mbi, sizeof(mbi)), 0);
+ // FIXME: is it possible for the stack to not be a single allocation?
+ // Are these values what ASan expects to get (reserved, not committed;
+ // including stack guard page) ?
+ *stack_top = (uptr)mbi.BaseAddress + mbi.RegionSize;
+ *stack_bottom = (uptr)mbi.AllocationBase;
+}
+
+
+void *MmapOrDie(uptr size, const char *mem_type) {
+ void *rv = VirtualAlloc(0, size, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
+ if (rv == 0) {
+ Report("ERROR: Failed to allocate 0x%zx (%zd) bytes of %s\n",
+ size, size, mem_type);
+ CHECK("unable to mmap" && 0);
+ }
+ return rv;
+}
+
+void UnmapOrDie(void *addr, uptr size) {
+ if (VirtualFree(addr, size, MEM_DECOMMIT) == 0) {
+ Report("ERROR: Failed to deallocate 0x%zx (%zd) bytes at address %p\n",
+ size, size, addr);
+ CHECK("unable to unmap" && 0);
+ }
+}
+
+void *MmapFixedNoReserve(uptr fixed_addr, uptr size) {
+ return VirtualAlloc((LPVOID)fixed_addr, size,
+ MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
+}
+
+void *Mprotect(uptr fixed_addr, uptr size) {
+ return VirtualAlloc((LPVOID)fixed_addr, size,
+ MEM_RESERVE | MEM_COMMIT, PAGE_NOACCESS);
+}
+
+bool MemoryRangeIsAvailable(uptr range_start, uptr range_end) {
+ // FIXME: shall we do anything here on Windows?
+ return true;
+}
+
+void *MapFileToMemory(const char *file_name, uptr *buff_size) {
+ UNIMPLEMENTED();
+}
+
+const char *GetEnv(const char *name) {
+ static char env_buffer[32767] = {};
+
+ // Note: this implementation stores the result in a static buffer so we only
+ // allow it to be called just once.
+ static bool called_once = false;
+ if (called_once)
+ UNIMPLEMENTED();
+ called_once = true;
+
+ DWORD rv = GetEnvironmentVariableA(name, env_buffer, sizeof(env_buffer));
+ if (rv > 0 && rv < sizeof(env_buffer))
+ return env_buffer;
+ return 0;
+}
+
+const char *GetPwd() {
+ UNIMPLEMENTED();
+ return 0;
+}
+
+void DumpProcessMap() {
+ UNIMPLEMENTED();
+}
+
+void DisableCoreDumper() {
+ UNIMPLEMENTED();
+}
+
+void SleepForSeconds(int seconds) {
+ Sleep(seconds * 1000);
+}
+
+void SleepForMillis(int millis) {
+ Sleep(millis);
+}
+
+void Exit(int exitcode) {
+ _exit(exitcode);
+}
+
+void Abort() {
+ abort();
+ _exit(-1); // abort is not NORETURN on Windows.
+}
+
+int Atexit(void (*function)(void)) {
+ return atexit(function);
+}
+
+// ------------------ sanitizer_symbolizer.h
+bool FindDWARFSection(uptr object_file_addr, const char *section_name,
+ DWARFSection *section) {
+ UNIMPLEMENTED();
+ return false;
+}
+
+uptr GetListOfModules(ModuleDIContext *modules, uptr max_modules) {
+ UNIMPLEMENTED();
+};
+
+// ------------------ sanitizer_libc.h
+void *internal_mmap(void *addr, uptr length, int prot, int flags,
+ int fd, u64 offset) {
+ UNIMPLEMENTED();
+ return 0;
+}
+
+int internal_munmap(void *addr, uptr length) {
+ UNIMPLEMENTED();
+ return 0;
+}
+
+int internal_close(fd_t fd) {
+ UNIMPLEMENTED();
+ return 0;
+}
+
+fd_t internal_open(const char *filename, bool write) {
+ UNIMPLEMENTED();
+ return 0;
+}
+
+uptr internal_read(fd_t fd, void *buf, uptr count) {
+ UNIMPLEMENTED();
+ return 0;
+}
+
+uptr internal_write(fd_t fd, const void *buf, uptr count) {
+ if (fd != 2)
+ UNIMPLEMENTED();
+ HANDLE err = GetStdHandle(STD_ERROR_HANDLE);
+ if (err == 0)
+ return 0; // FIXME: this might not work on some apps.
+ DWORD ret;
+ if (!WriteFile(err, buf, count, &ret, 0))
+ return 0;
+ return ret;
+}
+
+uptr internal_filesize(fd_t fd) {
+ UNIMPLEMENTED();
+ return 0;
+}
+
+int internal_dup2(int oldfd, int newfd) {
+ UNIMPLEMENTED();
+ return 0;
+}
+
+int internal_sched_yield() {
+ UNIMPLEMENTED();
+ return 0;
+}
+
+} // namespace __sanitizer
+
+#endif // _WIN32
diff --git a/lib/sanitizer_common/tests/sanitizer_allocator64_test.cc b/lib/sanitizer_common/tests/sanitizer_allocator64_test.cc
new file mode 100644
index 0000000..1410f26
--- /dev/null
+++ b/lib/sanitizer_common/tests/sanitizer_allocator64_test.cc
@@ -0,0 +1,257 @@
+//===-- sanitizer_allocator64_test.cc -------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+// Tests for sanitizer_allocator64.h.
+//===----------------------------------------------------------------------===//
+#include "sanitizer_common/sanitizer_allocator64.h"
+#include "gtest/gtest.h"
+
+#include <algorithm>
+#include <vector>
+
+static const uptr kAllocatorSpace = 0x600000000000ULL;
+static const uptr kAllocatorSize = 0x10000000000; // 1T.
+
+typedef DefaultSizeClassMap SCMap;
+typedef
+ SizeClassAllocator64<kAllocatorSpace, kAllocatorSize, 16, SCMap> Allocator;
+typedef SizeClassAllocatorLocalCache<Allocator::kNumClasses, Allocator>
+ AllocatorCache;
+
+TEST(SanitizerCommon, DefaultSizeClassMap) {
+#if 0
+ for (uptr i = 0; i < SCMap::kNumClasses; i++) {
+ // printf("% 3ld: % 5ld (%4lx); ", i, SCMap::Size(i), SCMap::Size(i));
+ printf("c%ld => %ld ", i, SCMap::Size(i));
+ if ((i % 8) == 7)
+ printf("\n");
+ }
+ printf("\n");
+#endif
+
+ for (uptr c = 0; c < SCMap::kNumClasses; c++) {
+ uptr s = SCMap::Size(c);
+ CHECK_EQ(SCMap::ClassID(s), c);
+ if (c != SCMap::kNumClasses - 1)
+ CHECK_EQ(SCMap::ClassID(s + 1), c + 1);
+ CHECK_EQ(SCMap::ClassID(s - 1), c);
+ if (c)
+ CHECK_GT(SCMap::Size(c), SCMap::Size(c-1));
+ }
+ CHECK_EQ(SCMap::ClassID(SCMap::kMaxSize + 1), 0);
+
+ for (uptr s = 1; s <= SCMap::kMaxSize; s++) {
+ uptr c = SCMap::ClassID(s);
+ CHECK_LT(c, SCMap::kNumClasses);
+ CHECK_GE(SCMap::Size(c), s);
+ if (c > 0)
+ CHECK_LT(SCMap::Size(c-1), s);
+ }
+}
+
+TEST(SanitizerCommon, SizeClassAllocator64) {
+ Allocator a;
+ a.Init();
+
+ static const uptr sizes[] = {1, 16, 30, 40, 100, 1000, 10000,
+ 50000, 60000, 100000, 300000, 500000, 1000000, 2000000};
+
+ std::vector<void *> allocated;
+
+ uptr last_total_allocated = 0;
+ for (int i = 0; i < 5; i++) {
+ // Allocate a bunch of chunks.
+ for (uptr s = 0; s < sizeof(sizes) /sizeof(sizes[0]); s++) {
+ uptr size = sizes[s];
+ // printf("s = %ld\n", size);
+ uptr n_iter = std::max((uptr)2, 1000000 / size);
+ for (uptr i = 0; i < n_iter; i++) {
+ void *x = a.Allocate(size, 1);
+ allocated.push_back(x);
+ CHECK(a.PointerIsMine(x));
+ CHECK_GE(a.GetActuallyAllocatedSize(x), size);
+ uptr class_id = a.GetSizeClass(x);
+ CHECK_EQ(class_id, SCMap::ClassID(size));
+ uptr *metadata = reinterpret_cast<uptr*>(a.GetMetaData(x));
+ metadata[0] = reinterpret_cast<uptr>(x) + 1;
+ metadata[1] = 0xABCD;
+ }
+ }
+ // Deallocate all.
+ for (uptr i = 0; i < allocated.size(); i++) {
+ void *x = allocated[i];
+ uptr *metadata = reinterpret_cast<uptr*>(a.GetMetaData(x));
+ CHECK_EQ(metadata[0], reinterpret_cast<uptr>(x) + 1);
+ CHECK_EQ(metadata[1], 0xABCD);
+ a.Deallocate(x);
+ }
+ allocated.clear();
+ uptr total_allocated = a.TotalMemoryUsed();
+ if (last_total_allocated == 0)
+ last_total_allocated = total_allocated;
+ CHECK_EQ(last_total_allocated, total_allocated);
+ }
+
+ a.TestOnlyUnmap();
+}
+
+
+TEST(SanitizerCommon, SizeClassAllocator64MetadataStress) {
+ Allocator a;
+ a.Init();
+ static volatile void *sink;
+
+ const uptr kNumAllocs = 10000;
+ void *allocated[kNumAllocs];
+ for (uptr i = 0; i < kNumAllocs; i++) {
+ uptr size = (i % 4096) + 1;
+ void *x = a.Allocate(size, 1);
+ allocated[i] = x;
+ }
+ // Get Metadata kNumAllocs^2 times.
+ for (uptr i = 0; i < kNumAllocs * kNumAllocs; i++) {
+ sink = a.GetMetaData(allocated[i % kNumAllocs]);
+ }
+ for (uptr i = 0; i < kNumAllocs; i++) {
+ a.Deallocate(allocated[i]);
+ }
+
+ a.TestOnlyUnmap();
+ (void)sink;
+}
+
+void FailInAssertionOnOOM() {
+ Allocator a;
+ a.Init();
+ const uptr size = 1 << 20;
+ for (int i = 0; i < 1000000; i++) {
+ a.Allocate(size, 1);
+ }
+
+ a.TestOnlyUnmap();
+}
+
+TEST(SanitizerCommon, SizeClassAllocator64Overflow) {
+ EXPECT_DEATH(FailInAssertionOnOOM(),
+ "allocated_user.*allocated_meta.*kRegionSize");
+}
+
+TEST(SanitizerCommon, LargeMmapAllocator) {
+ LargeMmapAllocator a;
+ a.Init();
+
+ static const int kNumAllocs = 100;
+ void *allocated[kNumAllocs];
+ static const uptr size = 1000;
+ // Allocate some.
+ for (int i = 0; i < kNumAllocs; i++) {
+ allocated[i] = a.Allocate(size, 1);
+ }
+ // Deallocate all.
+ CHECK_GT(a.TotalMemoryUsed(), size * kNumAllocs);
+ for (int i = 0; i < kNumAllocs; i++) {
+ void *p = allocated[i];
+ CHECK(a.PointerIsMine(p));
+ a.Deallocate(p);
+ }
+ // Check that non left.
+ CHECK_EQ(a.TotalMemoryUsed(), 0);
+
+ // Allocate some more, also add metadata.
+ for (int i = 0; i < kNumAllocs; i++) {
+ void *x = a.Allocate(size, 1);
+ CHECK_GE(a.GetActuallyAllocatedSize(x), size);
+ uptr *meta = reinterpret_cast<uptr*>(a.GetMetaData(x));
+ *meta = i;
+ allocated[i] = x;
+ }
+ CHECK_GT(a.TotalMemoryUsed(), size * kNumAllocs);
+ // Deallocate all in reverse order.
+ for (int i = 0; i < kNumAllocs; i++) {
+ int idx = kNumAllocs - i - 1;
+ void *p = allocated[idx];
+ uptr *meta = reinterpret_cast<uptr*>(a.GetMetaData(p));
+ CHECK_EQ(*meta, idx);
+ CHECK(a.PointerIsMine(p));
+ a.Deallocate(p);
+ }
+ CHECK_EQ(a.TotalMemoryUsed(), 0);
+}
+
+TEST(SanitizerCommon, CombinedAllocator) {
+ typedef Allocator PrimaryAllocator;
+ typedef LargeMmapAllocator SecondaryAllocator;
+ typedef CombinedAllocator<PrimaryAllocator, AllocatorCache,
+ SecondaryAllocator> Allocator;
+
+ AllocatorCache cache;
+ Allocator a;
+ a.Init();
+ cache.Init();
+ const uptr kNumAllocs = 100000;
+ const uptr kNumIter = 10;
+ for (uptr iter = 0; iter < kNumIter; iter++) {
+ std::vector<void*> allocated;
+ for (uptr i = 0; i < kNumAllocs; i++) {
+ uptr size = (i % (1 << 14)) + 1;
+ if ((i % 1024) == 0)
+ size = 1 << (10 + (i % 14));
+ void *x = a.Allocate(&cache, size, 1);
+ uptr *meta = reinterpret_cast<uptr*>(a.GetMetaData(x));
+ CHECK_EQ(*meta, 0);
+ *meta = size;
+ allocated.push_back(x);
+ }
+
+ random_shuffle(allocated.begin(), allocated.end());
+
+ for (uptr i = 0; i < kNumAllocs; i++) {
+ void *x = allocated[i];
+ uptr *meta = reinterpret_cast<uptr*>(a.GetMetaData(x));
+ CHECK_NE(*meta, 0);
+ CHECK(a.PointerIsMine(x));
+ *meta = 0;
+ a.Deallocate(&cache, x);
+ }
+ allocated.clear();
+ a.SwallowCache(&cache);
+ }
+ a.TestOnlyUnmap();
+}
+
+static THREADLOCAL AllocatorCache static_allocator_cache;
+
+TEST(SanitizerCommon, SizeClassAllocatorLocalCache) {
+ static_allocator_cache.Init();
+
+ Allocator a;
+ AllocatorCache cache;
+
+ a.Init();
+ cache.Init();
+
+ const uptr kNumAllocs = 10000;
+ const int kNumIter = 100;
+ uptr saved_total = 0;
+ for (int i = 0; i < kNumIter; i++) {
+ void *allocated[kNumAllocs];
+ for (uptr i = 0; i < kNumAllocs; i++) {
+ allocated[i] = cache.Allocate(&a, 0);
+ }
+ for (uptr i = 0; i < kNumAllocs; i++) {
+ cache.Deallocate(&a, 0, allocated[i]);
+ }
+ cache.Drain(&a);
+ uptr total_allocated = a.TotalMemoryUsed();
+ if (saved_total)
+ CHECK_EQ(saved_total, total_allocated);
+ saved_total = total_allocated;
+ }
+
+ a.TestOnlyUnmap();
+}
diff --git a/lib/sanitizer_common/tests/sanitizer_allocator64_testlib.cc b/lib/sanitizer_common/tests/sanitizer_allocator64_testlib.cc
new file mode 100644
index 0000000..cff7823
--- /dev/null
+++ b/lib/sanitizer_common/tests/sanitizer_allocator64_testlib.cc
@@ -0,0 +1,99 @@
+//===-- sanitizer_allocator64_testlib.cc ----------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+// Malloc replacement library based on CombinedAllocator.
+// The primary purpose of this file is an end-to-end integration test
+// for CombinedAllocator.
+//===----------------------------------------------------------------------===//
+#include "sanitizer_common/sanitizer_allocator64.h"
+#include <stddef.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <assert.h>
+
+namespace {
+static const uptr kAllocatorSpace = 0x600000000000ULL;
+static const uptr kAllocatorSize = 0x10000000000; // 1T.
+
+typedef SizeClassAllocator64<kAllocatorSpace, kAllocatorSize, 16,
+ DefaultSizeClassMap> PrimaryAllocator;
+typedef SizeClassAllocatorLocalCache<PrimaryAllocator::kNumClasses,
+ PrimaryAllocator> AllocatorCache;
+typedef LargeMmapAllocator SecondaryAllocator;
+typedef CombinedAllocator<PrimaryAllocator, AllocatorCache,
+ SecondaryAllocator> Allocator;
+
+static THREADLOCAL AllocatorCache cache;
+static Allocator allocator;
+
+static int inited = 0;
+
+__attribute__((constructor))
+void Init() {
+ if (inited) return;
+ inited = true; // this must happen before any threads are created.
+ allocator.Init();
+}
+
+} // namespace
+
+namespace __sanitizer {
+void NORETURN Die() {
+ _exit(77);
+}
+void NORETURN CheckFailed(const char *file, int line, const char *cond,
+ u64 v1, u64 v2) {
+ fprintf(stderr, "CheckFailed: %s:%d %s (%lld %lld)\n",
+ file, line, cond, v1, v2);
+ Die();
+}
+}
+
+#if 1
+extern "C" {
+void *malloc(size_t size) {
+ Init();
+ assert(inited);
+ return allocator.Allocate(&cache, size, 8);
+}
+
+void free(void *p) {
+ assert(inited);
+ allocator.Deallocate(&cache, p);
+}
+
+void *calloc(size_t nmemb, size_t size) {
+ assert(inited);
+ return allocator.Allocate(&cache, nmemb * size, 8, /*cleared=*/true);
+}
+
+void *realloc(void *p, size_t new_size) {
+ assert(inited);
+ return allocator.Reallocate(&cache, p, new_size, 8);
+}
+
+void *memalign() { assert(0); }
+
+int posix_memalign(void **memptr, size_t alignment, size_t size) {
+ *memptr = allocator.Allocate(&cache, size, alignment);
+ CHECK_EQ(((uptr)*memptr & (alignment - 1)), 0);
+ return 0;
+}
+
+void *valloc(size_t size) {
+ assert(inited);
+ return allocator.Allocate(&cache, size, kPageSize);
+}
+
+void *pvalloc(size_t size) {
+ assert(inited);
+ if (size == 0) size = kPageSize;
+ return allocator.Allocate(&cache, size, kPageSize);
+}
+}
+#endif
diff --git a/lib/sanitizer_common/tests/sanitizer_allocator_test.cc b/lib/sanitizer_common/tests/sanitizer_allocator_test.cc
new file mode 100644
index 0000000..d6c7f56
--- /dev/null
+++ b/lib/sanitizer_common/tests/sanitizer_allocator_test.cc
@@ -0,0 +1,56 @@
+//===-- sanitizer_allocator_test.cc ---------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of ThreadSanitizer/AddressSanitizer runtime.
+//
+//===----------------------------------------------------------------------===//
+#include "sanitizer_common/sanitizer_common.h"
+#include "gtest/gtest.h"
+#include <stdlib.h>
+
+namespace __sanitizer {
+
+TEST(Allocator, Basic) {
+ char *p = (char*)InternalAlloc(10);
+ EXPECT_NE(p, (char*)0);
+ char *p2 = (char*)InternalAlloc(20);
+ EXPECT_NE(p2, (char*)0);
+ EXPECT_NE(p2, p);
+ for (int i = 0; i < 10; i++) {
+ p[i] = 42;
+ EXPECT_EQ(p, InternalAllocBlock(p + i));
+ }
+ for (int i = 0; i < 20; i++) {
+ ((char*)p2)[i] = 42;
+ EXPECT_EQ(p2, InternalAllocBlock(p2 + i));
+ }
+ InternalFree(p);
+ InternalFree(p2);
+}
+
+TEST(Allocator, Stress) {
+ const int kCount = 1000;
+ char *ptrs[kCount];
+ unsigned rnd = 42;
+ for (int i = 0; i < kCount; i++) {
+ uptr sz = rand_r(&rnd) % 1000;
+ char *p = (char*)InternalAlloc(sz);
+ EXPECT_NE(p, (char*)0);
+ for (uptr j = 0; j < sz; j++) {
+ p[j] = 42;
+ EXPECT_EQ(p, InternalAllocBlock(p + j));
+ }
+ ptrs[i] = p;
+ }
+ for (int i = 0; i < kCount; i++) {
+ InternalFree(ptrs[i]);
+ }
+}
+
+} // namespace __sanitizer
diff --git a/lib/sanitizer_common/tests/sanitizer_common_test.cc b/lib/sanitizer_common/tests/sanitizer_common_test.cc
new file mode 100644
index 0000000..91570dc
--- /dev/null
+++ b/lib/sanitizer_common/tests/sanitizer_common_test.cc
@@ -0,0 +1,66 @@
+//===-- sanitizer_common_test.cc ------------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of ThreadSanitizer/AddressSanitizer runtime.
+//
+//===----------------------------------------------------------------------===//
+#include "sanitizer_common/sanitizer_common.h"
+#include "gtest/gtest.h"
+
+namespace __sanitizer {
+
+static bool IsSorted(const uptr *array, uptr n) {
+ for (uptr i = 1; i < n; i++) {
+ if (array[i] < array[i - 1]) return false;
+ }
+ return true;
+}
+
+TEST(SanitizerCommon, SortTest) {
+ uptr array[100];
+ uptr n = 100;
+ // Already sorted.
+ for (uptr i = 0; i < n; i++) {
+ array[i] = i;
+ }
+ SortArray(array, n);
+ EXPECT_TRUE(IsSorted(array, n));
+ // Reverse order.
+ for (uptr i = 0; i < n; i++) {
+ array[i] = n - 1 - i;
+ }
+ SortArray(array, n);
+ EXPECT_TRUE(IsSorted(array, n));
+ // Mixed order.
+ for (uptr i = 0; i < n; i++) {
+ array[i] = (i % 2 == 0) ? i : n - 1 - i;
+ }
+ SortArray(array, n);
+ EXPECT_TRUE(IsSorted(array, n));
+ // All equal.
+ for (uptr i = 0; i < n; i++) {
+ array[i] = 42;
+ }
+ SortArray(array, n);
+ EXPECT_TRUE(IsSorted(array, n));
+ // All but one sorted.
+ for (uptr i = 0; i < n - 1; i++) {
+ array[i] = i;
+ }
+ array[n - 1] = 42;
+ SortArray(array, n);
+ EXPECT_TRUE(IsSorted(array, n));
+ // Minimal case - sort three elements.
+ array[0] = 1;
+ array[1] = 0;
+ SortArray(array, 2);
+ EXPECT_TRUE(IsSorted(array, 2));
+}
+
+} // namespace sanitizer
diff --git a/lib/sanitizer_common/tests/sanitizer_flags_test.cc b/lib/sanitizer_common/tests/sanitizer_flags_test.cc
new file mode 100644
index 0000000..4b273e5
--- /dev/null
+++ b/lib/sanitizer_common/tests/sanitizer_flags_test.cc
@@ -0,0 +1,72 @@
+//===-- sanitizer_flags_test.cc -------------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of ThreadSanitizer/AddressSanitizer runtime.
+//
+//===----------------------------------------------------------------------===//
+#include "sanitizer_common/sanitizer_common.h"
+#include "sanitizer_common/sanitizer_flags.h"
+#include "gtest/gtest.h"
+
+#include "tsan_rtl.h" // FIXME: break dependency from TSan runtime.
+using __tsan::ScopedInRtl;
+
+#include <string.h>
+
+namespace __sanitizer {
+
+static const char kFlagName[] = "flag_name";
+
+template <typename T>
+static void TestFlag(T start_value, const char *env, T final_value) {
+ T flag = start_value;
+ ParseFlag(env, &flag, kFlagName);
+ EXPECT_EQ(final_value, flag);
+}
+
+static void TestStrFlag(const char *start_value, const char *env,
+ const char *final_value) {
+ const char *flag = start_value;
+ ParseFlag(env, &flag, kFlagName);
+ EXPECT_STREQ(final_value, flag);
+}
+
+TEST(SanitizerCommon, BooleanFlags) {
+ ScopedInRtl in_rtl;
+ TestFlag(true, "--flag_name", true);
+ TestFlag(false, "flag_name", false);
+ TestFlag(false, "--flag_name=1", true);
+ TestFlag(true, "asdas flag_name=0 asdas", false);
+ TestFlag(true, " --flag_name=0 ", false);
+ TestFlag(false, "flag_name=yes", true);
+ TestFlag(false, "flag_name=true", true);
+ TestFlag(true, "flag_name=no", false);
+ TestFlag(true, "flag_name=false", false);
+}
+
+TEST(SanitizerCommon, IntFlags) {
+ ScopedInRtl in_rtl;
+ TestFlag(-11, 0, -11);
+ TestFlag(-11, "flag_name", 0);
+ TestFlag(-11, "--flag_name=", 0);
+ TestFlag(-11, "--flag_name=42", 42);
+ TestFlag(-11, "--flag_name=-42", -42);
+}
+
+TEST(SanitizerCommon, StrFlags) {
+ ScopedInRtl in_rtl;
+ TestStrFlag("zzz", 0, "zzz");
+ TestStrFlag("zzz", "flag_name", "");
+ TestStrFlag("zzz", "--flag_name=", "");
+ TestStrFlag("", "--flag_name=abc", "abc");
+ TestStrFlag("", "--flag_name='abc zxc'", "abc zxc");
+ TestStrFlag("", "--flag_name=\"abc qwe\" asd", "abc qwe");
+}
+
+} // namespace __sanitizer
diff --git a/lib/sanitizer_common/tests/sanitizer_list_test.cc b/lib/sanitizer_common/tests/sanitizer_list_test.cc
new file mode 100644
index 0000000..d328fbf
--- /dev/null
+++ b/lib/sanitizer_common/tests/sanitizer_list_test.cc
@@ -0,0 +1,157 @@
+//===-- sanitizer_list_test.cc --------------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of ThreadSanitizer/AddressSanitizer runtime.
+//
+//===----------------------------------------------------------------------===//
+#include "sanitizer_common/sanitizer_list.h"
+#include "gtest/gtest.h"
+
+namespace __sanitizer {
+
+struct ListItem {
+ ListItem *next;
+};
+
+typedef IntrusiveList<ListItem> List;
+
+// Check that IntrusiveList can be made thread-local.
+static THREADLOCAL List static_list;
+
+static void SetList(List *l, ListItem *x = 0,
+ ListItem *y = 0, ListItem *z = 0) {
+ l->clear();
+ if (x) l->push_back(x);
+ if (y) l->push_back(y);
+ if (z) l->push_back(z);
+}
+
+static void CheckList(List *l, ListItem *i1, ListItem *i2 = 0, ListItem *i3 = 0,
+ ListItem *i4 = 0, ListItem *i5 = 0, ListItem *i6 = 0) {
+ if (i1) {
+ CHECK_EQ(l->front(), i1);
+ l->pop_front();
+ }
+ if (i2) {
+ CHECK_EQ(l->front(), i2);
+ l->pop_front();
+ }
+ if (i3) {
+ CHECK_EQ(l->front(), i3);
+ l->pop_front();
+ }
+ if (i4) {
+ CHECK_EQ(l->front(), i4);
+ l->pop_front();
+ }
+ if (i5) {
+ CHECK_EQ(l->front(), i5);
+ l->pop_front();
+ }
+ if (i6) {
+ CHECK_EQ(l->front(), i6);
+ l->pop_front();
+ }
+ CHECK(l->empty());
+}
+
+TEST(SanitizerCommon, IntrusiveList) {
+ ListItem items[6];
+ CHECK_EQ(static_list.size(), 0);
+
+ List l;
+ l.clear();
+
+ ListItem *x = &items[0];
+ ListItem *y = &items[1];
+ ListItem *z = &items[2];
+ ListItem *a = &items[3];
+ ListItem *b = &items[4];
+ ListItem *c = &items[5];
+
+ CHECK_EQ(l.size(), 0);
+ l.push_back(x);
+ CHECK_EQ(l.size(), 1);
+ CHECK_EQ(l.back(), x);
+ CHECK_EQ(l.front(), x);
+ l.pop_front();
+ CHECK(l.empty());
+ l.CheckConsistency();
+
+ l.push_front(x);
+ CHECK_EQ(l.size(), 1);
+ CHECK_EQ(l.back(), x);
+ CHECK_EQ(l.front(), x);
+ l.pop_front();
+ CHECK(l.empty());
+ l.CheckConsistency();
+
+ l.push_front(x);
+ l.push_front(y);
+ l.push_front(z);
+ CHECK_EQ(l.size(), 3);
+ CHECK_EQ(l.front(), z);
+ CHECK_EQ(l.back(), x);
+ l.CheckConsistency();
+
+ l.pop_front();
+ CHECK_EQ(l.size(), 2);
+ CHECK_EQ(l.front(), y);
+ CHECK_EQ(l.back(), x);
+ l.pop_front();
+ l.pop_front();
+ CHECK(l.empty());
+ l.CheckConsistency();
+
+ l.push_back(x);
+ l.push_back(y);
+ l.push_back(z);
+ CHECK_EQ(l.size(), 3);
+ CHECK_EQ(l.front(), x);
+ CHECK_EQ(l.back(), z);
+ l.CheckConsistency();
+
+ l.pop_front();
+ CHECK_EQ(l.size(), 2);
+ CHECK_EQ(l.front(), y);
+ CHECK_EQ(l.back(), z);
+ l.pop_front();
+ l.pop_front();
+ CHECK(l.empty());
+ l.CheckConsistency();
+
+ List l1, l2;
+ l1.clear();
+ l2.clear();
+
+ l1.append_front(&l2);
+ CHECK(l1.empty());
+ CHECK(l2.empty());
+
+ l1.append_back(&l2);
+ CHECK(l1.empty());
+ CHECK(l2.empty());
+
+ SetList(&l1, x);
+ CheckList(&l1, x);
+
+ SetList(&l1, x, y, z);
+ SetList(&l2, a, b, c);
+ l1.append_back(&l2);
+ CheckList(&l1, x, y, z, a, b, c);
+ CHECK(l2.empty());
+
+ SetList(&l1, x, y);
+ SetList(&l2);
+ l1.append_front(&l2);
+ CheckList(&l1, x, y);
+ CHECK(l2.empty());
+}
+
+} // namespace __sanitizer
OpenPOWER on IntegriCloud