diff options
Diffstat (limited to 'lib/sanitizer_common/sanitizer_common.h')
-rw-r--r-- | lib/sanitizer_common/sanitizer_common.h | 187 |
1 files changed, 185 insertions, 2 deletions
diff --git a/lib/sanitizer_common/sanitizer_common.h b/lib/sanitizer_common/sanitizer_common.h index 1d002398c785a..d800360169fb5 100644 --- a/lib/sanitizer_common/sanitizer_common.h +++ b/lib/sanitizer_common/sanitizer_common.h @@ -17,8 +17,11 @@ #define SANITIZER_COMMON_H #include "sanitizer_internal_defs.h" +#include "sanitizer_libc.h" +#include "sanitizer_mutex.h" namespace __sanitizer { +struct StackTrace; // Constants. const uptr kWordSize = SANITIZER_WORDSIZE / 8; @@ -30,15 +33,19 @@ const uptr kCacheLineSize = 128; const uptr kCacheLineSize = 64; #endif +extern const char *SanitizerToolName; // Can be changed by the tool. +extern uptr SanitizerVerbosity; + uptr GetPageSize(); uptr GetPageSizeCached(); uptr GetMmapGranularity(); // Threads -int GetPid(); 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); @@ -104,7 +111,12 @@ bool PrintsToTty(); void Printf(const char *format, ...); void Report(const char *format, ...); void SetPrintfAndReportCallback(void (*callback)(const char *)); +// Can be used to prevent mixing error reports from different sanitizers. +extern StaticSpinMutex CommonSanitizerReportMutex; +void MaybeOpenReportFile(); +extern fd_t report_fd; +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', @@ -121,21 +133,26 @@ void DisableCoreDumper(); void DumpProcessMap(); bool FileExists(const char *filename); const char *GetEnv(const char *name); +bool SetEnv(const char *name, const char *value); const char *GetPwd(); +u32 GetUid(); void ReExec(); bool StackSizeIsUnlimited(); void SetStackSizeLimitInBytes(uptr limit); void PrepareForSandboxing(); +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); // Exit void NORETURN Abort(); -void NORETURN Exit(int exitcode); void NORETURN Die(); void NORETURN SANITIZER_INTERFACE_ATTRIBUTE CheckFailed(const char *file, int line, const char *cond, u64 v1, u64 v2); @@ -154,20 +171,79 @@ typedef void (*CheckFailedCallbackType)(const char *, int, const char *, u64, u64); void SetCheckFailedCallback(CheckFailedCallbackType callback); +// Construct a one-line string like +// SanitizerToolName: error_type file:line function +// and call __sanitizer_report_error_summary on it. +void ReportErrorSummary(const char *error_type, const char *file, + int line, const char *function); + // Math +#if SANITIZER_WINDOWS && !defined(__clang__) +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__) + up = SANITIZER_WORDSIZE - 1 - __builtin_clzl(x); +#elif defined(_WIN64) + _BitScanReverse64(&up, x); +#else + _BitScanReverse(&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__) + 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; } @@ -196,6 +272,113 @@ INLINE int ToLower(int c) { # define FIRST_32_SECOND_64(a, b) (a) #endif +// 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 InternalVector { + public: + explicit InternalVector(uptr initial_capacity) { + CHECK_GT(initial_capacity, 0); + capacity_ = initial_capacity; + size_ = 0; + data_ = (T *)MmapOrDie(capacity_ * sizeof(T), "InternalVector"); + } + ~InternalVector() { + 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_; + } + + 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), + "InternalVector"); + internal_memcpy(new_data, data_, size_ * sizeof(T)); + T *old_data = data_; + data_ = new_data; + UnmapOrDie(old_data, capacity_ * sizeof(T)); + capacity_ = new_capacity; + } + // Disallow evil constructors. + InternalVector(const InternalVector&); + void operator=(const InternalVector&); + + T *data_; + uptr capacity_; + uptr size_; +}; + +// HeapSort for arrays and InternalVector. +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; + } + } +} + } // namespace __sanitizer #endif // SANITIZER_COMMON_H |