diff options
Diffstat (limited to 'contrib/compiler-rt/lib/sanitizer_common/sanitizer_common.h')
-rw-r--r-- | contrib/compiler-rt/lib/sanitizer_common/sanitizer_common.h | 622 |
1 files changed, 622 insertions, 0 deletions
diff --git a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_common.h b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_common.h new file mode 100644 index 000000000000..ff13ef164045 --- /dev/null +++ b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_common.h @@ -0,0 +1,622 @@ +//===-- 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 run-time libraries of sanitizers. +// +// 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_flags.h" +#include "sanitizer_interface_internal.h" +#include "sanitizer_internal_defs.h" +#include "sanitizer_libc.h" +#include "sanitizer_list.h" +#include "sanitizer_mutex.h" + +namespace __sanitizer { +struct StackTrace; + +// Constants. +const uptr kWordSize = SANITIZER_WORDSIZE / 8; +const uptr kWordSizeInBits = 8 * kWordSize; + +#if defined(__powerpc__) || defined(__powerpc64__) + const uptr kCacheLineSize = 128; +#else + const uptr kCacheLineSize = 64; +#endif + +const uptr kMaxPathLength = 4096; + +const uptr kMaxThreadStackSize = 1 << 30; // 1Gb + +extern const char *SanitizerToolName; // Can be changed by the tool. + +extern atomic_uint32_t current_verbosity; +INLINE void SetVerbosity(int verbosity) { + atomic_store(¤t_verbosity, verbosity, memory_order_relaxed); +} +INLINE int Verbosity() { + return atomic_load(¤t_verbosity, memory_order_relaxed); +} + +uptr GetPageSize(); +uptr GetPageSizeCached(); +uptr GetMmapGranularity(); +uptr GetMaxVirtualAddress(); +// Threads +uptr GetTid(); +uptr GetThreadSelf(); +void GetThreadStackTopAndBottom(bool at_initialization, uptr *stack_top, + uptr *stack_bottom); +void GetThreadStackAndTls(bool main, uptr *stk_addr, uptr *stk_size, + uptr *tls_addr, uptr *tls_size); + +// Memory management +void *MmapOrDie(uptr size, const char *mem_type); +void UnmapOrDie(void *addr, uptr size); +void *MmapFixedNoReserve(uptr fixed_addr, uptr size); +void *MmapNoReserveOrDie(uptr size, const char *mem_type); +void *MmapFixedOrDie(uptr fixed_addr, uptr size); +void *Mprotect(uptr fixed_addr, uptr size); +// Map aligned chunk of address space; size and alignment are powers of two. +void *MmapAlignedOrDie(uptr size, uptr alignment, const char *mem_type); +// Used to check if we can map shadow memory to a fixed location. +bool MemoryRangeIsAvailable(uptr range_start, uptr range_end); +void FlushUnneededShadowMemory(uptr addr, uptr size); +void IncreaseTotalMmap(uptr size); +void DecreaseTotalMmap(uptr size); +uptr GetRSS(); +void NoHugePagesInRegion(uptr addr, uptr length); +void DontDumpShadowMemory(uptr addr, uptr length); + +// InternalScopedBuffer can be used instead of large stack arrays to +// keep frame size low. +// FIXME: use InternalAlloc instead of MmapOrDie once +// InternalAlloc is made libc-free. +template<typename T> +class InternalScopedBuffer { + public: + explicit InternalScopedBuffer(uptr cnt) { + cnt_ = cnt; + ptr_ = (T*)MmapOrDie(cnt * sizeof(T), "InternalScopedBuffer"); + } + ~InternalScopedBuffer() { + UnmapOrDie(ptr_, cnt_ * sizeof(T)); + } + T &operator[](uptr i) { return ptr_[i]; } + T *data() { return ptr_; } + uptr size() { return cnt_ * sizeof(T); } + + private: + T *ptr_; + uptr cnt_; + // Disallow evil constructors. + InternalScopedBuffer(const InternalScopedBuffer&); + void operator=(const InternalScopedBuffer&); +}; + +class InternalScopedString : public InternalScopedBuffer<char> { + public: + explicit InternalScopedString(uptr max_length) + : InternalScopedBuffer<char>(max_length), length_(0) { + (*this)[0] = '\0'; + } + uptr length() { return length_; } + void clear() { + (*this)[0] = '\0'; + length_ = 0; + } + void append(const char *format, ...); + + private: + uptr length_; +}; + +// Simple low-level (mmap-based) allocator for internal use. Doesn't have +// constructor, so all instances of LowLevelAllocator should be +// linker initialized. +class LowLevelAllocator { + public: + // Requires an external lock. + void *Allocate(uptr size); + private: + char *allocated_end_; + char *allocated_current_; +}; +typedef void (*LowLevelAllocateCallback)(uptr ptr, uptr size); +// Allows to register tool-specific callbacks for LowLevelAllocator. +// Passing NULL removes the callback. +void SetLowLevelAllocateCallback(LowLevelAllocateCallback callback); + +// IO +void RawWrite(const char *buffer); +bool ColorizeReports(); +void Printf(const char *format, ...); +void Report(const char *format, ...); +void SetPrintfAndReportCallback(void (*callback)(const char *)); +#define VReport(level, ...) \ + do { \ + if ((uptr)Verbosity() >= (level)) Report(__VA_ARGS__); \ + } while (0) +#define VPrintf(level, ...) \ + do { \ + if ((uptr)Verbosity() >= (level)) Printf(__VA_ARGS__); \ + } while (0) + +// Can be used to prevent mixing error reports from different sanitizers. +extern StaticSpinMutex CommonSanitizerReportMutex; + +struct ReportFile { + void Write(const char *buffer, uptr length); + bool PrintsToTty(); + void SetReportPath(const char *path); + + // Don't use fields directly. They are only declared public to allow + // aggregate initialization. + + // Protects fields below. + StaticSpinMutex *mu; + // Opened file descriptor. Defaults to stderr. It may be equal to + // kInvalidFd, in which case new file will be opened when necessary. + fd_t fd; + // Path prefix of report file, set via __sanitizer_set_report_path. + char path_prefix[kMaxPathLength]; + // Full path to report, obtained as <path_prefix>.PID + char full_path[kMaxPathLength]; + // PID of the process that opened fd. If a fork() occurs, + // the PID of child will be different from fd_pid. + uptr fd_pid; + + private: + void ReopenIfNecessary(); +}; +extern ReportFile report_file; + +extern uptr stoptheworld_tracer_pid; +extern uptr stoptheworld_tracer_ppid; + +uptr OpenFile(const char *filename, bool write); +// 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, int *errno_p = nullptr); +// 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); +void *MapWritableFileToMemory(void *addr, uptr size, uptr fd, uptr offset); + +bool IsAccessibleMemoryRange(uptr beg, uptr size); + +// Error report formatting. +const char *StripPathPrefix(const char *filepath, + const char *strip_file_prefix); +// Strip the directories from the module name. +const char *StripModuleName(const char *module); + +// OS +void DisableCoreDumperIfNecessary(); +void DumpProcessMap(); +bool FileExists(const char *filename); +const char *GetEnv(const char *name); +bool SetEnv(const char *name, const char *value); +const char *GetPwd(); +char *FindPathToBinary(const char *name); +u32 GetUid(); +void ReExec(); +bool StackSizeIsUnlimited(); +void SetStackSizeLimitInBytes(uptr limit); +bool AddressSpaceIsUnlimited(); +void SetAddressSpaceUnlimited(); +void AdjustStackSize(void *attr); +void PrepareForSandboxing(__sanitizer_sandbox_arguments *args); +void CovPrepareForSandboxing(__sanitizer_sandbox_arguments *args); +void SetSandboxingCallback(void (*f)()); + +void CoverageUpdateMapping(); +void CovBeforeFork(); +void CovAfterFork(int child_pid); + +void InitializeCoverage(bool enabled, const char *coverage_dir); +void ReInitializeCoverage(bool enabled, const char *coverage_dir); + +void InitTlsSize(); +uptr GetTlsSize(); + +// Other +void SleepForSeconds(int seconds); +void SleepForMillis(int millis); +u64 NanoTime(); +int Atexit(void (*function)(void)); +void SortArray(uptr *array, uptr size); +bool TemplateMatch(const char *templ, const char *str); + +// Exit +void NORETURN Abort(); +void NORETURN Die(); +void NORETURN +CheckFailed(const char *file, int line, const char *cond, u64 v1, u64 v2); + +// Set the name of the current thread to 'name', return true on succees. +// The name may be truncated to a system-dependent limit. +bool SanitizerSetThreadName(const char *name); +// Get the name of the current thread (no more than max_len bytes), +// return true on succees. name should have space for at least max_len+1 bytes. +bool SanitizerGetThreadName(char *name, int max_len); + +// Specific tools may override behavior of "Die" and "CheckFailed" functions +// to do tool-specific job. +typedef void (*DieCallbackType)(void); +void SetDieCallback(DieCallbackType); +void SetUserDieCallback(DieCallbackType); +DieCallbackType GetDieCallback(); +typedef void (*CheckFailedCallbackType)(const char *, int, const char *, + u64, u64); +void SetCheckFailedCallback(CheckFailedCallbackType callback); + +// Callback will be called if soft_rss_limit_mb is given and the limit is +// exceeded (exceeded==true) or if rss went down below the limit +// (exceeded==false). +// The callback should be registered once at the tool init time. +void SetSoftRssLimitExceededCallback(void (*Callback)(bool exceeded)); + +// Functions related to signal handling. +typedef void (*SignalHandlerType)(int, void *, void *); +bool IsDeadlySignal(int signum); +void InstallDeadlySignalHandlers(SignalHandlerType handler); +// Alternative signal stack (POSIX-only). +void SetAlternateSignalStack(); +void UnsetAlternateSignalStack(); + +// We don't want a summary too long. +const int kMaxSummaryLength = 1024; +// Construct a one-line string: +// SUMMARY: SanitizerToolName: error_message +// and pass it to __sanitizer_report_error_summary. +void ReportErrorSummary(const char *error_message); +// Same as above, but construct error_message as: +// error_type file:line function +void ReportErrorSummary(const char *error_type, const char *file, + int line, const char *function); +void ReportErrorSummary(const char *error_type, StackTrace *trace); + +// Math +#if SANITIZER_WINDOWS && !defined(__clang__) && !defined(__GNUC__) +extern "C" { +unsigned char _BitScanForward(unsigned long *index, unsigned long mask); // NOLINT +unsigned char _BitScanReverse(unsigned long *index, unsigned long mask); // NOLINT +#if defined(_WIN64) +unsigned char _BitScanForward64(unsigned long *index, unsigned __int64 mask); // NOLINT +unsigned char _BitScanReverse64(unsigned long *index, unsigned __int64 mask); // NOLINT +#endif +} +#endif + +INLINE uptr MostSignificantSetBitIndex(uptr x) { + CHECK_NE(x, 0U); + unsigned long up; // NOLINT +#if !SANITIZER_WINDOWS || defined(__clang__) || defined(__GNUC__) + up = SANITIZER_WORDSIZE - 1 - __builtin_clzl(x); +#elif defined(_WIN64) + _BitScanReverse64(&up, x); +#else + _BitScanReverse(&up, x); +#endif + return up; +} + +INLINE uptr LeastSignificantSetBitIndex(uptr x) { + CHECK_NE(x, 0U); + unsigned long up; // NOLINT +#if !SANITIZER_WINDOWS || defined(__clang__) || defined(__GNUC__) + up = __builtin_ctzl(x); +#elif defined(_WIN64) + _BitScanForward64(&up, x); +#else + _BitScanForward(&up, x); +#endif + return up; +} + +INLINE bool IsPowerOfTwo(uptr x) { + return (x & (x - 1)) == 0; +} + +INLINE uptr RoundUpToPowerOfTwo(uptr size) { + CHECK(size); + if (IsPowerOfTwo(size)) return size; + + uptr up = MostSignificantSetBitIndex(size); + CHECK(size < (1ULL << (up + 1))); + CHECK(size > (1ULL << up)); + return 1UL << (up + 1); +} + +INLINE uptr RoundUpTo(uptr size, uptr boundary) { + CHECK(IsPowerOfTwo(boundary)); + return (size + boundary - 1) & ~(boundary - 1); +} + +INLINE uptr RoundDownTo(uptr x, uptr boundary) { + return x & ~(boundary - 1); +} + +INLINE bool IsAligned(uptr a, uptr alignment) { + return (a & (alignment - 1)) == 0; +} + +INLINE uptr Log2(uptr x) { + CHECK(IsPowerOfTwo(x)); +#if !SANITIZER_WINDOWS || defined(__clang__) || defined(__GNUC__) + return __builtin_ctzl(x); +#elif defined(_WIN64) + unsigned long ret; // NOLINT + _BitScanForward64(&ret, x); + return ret; +#else + unsigned long ret; // NOLINT + _BitScanForward(&ret, x); + return ret; +#endif +} + +// 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; +} + +// A low-level vector based on mmap. May incur a significant memory overhead for +// small vectors. +// WARNING: The current implementation supports only POD types. +template<typename T> +class InternalMmapVectorNoCtor { + public: + void Initialize(uptr initial_capacity) { + capacity_ = Max(initial_capacity, (uptr)1); + size_ = 0; + data_ = (T *)MmapOrDie(capacity_ * sizeof(T), "InternalMmapVectorNoCtor"); + } + void Destroy() { + UnmapOrDie(data_, capacity_ * sizeof(T)); + } + T &operator[](uptr i) { + CHECK_LT(i, size_); + return data_[i]; + } + const T &operator[](uptr i) const { + CHECK_LT(i, size_); + return data_[i]; + } + void push_back(const T &element) { + CHECK_LE(size_, capacity_); + if (size_ == capacity_) { + uptr new_capacity = RoundUpToPowerOfTwo(size_ + 1); + Resize(new_capacity); + } + data_[size_++] = element; + } + T &back() { + CHECK_GT(size_, 0); + return data_[size_ - 1]; + } + void pop_back() { + CHECK_GT(size_, 0); + size_--; + } + uptr size() const { + return size_; + } + const T *data() const { + return data_; + } + uptr capacity() const { + return capacity_; + } + + void clear() { size_ = 0; } + + private: + void Resize(uptr new_capacity) { + CHECK_GT(new_capacity, 0); + CHECK_LE(size_, new_capacity); + T *new_data = (T *)MmapOrDie(new_capacity * sizeof(T), + "InternalMmapVector"); + internal_memcpy(new_data, data_, size_ * sizeof(T)); + T *old_data = data_; + data_ = new_data; + UnmapOrDie(old_data, capacity_ * sizeof(T)); + capacity_ = new_capacity; + } + + T *data_; + uptr capacity_; + uptr size_; +}; + +template<typename T> +class InternalMmapVector : public InternalMmapVectorNoCtor<T> { + public: + explicit InternalMmapVector(uptr initial_capacity) { + InternalMmapVectorNoCtor<T>::Initialize(initial_capacity); + } + ~InternalMmapVector() { InternalMmapVectorNoCtor<T>::Destroy(); } + // Disallow evil constructors. + InternalMmapVector(const InternalMmapVector&); + void operator=(const InternalMmapVector&); +}; + +// HeapSort for arrays and InternalMmapVector. +template<class Container, class Compare> +void InternalSort(Container *v, uptr size, Compare comp) { + 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 (comp((*v)[p], (*v)[j])) + Swap((*v)[j], (*v)[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((*v)[0], (*v)[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 && comp((*v)[max_ind], (*v)[left])) + max_ind = left; + if (right < i && comp((*v)[max_ind], (*v)[right])) + max_ind = right; + if (max_ind != j) + Swap((*v)[j], (*v)[max_ind]); + else + break; + } + } +} + +template<class Container, class Value, class Compare> +uptr InternalBinarySearch(const Container &v, uptr first, uptr last, + const Value &val, Compare comp) { + uptr not_found = last + 1; + while (last >= first) { + uptr mid = (first + last) / 2; + if (comp(v[mid], val)) + first = mid + 1; + else if (comp(val, v[mid])) + last = mid - 1; + else + return mid; + } + return not_found; +} + +// Represents a binary loaded into virtual memory (e.g. this can be an +// executable or a shared object). +class LoadedModule { + public: + LoadedModule(const char *module_name, uptr base_address); + void clear(); + void addAddressRange(uptr beg, uptr end, bool executable); + bool containsAddress(uptr address) const; + + const char *full_name() const { return full_name_; } + uptr base_address() const { return base_address_; } + + struct AddressRange { + AddressRange *next; + uptr beg; + uptr end; + bool executable; + + AddressRange(uptr beg, uptr end, bool executable) + : next(nullptr), beg(beg), end(end), executable(executable) {} + }; + + typedef IntrusiveList<AddressRange>::ConstIterator Iterator; + Iterator ranges() const { return Iterator(&ranges_); } + + private: + char *full_name_; // Owned. + uptr base_address_; + IntrusiveList<AddressRange> ranges_; +}; + +// OS-dependent function that fills array with descriptions of at most +// "max_modules" currently loaded modules. Returns the number of +// initialized modules. If filter is nonzero, ignores modules for which +// filter(full_name) is false. +typedef bool (*string_predicate_t)(const char *); +uptr GetListOfModules(LoadedModule *modules, uptr max_modules, + string_predicate_t filter); + +#if SANITIZER_POSIX +const uptr kPthreadDestructorIterations = 4; +#else +// Unused on Windows. +const uptr kPthreadDestructorIterations = 0; +#endif + +// Callback type for iterating over a set of memory ranges. +typedef void (*RangeIteratorCallback)(uptr begin, uptr end, void *arg); + +#if SANITIZER_ANDROID +// Initialize Android logging. Any writes before this are silently lost. +void AndroidLogInit(); +void AndroidLogWrite(const char *buffer); +void GetExtraActivationFlags(char *buf, uptr size); +void SanitizerInitializeUnwinder(); +#else +INLINE void AndroidLogInit() {} +INLINE void AndroidLogWrite(const char *buffer_unused) {} +INLINE void GetExtraActivationFlags(char *buf, uptr size) { *buf = '\0'; } +INLINE void SanitizerInitializeUnwinder() {} +#endif + +void *internal_start_thread(void(*func)(void*), void *arg); +void internal_join_thread(void *th); +void MaybeStartBackgroudThread(); + +// Make the compiler think that something is going on there. +// Use this inside a loop that looks like memset/memcpy/etc to prevent the +// compiler from recognising it and turning it into an actual call to +// memset/memcpy/etc. +static inline void SanitizerBreakOptimization(void *arg) { +#if _MSC_VER + // FIXME: make sure this is actually enough. + __asm; +#else + __asm__ __volatile__("" : : "r" (arg) : "memory"); +#endif +} + +} // namespace __sanitizer + +inline void *operator new(__sanitizer::operator_new_size_type size, + __sanitizer::LowLevelAllocator &alloc) { + return alloc.Allocate(size); +} + +struct StackDepotStats { + uptr n_uniq_ids; + uptr allocated; +}; + +#endif // SANITIZER_COMMON_H |