diff options
author | nkozlovskiy <nmk@ydb.tech> | 2023-10-11 19:11:46 +0300 |
---|---|---|
committer | nkozlovskiy <nmk@ydb.tech> | 2023-10-11 19:33:28 +0300 |
commit | 61b3971447e473726d6cdb23fc298e457b4d973c (patch) | |
tree | e2a2a864bb7717f7ae6138f6a3194a254dd2c7bb /contrib/libs/clang14-rt/lib/sanitizer_common | |
parent | a674dc57d88d43c2e8e90a6084d5d2c988e0402c (diff) | |
download | ydb-61b3971447e473726d6cdb23fc298e457b4d973c.tar.gz |
add sanitizers dependencies
Diffstat (limited to 'contrib/libs/clang14-rt/lib/sanitizer_common')
183 files changed, 66330 insertions, 0 deletions
diff --git a/contrib/libs/clang14-rt/lib/sanitizer_common/sancov_flags.cpp b/contrib/libs/clang14-rt/lib/sanitizer_common/sancov_flags.cpp new file mode 100644 index 0000000000..ed46e88acd --- /dev/null +++ b/contrib/libs/clang14-rt/lib/sanitizer_common/sancov_flags.cpp @@ -0,0 +1,58 @@ +//===-- sancov_flags.cpp ----------------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// Sanitizer Coverage runtime flags. +// +//===----------------------------------------------------------------------===// + +#include "sancov_flags.h" +#include "sanitizer_flag_parser.h" +#include "sanitizer_platform.h" + +SANITIZER_INTERFACE_WEAK_DEF(const char*, __sancov_default_options, void) { + return ""; +} + +using namespace __sanitizer; + +namespace __sancov { + +SancovFlags sancov_flags_dont_use_directly; // use via flags(); + +void SancovFlags::SetDefaults() { +#define SANCOV_FLAG(Type, Name, DefaultValue, Description) Name = DefaultValue; +#include "sancov_flags.inc" +#undef SANCOV_FLAG +} + +static void RegisterSancovFlags(FlagParser *parser, SancovFlags *f) { +#define SANCOV_FLAG(Type, Name, DefaultValue, Description) \ + RegisterFlag(parser, #Name, Description, &f->Name); +#include "sancov_flags.inc" +#undef SANCOV_FLAG +} + +static const char *MaybeCallSancovDefaultOptions() { + return (&__sancov_default_options) ? __sancov_default_options() : ""; +} + +void InitializeSancovFlags() { + SancovFlags *f = sancov_flags(); + f->SetDefaults(); + + FlagParser parser; + RegisterSancovFlags(&parser, f); + + parser.ParseString(MaybeCallSancovDefaultOptions()); + parser.ParseStringFromEnv("SANCOV_OPTIONS"); + + ReportUnrecognizedFlags(); + if (f->help) parser.PrintFlagDescriptions(); +} + +} // namespace __sancov diff --git a/contrib/libs/clang14-rt/lib/sanitizer_common/sancov_flags.h b/contrib/libs/clang14-rt/lib/sanitizer_common/sancov_flags.h new file mode 100644 index 0000000000..95d4ee5ca4 --- /dev/null +++ b/contrib/libs/clang14-rt/lib/sanitizer_common/sancov_flags.h @@ -0,0 +1,39 @@ +//===-- sancov_flags.h ------------------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// Sanitizer Coverage runtime flags. +// +//===----------------------------------------------------------------------===// +#ifndef SANCOV_FLAGS_H +#define SANCOV_FLAGS_H + +#include "sanitizer_flag_parser.h" +#include "sanitizer_internal_defs.h" + +namespace __sancov { + +struct SancovFlags { +#define SANCOV_FLAG(Type, Name, DefaultValue, Description) Type Name; +#include "sancov_flags.inc" +#undef SANCOV_FLAG + + void SetDefaults(); +}; + +extern SancovFlags sancov_flags_dont_use_directly; + +inline SancovFlags* sancov_flags() { return &sancov_flags_dont_use_directly; } + +void InitializeSancovFlags(); + +} // namespace __sancov + +extern "C" SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE const char* +__sancov_default_options(); + +#endif diff --git a/contrib/libs/clang14-rt/lib/sanitizer_common/sancov_flags.inc b/contrib/libs/clang14-rt/lib/sanitizer_common/sancov_flags.inc new file mode 100644 index 0000000000..de9ede217f --- /dev/null +++ b/contrib/libs/clang14-rt/lib/sanitizer_common/sancov_flags.inc @@ -0,0 +1,20 @@ +//===-- sancov_flags.inc ----------------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// Sanitizer Coverage runtime flags. +// +//===----------------------------------------------------------------------===// +#ifndef SANCOV_FLAG +#error "Defnine SANCOV_FLAG prior to including this file!" +#endif + +SANCOV_FLAG(bool, symbolize, true, + "If set, coverage information will be symbolized by sancov tool " + "after dumping.") + +SANCOV_FLAG(bool, help, false, "Print flags help.") diff --git a/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_addrhashmap.h b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_addrhashmap.h new file mode 100644 index 0000000000..fe48b9caf0 --- /dev/null +++ b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_addrhashmap.h @@ -0,0 +1,393 @@ +//===-- sanitizer_addrhashmap.h ---------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// Concurrent uptr->T hashmap. +// +//===----------------------------------------------------------------------===// + +#ifndef SANITIZER_ADDRHASHMAP_H +#define SANITIZER_ADDRHASHMAP_H + +#include "sanitizer_common.h" +#include "sanitizer_mutex.h" +#include "sanitizer_atomic.h" +#include "sanitizer_allocator_internal.h" + +namespace __sanitizer { + +// Concurrent uptr->T hashmap. +// T must be a POD type, kSize is preferably a prime but can be any number. +// Usage example: +// +// typedef AddrHashMap<uptr, 11> Map; +// Map m; +// { +// Map::Handle h(&m, addr); +// use h.operator->() to access the data +// if h.created() then the element was just created, and the current thread +// has exclusive access to it +// otherwise the current thread has only read access to the data +// } +// { +// Map::Handle h(&m, addr, true); +// this will remove the data from the map in Handle dtor +// the current thread has exclusive access to the data +// if !h.exists() then the element never existed +// } +// { +// Map::Handle h(&m, addr, false, true); +// this will create a new element or return a handle to an existing element +// if !h.created() this thread does *not* have exclusive access to the data +// } +template<typename T, uptr kSize> +class AddrHashMap { + private: + struct Cell { + atomic_uintptr_t addr; + T val; + }; + + struct AddBucket { + uptr cap; + uptr size; + Cell cells[1]; // variable len + }; + + static const uptr kBucketSize = 3; + + struct Bucket { + Mutex mtx; + atomic_uintptr_t add; + Cell cells[kBucketSize]; + }; + + public: + AddrHashMap(); + + class Handle { + public: + Handle(AddrHashMap<T, kSize> *map, uptr addr); + Handle(AddrHashMap<T, kSize> *map, uptr addr, bool remove); + Handle(AddrHashMap<T, kSize> *map, uptr addr, bool remove, bool create); + + ~Handle(); + T *operator->(); + T &operator*(); + const T &operator*() const; + bool created() const; + bool exists() const; + + private: + friend AddrHashMap<T, kSize>; + AddrHashMap<T, kSize> *map_; + Bucket *bucket_; + Cell *cell_; + uptr addr_; + uptr addidx_; + bool created_; + bool remove_; + bool create_; + }; + + typedef void (*ForEachCallback)(const uptr key, const T &val, void *arg); + // ForEach acquires a lock on each bucket while iterating over + // elements. Note that this only ensures that the structure of the hashmap is + // unchanged, there may be a data race to the element itself. + void ForEach(ForEachCallback cb, void *arg); + + private: + friend class Handle; + Bucket *table_; + + void acquire(Handle *h); + void release(Handle *h); + uptr calcHash(uptr addr); +}; + +template <typename T, uptr kSize> +void AddrHashMap<T, kSize>::ForEach(ForEachCallback cb, void *arg) { + for (uptr n = 0; n < kSize; n++) { + Bucket *bucket = &table_[n]; + + ReadLock lock(&bucket->mtx); + + for (uptr i = 0; i < kBucketSize; i++) { + Cell *c = &bucket->cells[i]; + uptr addr1 = atomic_load(&c->addr, memory_order_acquire); + if (addr1 != 0) + cb(addr1, c->val, arg); + } + + // Iterate over any additional cells. + if (AddBucket *add = + (AddBucket *)atomic_load(&bucket->add, memory_order_acquire)) { + for (uptr i = 0; i < add->size; i++) { + Cell *c = &add->cells[i]; + uptr addr1 = atomic_load(&c->addr, memory_order_acquire); + if (addr1 != 0) + cb(addr1, c->val, arg); + } + } + } +} + +template<typename T, uptr kSize> +AddrHashMap<T, kSize>::Handle::Handle(AddrHashMap<T, kSize> *map, uptr addr) { + map_ = map; + addr_ = addr; + remove_ = false; + create_ = true; + map_->acquire(this); +} + +template<typename T, uptr kSize> +AddrHashMap<T, kSize>::Handle::Handle(AddrHashMap<T, kSize> *map, uptr addr, + bool remove) { + map_ = map; + addr_ = addr; + remove_ = remove; + create_ = true; + map_->acquire(this); +} + +template<typename T, uptr kSize> +AddrHashMap<T, kSize>::Handle::Handle(AddrHashMap<T, kSize> *map, uptr addr, + bool remove, bool create) { + map_ = map; + addr_ = addr; + remove_ = remove; + create_ = create; + map_->acquire(this); +} + +template<typename T, uptr kSize> +AddrHashMap<T, kSize>::Handle::~Handle() { + map_->release(this); +} + +template <typename T, uptr kSize> +T *AddrHashMap<T, kSize>::Handle::operator->() { + return &cell_->val; +} + +template <typename T, uptr kSize> +const T &AddrHashMap<T, kSize>::Handle::operator*() const { + return cell_->val; +} + +template <typename T, uptr kSize> +T &AddrHashMap<T, kSize>::Handle::operator*() { + return cell_->val; +} + +template<typename T, uptr kSize> +bool AddrHashMap<T, kSize>::Handle::created() const { + return created_; +} + +template<typename T, uptr kSize> +bool AddrHashMap<T, kSize>::Handle::exists() const { + return cell_ != nullptr; +} + +template<typename T, uptr kSize> +AddrHashMap<T, kSize>::AddrHashMap() { + table_ = (Bucket*)MmapOrDie(kSize * sizeof(table_[0]), "AddrHashMap"); +} + +template <typename T, uptr kSize> +void AddrHashMap<T, kSize>::acquire(Handle *h) + SANITIZER_NO_THREAD_SAFETY_ANALYSIS { + uptr addr = h->addr_; + uptr hash = calcHash(addr); + Bucket *b = &table_[hash]; + + h->created_ = false; + h->addidx_ = -1U; + h->bucket_ = b; + h->cell_ = nullptr; + + // If we want to remove the element, we need exclusive access to the bucket, + // so skip the lock-free phase. + if (h->remove_) + goto locked; + + retry: + // First try to find an existing element w/o read mutex. + CHECK(!h->remove_); + // Check the embed cells. + for (uptr i = 0; i < kBucketSize; i++) { + Cell *c = &b->cells[i]; + uptr addr1 = atomic_load(&c->addr, memory_order_acquire); + if (addr1 == addr) { + h->cell_ = c; + return; + } + } + + // Check the add cells with read lock. + if (atomic_load(&b->add, memory_order_relaxed)) { + b->mtx.ReadLock(); + AddBucket *add = (AddBucket*)atomic_load(&b->add, memory_order_relaxed); + for (uptr i = 0; i < add->size; i++) { + Cell *c = &add->cells[i]; + uptr addr1 = atomic_load(&c->addr, memory_order_relaxed); + if (addr1 == addr) { + h->addidx_ = i; + h->cell_ = c; + return; + } + } + b->mtx.ReadUnlock(); + } + + locked: + // Re-check existence under write lock. + // Embed cells. + b->mtx.Lock(); + for (uptr i = 0; i < kBucketSize; i++) { + Cell *c = &b->cells[i]; + uptr addr1 = atomic_load(&c->addr, memory_order_relaxed); + if (addr1 == addr) { + if (h->remove_) { + h->cell_ = c; + return; + } + b->mtx.Unlock(); + goto retry; + } + } + + // Add cells. + AddBucket *add = (AddBucket*)atomic_load(&b->add, memory_order_relaxed); + if (add) { + for (uptr i = 0; i < add->size; i++) { + Cell *c = &add->cells[i]; + uptr addr1 = atomic_load(&c->addr, memory_order_relaxed); + if (addr1 == addr) { + if (h->remove_) { + h->addidx_ = i; + h->cell_ = c; + return; + } + b->mtx.Unlock(); + goto retry; + } + } + } + + // The element does not exist, no need to create it if we want to remove. + if (h->remove_ || !h->create_) { + b->mtx.Unlock(); + return; + } + + // Now try to create it under the mutex. + h->created_ = true; + // See if we have a free embed cell. + for (uptr i = 0; i < kBucketSize; i++) { + Cell *c = &b->cells[i]; + uptr addr1 = atomic_load(&c->addr, memory_order_relaxed); + if (addr1 == 0) { + h->cell_ = c; + return; + } + } + + // Store in the add cells. + if (!add) { + // Allocate a new add array. + const uptr kInitSize = 64; + add = (AddBucket*)InternalAlloc(kInitSize); + internal_memset(add, 0, kInitSize); + add->cap = (kInitSize - sizeof(*add)) / sizeof(add->cells[0]) + 1; + add->size = 0; + atomic_store(&b->add, (uptr)add, memory_order_relaxed); + } + if (add->size == add->cap) { + // Grow existing add array. + uptr oldsize = sizeof(*add) + (add->cap - 1) * sizeof(add->cells[0]); + uptr newsize = oldsize * 2; + AddBucket *add1 = (AddBucket*)InternalAlloc(newsize); + internal_memset(add1, 0, newsize); + add1->cap = (newsize - sizeof(*add)) / sizeof(add->cells[0]) + 1; + add1->size = add->size; + internal_memcpy(add1->cells, add->cells, add->size * sizeof(add->cells[0])); + InternalFree(add); + atomic_store(&b->add, (uptr)add1, memory_order_relaxed); + add = add1; + } + // Store. + uptr i = add->size++; + Cell *c = &add->cells[i]; + CHECK_EQ(atomic_load(&c->addr, memory_order_relaxed), 0); + h->addidx_ = i; + h->cell_ = c; + } + + template <typename T, uptr kSize> + void AddrHashMap<T, kSize>::release(Handle *h) + SANITIZER_NO_THREAD_SAFETY_ANALYSIS { + if (!h->cell_) + return; + Bucket *b = h->bucket_; + Cell *c = h->cell_; + uptr addr1 = atomic_load(&c->addr, memory_order_relaxed); + if (h->created_) { + // Denote completion of insertion. + CHECK_EQ(addr1, 0); + // After the following store, the element becomes available + // for lock-free reads. + atomic_store(&c->addr, h->addr_, memory_order_release); + b->mtx.Unlock(); + } else if (h->remove_) { + // Denote that the cell is empty now. + CHECK_EQ(addr1, h->addr_); + atomic_store(&c->addr, 0, memory_order_release); + // See if we need to compact the bucket. + AddBucket *add = (AddBucket *)atomic_load(&b->add, memory_order_relaxed); + if (h->addidx_ == -1U) { + // Removed from embed array, move an add element into the freed cell. + if (add && add->size != 0) { + uptr last = --add->size; + Cell *c1 = &add->cells[last]; + c->val = c1->val; + uptr addr1 = atomic_load(&c1->addr, memory_order_relaxed); + atomic_store(&c->addr, addr1, memory_order_release); + atomic_store(&c1->addr, 0, memory_order_release); + } + } else { + // Removed from add array, compact it. + uptr last = --add->size; + Cell *c1 = &add->cells[last]; + if (c != c1) { + *c = *c1; + atomic_store(&c1->addr, 0, memory_order_relaxed); + } + } + if (add && add->size == 0) { + // FIXME(dvyukov): free add? + } + b->mtx.Unlock(); + } else { + CHECK_EQ(addr1, h->addr_); + if (h->addidx_ != -1U) + b->mtx.ReadUnlock(); + } + } + +template<typename T, uptr kSize> +uptr AddrHashMap<T, kSize>::calcHash(uptr addr) { + addr += addr << 10; + addr ^= addr >> 6; + return addr % kSize; +} + +} // namespace __sanitizer + +#endif // SANITIZER_ADDRHASHMAP_H diff --git a/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_allocator.cpp b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_allocator.cpp new file mode 100644 index 0000000000..25a43a59f0 --- /dev/null +++ b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_allocator.cpp @@ -0,0 +1,209 @@ +//===-- sanitizer_allocator.cpp -------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file is shared between AddressSanitizer and ThreadSanitizer +// run-time libraries. +// This allocator is used inside run-times. +//===----------------------------------------------------------------------===// + +#include "sanitizer_allocator.h" + +#include "sanitizer_allocator_checks.h" +#include "sanitizer_allocator_internal.h" +#include "sanitizer_atomic.h" +#include "sanitizer_common.h" +#include "sanitizer_platform.h" + +namespace __sanitizer { + +// Default allocator names. +const char *PrimaryAllocatorName = "SizeClassAllocator"; +const char *SecondaryAllocatorName = "LargeMmapAllocator"; + +static ALIGNED(64) char internal_alloc_placeholder[sizeof(InternalAllocator)]; +static atomic_uint8_t internal_allocator_initialized; +static StaticSpinMutex internal_alloc_init_mu; + +static InternalAllocatorCache internal_allocator_cache; +static StaticSpinMutex internal_allocator_cache_mu; + +InternalAllocator *internal_allocator() { + InternalAllocator *internal_allocator_instance = + reinterpret_cast<InternalAllocator *>(&internal_alloc_placeholder); + if (atomic_load(&internal_allocator_initialized, memory_order_acquire) == 0) { + SpinMutexLock l(&internal_alloc_init_mu); + if (atomic_load(&internal_allocator_initialized, memory_order_relaxed) == + 0) { + internal_allocator_instance->Init(kReleaseToOSIntervalNever); + atomic_store(&internal_allocator_initialized, 1, memory_order_release); + } + } + return internal_allocator_instance; +} + +static void *RawInternalAlloc(uptr size, InternalAllocatorCache *cache, + uptr alignment) { + if (alignment == 0) alignment = 8; + if (cache == 0) { + SpinMutexLock l(&internal_allocator_cache_mu); + return internal_allocator()->Allocate(&internal_allocator_cache, size, + alignment); + } + return internal_allocator()->Allocate(cache, size, alignment); +} + +static void *RawInternalRealloc(void *ptr, uptr size, + InternalAllocatorCache *cache) { + uptr alignment = 8; + if (cache == 0) { + SpinMutexLock l(&internal_allocator_cache_mu); + return internal_allocator()->Reallocate(&internal_allocator_cache, ptr, + size, alignment); + } + return internal_allocator()->Reallocate(cache, ptr, size, alignment); +} + +static void RawInternalFree(void *ptr, InternalAllocatorCache *cache) { + if (!cache) { + SpinMutexLock l(&internal_allocator_cache_mu); + return internal_allocator()->Deallocate(&internal_allocator_cache, ptr); + } + internal_allocator()->Deallocate(cache, ptr); +} + +static void NORETURN ReportInternalAllocatorOutOfMemory(uptr requested_size) { + SetAllocatorOutOfMemory(); + Report("FATAL: %s: internal allocator is out of memory trying to allocate " + "0x%zx bytes\n", SanitizerToolName, requested_size); + Die(); +} + +void *InternalAlloc(uptr size, InternalAllocatorCache *cache, uptr alignment) { + void *p = RawInternalAlloc(size, cache, alignment); + if (UNLIKELY(!p)) + ReportInternalAllocatorOutOfMemory(size); + return p; +} + +void *InternalRealloc(void *addr, uptr size, InternalAllocatorCache *cache) { + void *p = RawInternalRealloc(addr, size, cache); + if (UNLIKELY(!p)) + ReportInternalAllocatorOutOfMemory(size); + return p; +} + +void *InternalReallocArray(void *addr, uptr count, uptr size, + InternalAllocatorCache *cache) { + if (UNLIKELY(CheckForCallocOverflow(count, size))) { + Report( + "FATAL: %s: reallocarray parameters overflow: count * size (%zd * %zd) " + "cannot be represented in type size_t\n", + SanitizerToolName, count, size); + Die(); + } + return InternalRealloc(addr, count * size, cache); +} + +void *InternalCalloc(uptr count, uptr size, InternalAllocatorCache *cache) { + if (UNLIKELY(CheckForCallocOverflow(count, size))) { + Report("FATAL: %s: calloc parameters overflow: count * size (%zd * %zd) " + "cannot be represented in type size_t\n", SanitizerToolName, count, + size); + Die(); + } + void *p = InternalAlloc(count * size, cache); + if (LIKELY(p)) + internal_memset(p, 0, count * size); + return p; +} + +void InternalFree(void *addr, InternalAllocatorCache *cache) { + RawInternalFree(addr, cache); +} + +void InternalAllocatorLock() SANITIZER_NO_THREAD_SAFETY_ANALYSIS { + internal_allocator_cache_mu.Lock(); + internal_allocator()->ForceLock(); +} + +void InternalAllocatorUnlock() SANITIZER_NO_THREAD_SAFETY_ANALYSIS { + internal_allocator()->ForceUnlock(); + internal_allocator_cache_mu.Unlock(); +} + +// LowLevelAllocator +constexpr uptr kLowLevelAllocatorDefaultAlignment = 8; +static uptr low_level_alloc_min_alignment = kLowLevelAllocatorDefaultAlignment; +static LowLevelAllocateCallback low_level_alloc_callback; + +void *LowLevelAllocator::Allocate(uptr size) { + // Align allocation size. + size = RoundUpTo(size, low_level_alloc_min_alignment); + if (allocated_end_ - allocated_current_ < (sptr)size) { + uptr size_to_allocate = RoundUpTo(size, GetPageSizeCached()); + allocated_current_ = + (char*)MmapOrDie(size_to_allocate, __func__); + allocated_end_ = allocated_current_ + size_to_allocate; + if (low_level_alloc_callback) { + low_level_alloc_callback((uptr)allocated_current_, + size_to_allocate); + } + } + CHECK(allocated_end_ - allocated_current_ >= (sptr)size); + void *res = allocated_current_; + allocated_current_ += size; + return res; +} + +void SetLowLevelAllocateMinAlignment(uptr alignment) { + CHECK(IsPowerOfTwo(alignment)); + low_level_alloc_min_alignment = Max(alignment, low_level_alloc_min_alignment); +} + +void SetLowLevelAllocateCallback(LowLevelAllocateCallback callback) { + low_level_alloc_callback = callback; +} + +// Allocator's OOM and other errors handling support. + +static atomic_uint8_t allocator_out_of_memory = {0}; +static atomic_uint8_t allocator_may_return_null = {0}; + +bool IsAllocatorOutOfMemory() { + return atomic_load_relaxed(&allocator_out_of_memory); +} + +void SetAllocatorOutOfMemory() { + atomic_store_relaxed(&allocator_out_of_memory, 1); +} + +bool AllocatorMayReturnNull() { + return atomic_load(&allocator_may_return_null, memory_order_relaxed); +} + +void SetAllocatorMayReturnNull(bool may_return_null) { + atomic_store(&allocator_may_return_null, may_return_null, + memory_order_relaxed); +} + +void PrintHintAllocatorCannotReturnNull() { + Report("HINT: if you don't care about these errors you may set " + "allocator_may_return_null=1\n"); +} + +static atomic_uint8_t rss_limit_exceeded; + +bool IsRssLimitExceeded() { + return atomic_load(&rss_limit_exceeded, memory_order_relaxed); +} + +void SetRssLimitExceeded(bool limit_exceeded) { + atomic_store(&rss_limit_exceeded, limit_exceeded, memory_order_relaxed); +} + +} // namespace __sanitizer diff --git a/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_allocator.h b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_allocator.h new file mode 100644 index 0000000000..76b936ff5e --- /dev/null +++ b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_allocator.h @@ -0,0 +1,78 @@ +//===-- sanitizer_allocator.h -----------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// Specialized memory allocator for ThreadSanitizer, MemorySanitizer, etc. +// +//===----------------------------------------------------------------------===// + +#ifndef SANITIZER_ALLOCATOR_H +#define SANITIZER_ALLOCATOR_H + +#include "sanitizer_common.h" +#include "sanitizer_flat_map.h" +#include "sanitizer_internal_defs.h" +#include "sanitizer_lfstack.h" +#include "sanitizer_libc.h" +#include "sanitizer_list.h" +#include "sanitizer_local_address_space_view.h" +#include "sanitizer_mutex.h" +#include "sanitizer_procmaps.h" +#include "sanitizer_type_traits.h" + +namespace __sanitizer { + +// Allows the tools to name their allocations appropriately. +extern const char *PrimaryAllocatorName; +extern const char *SecondaryAllocatorName; + +// Since flags are immutable and allocator behavior can be changed at runtime +// (unit tests or ASan on Android are some examples), allocator_may_return_null +// flag value is cached here and can be altered later. +bool AllocatorMayReturnNull(); +void SetAllocatorMayReturnNull(bool may_return_null); + +// Returns true if allocator detected OOM condition. Can be used to avoid memory +// hungry operations. +bool IsAllocatorOutOfMemory(); +// Should be called by a particular allocator when OOM is detected. +void SetAllocatorOutOfMemory(); + +void PrintHintAllocatorCannotReturnNull(); + +// Callback type for iterating over chunks. +typedef void (*ForEachChunkCallback)(uptr chunk, void *arg); + +inline u32 Rand(u32 *state) { // ANSI C linear congruential PRNG. + return (*state = *state * 1103515245 + 12345) >> 16; +} + +inline u32 RandN(u32 *state, u32 n) { return Rand(state) % n; } // [0, n) + +template<typename T> +inline void RandomShuffle(T *a, u32 n, u32 *rand_state) { + if (n <= 1) return; + u32 state = *rand_state; + for (u32 i = n - 1; i > 0; i--) + Swap(a[i], a[RandN(&state, i + 1)]); + *rand_state = state; +} + +#include "sanitizer_allocator_size_class_map.h" +#include "sanitizer_allocator_stats.h" +#include "sanitizer_allocator_primary64.h" +#include "sanitizer_allocator_primary32.h" +#include "sanitizer_allocator_local_cache.h" +#include "sanitizer_allocator_secondary.h" +#include "sanitizer_allocator_combined.h" + +bool IsRssLimitExceeded(); +void SetRssLimitExceeded(bool limit_exceeded); + +} // namespace __sanitizer + +#endif // SANITIZER_ALLOCATOR_H diff --git a/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_allocator_checks.cpp b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_allocator_checks.cpp new file mode 100644 index 0000000000..9d67f679b5 --- /dev/null +++ b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_allocator_checks.cpp @@ -0,0 +1,22 @@ +//===-- sanitizer_allocator_checks.cpp --------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// Various checks shared between ThreadSanitizer, MemorySanitizer, etc. memory +// allocators. +// +//===----------------------------------------------------------------------===// + +#include "sanitizer_errno.h" + +namespace __sanitizer { + +void SetErrnoToENOMEM() { + errno = errno_ENOMEM; +} + +} // namespace __sanitizer diff --git a/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_allocator_checks.h b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_allocator_checks.h new file mode 100644 index 0000000000..1cc3992c4c --- /dev/null +++ b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_allocator_checks.h @@ -0,0 +1,76 @@ +//===-- sanitizer_allocator_checks.h ----------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// Various checks shared between ThreadSanitizer, MemorySanitizer, etc. memory +// allocators. +// +//===----------------------------------------------------------------------===// + +#ifndef SANITIZER_ALLOCATOR_CHECKS_H +#define SANITIZER_ALLOCATOR_CHECKS_H + +#include "sanitizer_internal_defs.h" +#include "sanitizer_common.h" +#include "sanitizer_platform.h" + +namespace __sanitizer { + +// The following is defined in a separate compilation unit to avoid pulling in +// sanitizer_errno.h in this header, which leads to conflicts when other system +// headers include errno.h. This is usually the result of an unlikely event, +// and as such we do not care as much about having it inlined. +void SetErrnoToENOMEM(); + +// A common errno setting logic shared by almost all sanitizer allocator APIs. +inline void *SetErrnoOnNull(void *ptr) { + if (UNLIKELY(!ptr)) + SetErrnoToENOMEM(); + return ptr; +} + +// In case of the check failure, the caller of the following Check... functions +// should "return POLICY::OnBadRequest();" where POLICY is the current allocator +// failure handling policy. + +// Checks aligned_alloc() parameters, verifies that the alignment is a power of +// two and that the size is a multiple of alignment for POSIX implementation, +// and a bit relaxed requirement for non-POSIX ones, that the size is a multiple +// of alignment. +inline bool CheckAlignedAllocAlignmentAndSize(uptr alignment, uptr size) { +#if SANITIZER_POSIX + return alignment != 0 && IsPowerOfTwo(alignment) && + (size & (alignment - 1)) == 0; +#else + return alignment != 0 && size % alignment == 0; +#endif +} + +// Checks posix_memalign() parameters, verifies that alignment is a power of two +// and a multiple of sizeof(void *). +inline bool CheckPosixMemalignAlignment(uptr alignment) { + return alignment != 0 && IsPowerOfTwo(alignment) && + (alignment % sizeof(void *)) == 0; +} + +// Returns true if calloc(size, n) call overflows on size*n calculation. +inline bool CheckForCallocOverflow(uptr size, uptr n) { + if (!size) + return false; + uptr max = (uptr)-1L; + return (max / size) < n; +} + +// Returns true if the size passed to pvalloc overflows when rounded to the next +// multiple of page_size. +inline bool CheckForPvallocOverflow(uptr size, uptr page_size) { + return RoundUpTo(size, page_size) < size; +} + +} // namespace __sanitizer + +#endif // SANITIZER_ALLOCATOR_CHECKS_H diff --git a/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_allocator_combined.h b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_allocator_combined.h new file mode 100644 index 0000000000..b92cfa5bf4 --- /dev/null +++ b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_allocator_combined.h @@ -0,0 +1,199 @@ +//===-- sanitizer_allocator_combined.h --------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// Part of the Sanitizer Allocator. +// +//===----------------------------------------------------------------------===// +#ifndef SANITIZER_ALLOCATOR_H +#error This file must be included inside sanitizer_allocator.h +#endif + +// 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 LargeMmapAllocatorPtrArray = DefaultLargeMmapAllocatorPtrArray> +class CombinedAllocator { + public: + using AllocatorCache = typename PrimaryAllocator::AllocatorCache; + using SecondaryAllocator = + LargeMmapAllocator<typename PrimaryAllocator::MapUnmapCallback, + LargeMmapAllocatorPtrArray, + typename PrimaryAllocator::AddressSpaceView>; + + void InitLinkerInitialized(s32 release_to_os_interval_ms) { + stats_.InitLinkerInitialized(); + primary_.Init(release_to_os_interval_ms); + secondary_.InitLinkerInitialized(); + } + + void Init(s32 release_to_os_interval_ms, uptr heap_start = 0) { + stats_.Init(); + primary_.Init(release_to_os_interval_ms, heap_start); + secondary_.Init(); + } + + void *Allocate(AllocatorCache *cache, uptr size, uptr alignment) { + // Returning 0 on malloc(0) may break a lot of code. + if (size == 0) + size = 1; + if (size + alignment < size) { + Report("WARNING: %s: CombinedAllocator allocation overflow: " + "0x%zx bytes with 0x%zx alignment requested\n", + SanitizerToolName, size, alignment); + return nullptr; + } + uptr original_size = size; + // If alignment requirements are to be fulfilled by the frontend allocator + // rather than by the primary or secondary, passing an alignment lower than + // or equal to 8 will prevent any further rounding up, as well as the later + // alignment check. + if (alignment > 8) + size = RoundUpTo(size, alignment); + // The primary allocator should return a 2^x aligned allocation when + // requested 2^x bytes, hence using the rounded up 'size' when being + // serviced by the primary (this is no longer true when the primary is + // using a non-fixed base address). The secondary takes care of the + // alignment without such requirement, and allocating 'size' would use + // extraneous memory, so we employ 'original_size'. + void *res; + if (primary_.CanAllocate(size, alignment)) + res = cache->Allocate(&primary_, primary_.ClassID(size)); + else + res = secondary_.Allocate(&stats_, original_size, alignment); + if (alignment > 8) + CHECK_EQ(reinterpret_cast<uptr>(res) & (alignment - 1), 0); + return res; + } + + s32 ReleaseToOSIntervalMs() const { + return primary_.ReleaseToOSIntervalMs(); + } + + void SetReleaseToOSIntervalMs(s32 release_to_os_interval_ms) { + primary_.SetReleaseToOSIntervalMs(release_to_os_interval_ms); + } + + void ForceReleaseToOS() { + primary_.ForceReleaseToOS(); + } + + void Deallocate(AllocatorCache *cache, void *p) { + if (!p) return; + if (primary_.PointerIsMine(p)) + cache->Deallocate(&primary_, primary_.GetSizeClass(p), p); + else + secondary_.Deallocate(&stats_, 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 nullptr; + } + 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(const void *p) const { + if (primary_.PointerIsMine(p)) + return true; + return secondary_.PointerIsMine(p); + } + + bool FromPrimary(const void *p) const { return primary_.PointerIsMine(p); } + + void *GetMetaData(const void *p) { + if (primary_.PointerIsMine(p)) + return primary_.GetMetaData(p); + return secondary_.GetMetaData(p); + } + + void *GetBlockBegin(const void *p) { + if (primary_.PointerIsMine(p)) + return primary_.GetBlockBegin(p); + return secondary_.GetBlockBegin(p); + } + + // This function does the same as GetBlockBegin, but is much faster. + // Must be called with the allocator locked. + void *GetBlockBeginFastLocked(void *p) { + if (primary_.PointerIsMine(p)) + return primary_.GetBlockBegin(p); + return secondary_.GetBlockBeginFastLocked(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 InitCache(AllocatorCache *cache) { + cache->Init(&stats_); + } + + void DestroyCache(AllocatorCache *cache) { + cache->Destroy(&primary_, &stats_); + } + + void SwallowCache(AllocatorCache *cache) { + cache->Drain(&primary_); + } + + void GetStats(AllocatorStatCounters s) const { + stats_.Get(s); + } + + void PrintStats() { + primary_.PrintStats(); + secondary_.PrintStats(); + } + + // ForceLock() and ForceUnlock() are needed to implement Darwin malloc zone + // introspection API. + void ForceLock() SANITIZER_NO_THREAD_SAFETY_ANALYSIS { + primary_.ForceLock(); + secondary_.ForceLock(); + } + + void ForceUnlock() SANITIZER_NO_THREAD_SAFETY_ANALYSIS { + secondary_.ForceUnlock(); + primary_.ForceUnlock(); + } + + // Iterate over all existing chunks. + // The allocator must be locked when calling this function. + void ForEachChunk(ForEachChunkCallback callback, void *arg) { + primary_.ForEachChunk(callback, arg); + secondary_.ForEachChunk(callback, arg); + } + + private: + PrimaryAllocator primary_; + SecondaryAllocator secondary_; + AllocatorGlobalStats stats_; +}; diff --git a/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_allocator_dlsym.h b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_allocator_dlsym.h new file mode 100644 index 0000000000..92b1373ef8 --- /dev/null +++ b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_allocator_dlsym.h @@ -0,0 +1,79 @@ +//===-- sanitizer_allocator_dlsym.h -----------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// Hack: Sanitizer initializer calls dlsym which may need to allocate and call +// back into uninitialized sanitizer. +// +//===----------------------------------------------------------------------===// + +#ifndef SANITIZER_ALLOCATOR_DLSYM_H +#define SANITIZER_ALLOCATOR_DLSYM_H + +#include "sanitizer_allocator_internal.h" + +namespace __sanitizer { + +template <typename Details> +struct DlSymAllocator { + static bool Use() { + // Fuchsia doesn't use dlsym-based interceptors. + return !SANITIZER_FUCHSIA && UNLIKELY(Details::UseImpl()); + } + + static bool PointerIsMine(const void *ptr) { + // Fuchsia doesn't use dlsym-based interceptors. + return !SANITIZER_FUCHSIA && + UNLIKELY(internal_allocator()->FromPrimary(ptr)); + } + + static void *Allocate(uptr size_in_bytes) { + void *ptr = InternalAlloc(size_in_bytes, nullptr, kWordSize); + CHECK(internal_allocator()->FromPrimary(ptr)); + Details::OnAllocate(ptr, + internal_allocator()->GetActuallyAllocatedSize(ptr)); + return ptr; + } + + static void *Callocate(SIZE_T nmemb, SIZE_T size) { + void *ptr = InternalCalloc(nmemb, size); + CHECK(internal_allocator()->FromPrimary(ptr)); + Details::OnAllocate(ptr, + internal_allocator()->GetActuallyAllocatedSize(ptr)); + return ptr; + } + + static void Free(void *ptr) { + uptr size = internal_allocator()->GetActuallyAllocatedSize(ptr); + Details::OnFree(ptr, size); + InternalFree(ptr); + } + + static void *Realloc(void *ptr, uptr new_size) { + if (!ptr) + return Allocate(new_size); + CHECK(internal_allocator()->FromPrimary(ptr)); + if (!new_size) { + Free(ptr); + return nullptr; + } + uptr size = internal_allocator()->GetActuallyAllocatedSize(ptr); + uptr memcpy_size = Min(new_size, size); + void *new_ptr = Allocate(new_size); + if (new_ptr) + internal_memcpy(new_ptr, ptr, memcpy_size); + Free(ptr); + return new_ptr; + } + + static void OnAllocate(const void *ptr, uptr size) {} + static void OnFree(const void *ptr, uptr size) {} +}; + +} // namespace __sanitizer + +#endif // SANITIZER_ALLOCATOR_DLSYM_H diff --git a/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_allocator_interface.h b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_allocator_interface.h new file mode 100644 index 0000000000..c1b27563e2 --- /dev/null +++ b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_allocator_interface.h @@ -0,0 +1,47 @@ +//===-- sanitizer_allocator_interface.h ------------------------- C++ -----===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// Re-declaration of functions from public sanitizer allocator interface. +// +//===----------------------------------------------------------------------===// + +#ifndef SANITIZER_ALLOCATOR_INTERFACE_H +#define SANITIZER_ALLOCATOR_INTERFACE_H + +#include "sanitizer_internal_defs.h" + +using __sanitizer::uptr; + +extern "C" { +SANITIZER_INTERFACE_ATTRIBUTE +uptr __sanitizer_get_estimated_allocated_size(uptr size); +SANITIZER_INTERFACE_ATTRIBUTE int __sanitizer_get_ownership(const void *p); +SANITIZER_INTERFACE_ATTRIBUTE uptr +__sanitizer_get_allocated_size(const void *p); +SANITIZER_INTERFACE_ATTRIBUTE uptr __sanitizer_get_current_allocated_bytes(); +SANITIZER_INTERFACE_ATTRIBUTE uptr __sanitizer_get_heap_size(); +SANITIZER_INTERFACE_ATTRIBUTE uptr __sanitizer_get_free_bytes(); +SANITIZER_INTERFACE_ATTRIBUTE uptr __sanitizer_get_unmapped_bytes(); + +SANITIZER_INTERFACE_ATTRIBUTE int __sanitizer_install_malloc_and_free_hooks( + void (*malloc_hook)(const void *, uptr), + void (*free_hook)(const void *)); + +SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE + void __sanitizer_malloc_hook(void *ptr, uptr size); +SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE + void __sanitizer_free_hook(void *ptr); + +SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE void +__sanitizer_purge_allocator(); + +SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE void +__sanitizer_print_memory_profile(uptr top_percent, uptr max_number_of_contexts); +} // extern "C" + +#endif // SANITIZER_ALLOCATOR_INTERFACE_H diff --git a/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_allocator_internal.h b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_allocator_internal.h new file mode 100644 index 0000000000..3899473687 --- /dev/null +++ b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_allocator_internal.h @@ -0,0 +1,57 @@ +//===-- sanitizer_allocator_internal.h --------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This allocator is used inside run-times. +// +//===----------------------------------------------------------------------===// + +#ifndef SANITIZER_ALLOCATOR_INTERNAL_H +#define SANITIZER_ALLOCATOR_INTERNAL_H + +#include "sanitizer_allocator.h" +#include "sanitizer_internal_defs.h" + +namespace __sanitizer { + +// FIXME: Check if we may use even more compact size class map for internal +// purposes. +typedef CompactSizeClassMap InternalSizeClassMap; + +struct AP32 { + static const uptr kSpaceBeg = 0; + static const u64 kSpaceSize = SANITIZER_MMAP_RANGE_SIZE; + static const uptr kMetadataSize = 0; + typedef InternalSizeClassMap SizeClassMap; + static const uptr kRegionSizeLog = 20; + using AddressSpaceView = LocalAddressSpaceView; + typedef NoOpMapUnmapCallback MapUnmapCallback; + static const uptr kFlags = 0; +}; +typedef SizeClassAllocator32<AP32> PrimaryInternalAllocator; + +typedef CombinedAllocator<PrimaryInternalAllocator, + LargeMmapAllocatorPtrArrayStatic> + InternalAllocator; +typedef InternalAllocator::AllocatorCache InternalAllocatorCache; + +void *InternalAlloc(uptr size, InternalAllocatorCache *cache = nullptr, + uptr alignment = 0); +void *InternalRealloc(void *p, uptr size, + InternalAllocatorCache *cache = nullptr); +void *InternalReallocArray(void *p, uptr count, uptr size, + InternalAllocatorCache *cache = nullptr); +void *InternalCalloc(uptr count, uptr size, + InternalAllocatorCache *cache = nullptr); +void InternalFree(void *p, InternalAllocatorCache *cache = nullptr); +void InternalAllocatorLock(); +void InternalAllocatorUnlock(); +InternalAllocator *internal_allocator(); + +} // namespace __sanitizer + +#endif // SANITIZER_ALLOCATOR_INTERNAL_H diff --git a/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_allocator_local_cache.h b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_allocator_local_cache.h new file mode 100644 index 0000000000..e495c56f03 --- /dev/null +++ b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_allocator_local_cache.h @@ -0,0 +1,271 @@ +//===-- sanitizer_allocator_local_cache.h -----------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// Part of the Sanitizer Allocator. +// +//===----------------------------------------------------------------------===// +#ifndef SANITIZER_ALLOCATOR_H +#error This file must be included inside sanitizer_allocator.h +#endif + +// Cache used by SizeClassAllocator64. +template <class SizeClassAllocator> +struct SizeClassAllocator64LocalCache { + typedef SizeClassAllocator Allocator; + typedef MemoryMapper<Allocator> MemoryMapperT; + + void Init(AllocatorGlobalStats *s) { + stats_.Init(); + if (s) + s->Register(&stats_); + } + + void Destroy(SizeClassAllocator *allocator, AllocatorGlobalStats *s) { + Drain(allocator); + if (s) + s->Unregister(&stats_); + } + + void *Allocate(SizeClassAllocator *allocator, uptr class_id) { + CHECK_NE(class_id, 0UL); + CHECK_LT(class_id, kNumClasses); + PerClass *c = &per_class_[class_id]; + if (UNLIKELY(c->count == 0)) { + if (UNLIKELY(!Refill(c, allocator, class_id))) + return nullptr; + DCHECK_GT(c->count, 0); + } + CompactPtrT chunk = c->chunks[--c->count]; + stats_.Add(AllocatorStatAllocated, c->class_size); + return reinterpret_cast<void *>(allocator->CompactPtrToPointer( + allocator->GetRegionBeginBySizeClass(class_id), chunk)); + } + + void Deallocate(SizeClassAllocator *allocator, uptr class_id, void *p) { + CHECK_NE(class_id, 0UL); + CHECK_LT(class_id, kNumClasses); + // If the first allocator call on a new thread is a deallocation, then + // max_count will be zero, leading to check failure. + PerClass *c = &per_class_[class_id]; + InitCache(c); + if (UNLIKELY(c->count == c->max_count)) + DrainHalfMax(c, allocator, class_id); + CompactPtrT chunk = allocator->PointerToCompactPtr( + allocator->GetRegionBeginBySizeClass(class_id), + reinterpret_cast<uptr>(p)); + c->chunks[c->count++] = chunk; + stats_.Sub(AllocatorStatAllocated, c->class_size); + } + + void Drain(SizeClassAllocator *allocator) { + MemoryMapperT memory_mapper(*allocator); + for (uptr i = 1; i < kNumClasses; i++) { + PerClass *c = &per_class_[i]; + while (c->count > 0) Drain(&memory_mapper, c, allocator, i, c->count); + } + } + + private: + typedef typename Allocator::SizeClassMapT SizeClassMap; + static const uptr kNumClasses = SizeClassMap::kNumClasses; + typedef typename Allocator::CompactPtrT CompactPtrT; + + struct PerClass { + u32 count; + u32 max_count; + uptr class_size; + CompactPtrT chunks[2 * SizeClassMap::kMaxNumCachedHint]; + }; + PerClass per_class_[kNumClasses]; + AllocatorStats stats_; + + void InitCache(PerClass *c) { + if (LIKELY(c->max_count)) + return; + for (uptr i = 1; i < kNumClasses; i++) { + PerClass *c = &per_class_[i]; + const uptr size = Allocator::ClassIdToSize(i); + c->max_count = 2 * SizeClassMap::MaxCachedHint(size); + c->class_size = size; + } + DCHECK_NE(c->max_count, 0UL); + } + + NOINLINE bool Refill(PerClass *c, SizeClassAllocator *allocator, + uptr class_id) { + InitCache(c); + const uptr num_requested_chunks = c->max_count / 2; + if (UNLIKELY(!allocator->GetFromAllocator(&stats_, class_id, c->chunks, + num_requested_chunks))) + return false; + c->count = num_requested_chunks; + return true; + } + + NOINLINE void DrainHalfMax(PerClass *c, SizeClassAllocator *allocator, + uptr class_id) { + MemoryMapperT memory_mapper(*allocator); + Drain(&memory_mapper, c, allocator, class_id, c->max_count / 2); + } + + void Drain(MemoryMapperT *memory_mapper, PerClass *c, + SizeClassAllocator *allocator, uptr class_id, uptr count) { + CHECK_GE(c->count, count); + const uptr first_idx_to_drain = c->count - count; + c->count -= count; + allocator->ReturnToAllocator(memory_mapper, &stats_, class_id, + &c->chunks[first_idx_to_drain], count); + } +}; + +// Cache used by SizeClassAllocator32. +template <class SizeClassAllocator> +struct SizeClassAllocator32LocalCache { + typedef SizeClassAllocator Allocator; + typedef typename Allocator::TransferBatch TransferBatch; + + void Init(AllocatorGlobalStats *s) { + stats_.Init(); + if (s) + s->Register(&stats_); + } + + // Returns a TransferBatch suitable for class_id. + TransferBatch *CreateBatch(uptr class_id, SizeClassAllocator *allocator, + TransferBatch *b) { + if (uptr batch_class_id = per_class_[class_id].batch_class_id) + return (TransferBatch*)Allocate(allocator, batch_class_id); + return b; + } + + // Destroys TransferBatch b. + void DestroyBatch(uptr class_id, SizeClassAllocator *allocator, + TransferBatch *b) { + if (uptr batch_class_id = per_class_[class_id].batch_class_id) + Deallocate(allocator, batch_class_id, b); + } + + void Destroy(SizeClassAllocator *allocator, AllocatorGlobalStats *s) { + Drain(allocator); + if (s) + s->Unregister(&stats_); + } + + void *Allocate(SizeClassAllocator *allocator, uptr class_id) { + CHECK_NE(class_id, 0UL); + CHECK_LT(class_id, kNumClasses); + PerClass *c = &per_class_[class_id]; + if (UNLIKELY(c->count == 0)) { + if (UNLIKELY(!Refill(c, allocator, class_id))) + return nullptr; + DCHECK_GT(c->count, 0); + } + void *res = c->batch[--c->count]; + PREFETCH(c->batch[c->count - 1]); + stats_.Add(AllocatorStatAllocated, c->class_size); + return res; + } + + void Deallocate(SizeClassAllocator *allocator, uptr class_id, void *p) { + CHECK_NE(class_id, 0UL); + CHECK_LT(class_id, kNumClasses); + // If the first allocator call on a new thread is a deallocation, then + // max_count will be zero, leading to check failure. + PerClass *c = &per_class_[class_id]; + InitCache(c); + if (UNLIKELY(c->count == c->max_count)) + Drain(c, allocator, class_id); + c->batch[c->count++] = p; + stats_.Sub(AllocatorStatAllocated, c->class_size); + } + + void Drain(SizeClassAllocator *allocator) { + for (uptr i = 1; i < kNumClasses; i++) { + PerClass *c = &per_class_[i]; + while (c->count > 0) + Drain(c, allocator, i); + } + } + + private: + typedef typename Allocator::SizeClassMapT SizeClassMap; + static const uptr kBatchClassID = SizeClassMap::kBatchClassID; + static const uptr kNumClasses = SizeClassMap::kNumClasses; + // If kUseSeparateSizeClassForBatch is true, all TransferBatch objects are + // allocated from kBatchClassID size class (except for those that are needed + // for kBatchClassID itself). The goal is to have TransferBatches in a totally + // different region of RAM to improve security. + static const bool kUseSeparateSizeClassForBatch = + Allocator::kUseSeparateSizeClassForBatch; + + struct PerClass { + uptr count; + uptr max_count; + uptr class_size; + uptr batch_class_id; + void *batch[2 * TransferBatch::kMaxNumCached]; + }; + PerClass per_class_[kNumClasses]; + AllocatorStats stats_; + + void InitCache(PerClass *c) { + if (LIKELY(c->max_count)) + return; + const uptr batch_class_id = SizeClassMap::ClassID(sizeof(TransferBatch)); + for (uptr i = 1; i < kNumClasses; i++) { + PerClass *c = &per_class_[i]; + const uptr size = Allocator::ClassIdToSize(i); + const uptr max_cached = TransferBatch::MaxCached(size); + c->max_count = 2 * max_cached; + c->class_size = size; + // Precompute the class id to use to store batches for the current class + // id. 0 means the class size is large enough to store a batch within one + // of the chunks. If using a separate size class, it will always be + // kBatchClassID, except for kBatchClassID itself. + if (kUseSeparateSizeClassForBatch) { + c->batch_class_id = (i == kBatchClassID) ? 0 : kBatchClassID; + } else { + c->batch_class_id = (size < + TransferBatch::AllocationSizeRequiredForNElements(max_cached)) ? + batch_class_id : 0; + } + } + DCHECK_NE(c->max_count, 0UL); + } + + NOINLINE bool Refill(PerClass *c, SizeClassAllocator *allocator, + uptr class_id) { + InitCache(c); + TransferBatch *b = allocator->AllocateBatch(&stats_, this, class_id); + if (UNLIKELY(!b)) + return false; + CHECK_GT(b->Count(), 0); + b->CopyToArray(c->batch); + c->count = b->Count(); + DestroyBatch(class_id, allocator, b); + return true; + } + + NOINLINE void Drain(PerClass *c, SizeClassAllocator *allocator, + uptr class_id) { + const uptr count = Min(c->max_count / 2, c->count); + const uptr first_idx_to_drain = c->count - count; + TransferBatch *b = CreateBatch( + class_id, allocator, (TransferBatch *)c->batch[first_idx_to_drain]); + // Failure to allocate a batch while releasing memory is non recoverable. + // TODO(alekseys): Figure out how to do it without allocating a new batch. + if (UNLIKELY(!b)) { + Report("FATAL: Internal error: %s's allocator failed to allocate a " + "transfer batch.\n", SanitizerToolName); + Die(); + } + b->SetFromArray(&c->batch[first_idx_to_drain], count); + c->count -= count; + allocator->DeallocateBatch(&stats_, class_id, b); + } +}; diff --git a/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_allocator_primary32.h b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_allocator_primary32.h new file mode 100644 index 0000000000..f2471efced --- /dev/null +++ b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_allocator_primary32.h @@ -0,0 +1,381 @@ +//===-- sanitizer_allocator_primary32.h -------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// Part of the Sanitizer Allocator. +// +//===----------------------------------------------------------------------===// +#ifndef SANITIZER_ALLOCATOR_H +#error This file must be included inside sanitizer_allocator.h +#endif + +template<class SizeClassAllocator> struct SizeClassAllocator32LocalCache; + +// SizeClassAllocator32 -- allocator for 32-bit address space. +// This allocator can theoretically be used on 64-bit arch, but there it is less +// efficient than SizeClassAllocator64. +// +// [kSpaceBeg, kSpaceBeg + kSpaceSize) is the range of addresses which can +// be returned by MmapOrDie(). +// +// Region: +// a result of a single call to MmapAlignedOrDieOnFatalError(kRegionSize, +// kRegionSize). +// Since the regions are aligned by kRegionSize, there are exactly +// kNumPossibleRegions possible regions in the address space and so we keep +// a ByteMap possible_regions to store the size classes of each Region. +// 0 size class means the region is not used by the allocator. +// +// One Region is used to allocate chunks of a single size class. +// A Region looks like this: +// UserChunk1 .. UserChunkN <gap> MetaChunkN .. MetaChunk1 +// +// In order to avoid false sharing the objects of this class should be +// chache-line aligned. + +struct SizeClassAllocator32FlagMasks { // Bit masks. + enum { + kRandomShuffleChunks = 1, + kUseSeparateSizeClassForBatch = 2, + }; +}; + +template <class Params> +class SizeClassAllocator32 { + private: + static const u64 kTwoLevelByteMapSize1 = + (Params::kSpaceSize >> Params::kRegionSizeLog) >> 12; + static const u64 kMinFirstMapSizeTwoLevelByteMap = 4; + + public: + using AddressSpaceView = typename Params::AddressSpaceView; + static const uptr kSpaceBeg = Params::kSpaceBeg; + static const u64 kSpaceSize = Params::kSpaceSize; + static const uptr kMetadataSize = Params::kMetadataSize; + typedef typename Params::SizeClassMap SizeClassMap; + static const uptr kRegionSizeLog = Params::kRegionSizeLog; + typedef typename Params::MapUnmapCallback MapUnmapCallback; + using ByteMap = typename conditional< + (kTwoLevelByteMapSize1 < kMinFirstMapSizeTwoLevelByteMap), + FlatByteMap<(Params::kSpaceSize >> Params::kRegionSizeLog), + AddressSpaceView>, + TwoLevelByteMap<kTwoLevelByteMapSize1, 1 << 12, AddressSpaceView>>::type; + + COMPILER_CHECK(!SANITIZER_SIGN_EXTENDED_ADDRESSES || + (kSpaceSize & (kSpaceSize - 1)) == 0); + + static const bool kRandomShuffleChunks = Params::kFlags & + SizeClassAllocator32FlagMasks::kRandomShuffleChunks; + static const bool kUseSeparateSizeClassForBatch = Params::kFlags & + SizeClassAllocator32FlagMasks::kUseSeparateSizeClassForBatch; + + struct TransferBatch { + static const uptr kMaxNumCached = SizeClassMap::kMaxNumCachedHint - 2; + void SetFromArray(void *batch[], uptr count) { + DCHECK_LE(count, kMaxNumCached); + count_ = count; + for (uptr i = 0; i < count; i++) + batch_[i] = batch[i]; + } + uptr Count() const { return count_; } + void Clear() { count_ = 0; } + void Add(void *ptr) { + batch_[count_++] = ptr; + DCHECK_LE(count_, kMaxNumCached); + } + void CopyToArray(void *to_batch[]) const { + for (uptr i = 0, n = Count(); i < n; i++) + to_batch[i] = batch_[i]; + } + + // How much memory do we need for a batch containing n elements. + static uptr AllocationSizeRequiredForNElements(uptr n) { + return sizeof(uptr) * 2 + sizeof(void *) * n; + } + static uptr MaxCached(uptr size) { + return Min(kMaxNumCached, SizeClassMap::MaxCachedHint(size)); + } + + TransferBatch *next; + + private: + uptr count_; + void *batch_[kMaxNumCached]; + }; + + static const uptr kBatchSize = sizeof(TransferBatch); + COMPILER_CHECK((kBatchSize & (kBatchSize - 1)) == 0); + COMPILER_CHECK(kBatchSize == SizeClassMap::kMaxNumCachedHint * sizeof(uptr)); + + static uptr ClassIdToSize(uptr class_id) { + return (class_id == SizeClassMap::kBatchClassID) ? + kBatchSize : SizeClassMap::Size(class_id); + } + + typedef SizeClassAllocator32<Params> ThisT; + typedef SizeClassAllocator32LocalCache<ThisT> AllocatorCache; + + void Init(s32 release_to_os_interval_ms, uptr heap_start = 0) { + CHECK(!heap_start); + possible_regions.Init(); + internal_memset(size_class_info_array, 0, sizeof(size_class_info_array)); + } + + s32 ReleaseToOSIntervalMs() const { + return kReleaseToOSIntervalNever; + } + + void SetReleaseToOSIntervalMs(s32 release_to_os_interval_ms) { + // This is empty here. Currently only implemented in 64-bit allocator. + } + + void ForceReleaseToOS() { + // Currently implemented in 64-bit allocator only. + } + + void *MapWithCallback(uptr size) { + void *res = MmapOrDie(size, PrimaryAllocatorName); + MapUnmapCallback().OnMap((uptr)res, size); + return res; + } + + void UnmapWithCallback(uptr beg, uptr size) { + MapUnmapCallback().OnUnmap(beg, size); + UnmapOrDie(reinterpret_cast<void *>(beg), size); + } + + static bool CanAllocate(uptr size, uptr alignment) { + return size <= SizeClassMap::kMaxSize && + alignment <= SizeClassMap::kMaxSize; + } + + void *GetMetaData(const void *p) { + CHECK(kMetadataSize); + CHECK(PointerIsMine(p)); + uptr mem = reinterpret_cast<uptr>(p); + uptr beg = ComputeRegionBeg(mem); + uptr size = ClassIdToSize(GetSizeClass(p)); + u32 offset = mem - beg; + uptr n = offset / (u32)size; // 32-bit division + uptr meta = (beg + kRegionSize) - (n + 1) * kMetadataSize; + return reinterpret_cast<void*>(meta); + } + + NOINLINE TransferBatch *AllocateBatch(AllocatorStats *stat, AllocatorCache *c, + uptr class_id) { + DCHECK_LT(class_id, kNumClasses); + SizeClassInfo *sci = GetSizeClassInfo(class_id); + SpinMutexLock l(&sci->mutex); + if (sci->free_list.empty()) { + if (UNLIKELY(!PopulateFreeList(stat, c, sci, class_id))) + return nullptr; + DCHECK(!sci->free_list.empty()); + } + TransferBatch *b = sci->free_list.front(); + sci->free_list.pop_front(); + return b; + } + + NOINLINE void DeallocateBatch(AllocatorStats *stat, uptr class_id, + TransferBatch *b) { + DCHECK_LT(class_id, kNumClasses); + CHECK_GT(b->Count(), 0); + SizeClassInfo *sci = GetSizeClassInfo(class_id); + SpinMutexLock l(&sci->mutex); + sci->free_list.push_front(b); + } + + bool PointerIsMine(const void *p) const { + uptr mem = reinterpret_cast<uptr>(p); + if (SANITIZER_SIGN_EXTENDED_ADDRESSES) + mem &= (kSpaceSize - 1); + if (mem < kSpaceBeg || mem >= kSpaceBeg + kSpaceSize) + return false; + return GetSizeClass(p) != 0; + } + + uptr GetSizeClass(const void *p) const { + uptr id = ComputeRegionId(reinterpret_cast<uptr>(p)); + return possible_regions.contains(id) ? possible_regions[id] : 0; + } + + void *GetBlockBegin(const void *p) { + CHECK(PointerIsMine(p)); + uptr mem = reinterpret_cast<uptr>(p); + uptr beg = ComputeRegionBeg(mem); + uptr size = ClassIdToSize(GetSizeClass(p)); + u32 offset = mem - beg; + u32 n = offset / (u32)size; // 32-bit division + uptr res = beg + (n * (u32)size); + return reinterpret_cast<void*>(res); + } + + uptr GetActuallyAllocatedSize(void *p) { + CHECK(PointerIsMine(p)); + return ClassIdToSize(GetSizeClass(p)); + } + + static uptr ClassID(uptr size) { return SizeClassMap::ClassID(size); } + + uptr TotalMemoryUsed() { + // No need to lock here. + uptr res = 0; + for (uptr i = 0; i < kNumPossibleRegions; i++) + if (possible_regions[i]) + res += kRegionSize; + return res; + } + + void TestOnlyUnmap() { + for (uptr i = 0; i < kNumPossibleRegions; i++) + if (possible_regions[i]) + UnmapWithCallback((i * kRegionSize), kRegionSize); + } + + // ForceLock() and ForceUnlock() are needed to implement Darwin malloc zone + // introspection API. + void ForceLock() SANITIZER_NO_THREAD_SAFETY_ANALYSIS { + for (uptr i = 0; i < kNumClasses; i++) { + GetSizeClassInfo(i)->mutex.Lock(); + } + } + + void ForceUnlock() SANITIZER_NO_THREAD_SAFETY_ANALYSIS { + for (int i = kNumClasses - 1; i >= 0; i--) { + GetSizeClassInfo(i)->mutex.Unlock(); + } + } + + // Iterate over all existing chunks. + // The allocator must be locked when calling this function. + void ForEachChunk(ForEachChunkCallback callback, void *arg) const { + for (uptr region = 0; region < kNumPossibleRegions; region++) + if (possible_regions.contains(region) && possible_regions[region]) { + uptr chunk_size = ClassIdToSize(possible_regions[region]); + uptr max_chunks_in_region = kRegionSize / (chunk_size + kMetadataSize); + uptr region_beg = region * kRegionSize; + for (uptr chunk = region_beg; + chunk < region_beg + max_chunks_in_region * chunk_size; + chunk += chunk_size) { + // Too slow: CHECK_EQ((void *)chunk, GetBlockBegin((void *)chunk)); + callback(chunk, arg); + } + } + } + + void PrintStats() {} + + static uptr AdditionalSize() { return 0; } + + typedef SizeClassMap SizeClassMapT; + static const uptr kNumClasses = SizeClassMap::kNumClasses; + + private: + static const uptr kRegionSize = 1 << kRegionSizeLog; + static const uptr kNumPossibleRegions = kSpaceSize / kRegionSize; + + struct ALIGNED(SANITIZER_CACHE_LINE_SIZE) SizeClassInfo { + StaticSpinMutex mutex; + IntrusiveList<TransferBatch> free_list; + u32 rand_state; + }; + COMPILER_CHECK(sizeof(SizeClassInfo) % kCacheLineSize == 0); + + uptr ComputeRegionId(uptr mem) const { + if (SANITIZER_SIGN_EXTENDED_ADDRESSES) + mem &= (kSpaceSize - 1); + const uptr res = mem >> kRegionSizeLog; + CHECK_LT(res, kNumPossibleRegions); + return res; + } + + uptr ComputeRegionBeg(uptr mem) const { return mem & ~(kRegionSize - 1); } + + uptr AllocateRegion(AllocatorStats *stat, uptr class_id) { + DCHECK_LT(class_id, kNumClasses); + const uptr res = reinterpret_cast<uptr>(MmapAlignedOrDieOnFatalError( + kRegionSize, kRegionSize, PrimaryAllocatorName)); + if (UNLIKELY(!res)) + return 0; + MapUnmapCallback().OnMap(res, kRegionSize); + stat->Add(AllocatorStatMapped, kRegionSize); + CHECK(IsAligned(res, kRegionSize)); + possible_regions[ComputeRegionId(res)] = class_id; + return res; + } + + SizeClassInfo *GetSizeClassInfo(uptr class_id) { + DCHECK_LT(class_id, kNumClasses); + return &size_class_info_array[class_id]; + } + + bool PopulateBatches(AllocatorCache *c, SizeClassInfo *sci, uptr class_id, + TransferBatch **current_batch, uptr max_count, + uptr *pointers_array, uptr count) { + // If using a separate class for batches, we do not need to shuffle it. + if (kRandomShuffleChunks && (!kUseSeparateSizeClassForBatch || + class_id != SizeClassMap::kBatchClassID)) + RandomShuffle(pointers_array, count, &sci->rand_state); + TransferBatch *b = *current_batch; + for (uptr i = 0; i < count; i++) { + if (!b) { + b = c->CreateBatch(class_id, this, (TransferBatch*)pointers_array[i]); + if (UNLIKELY(!b)) + return false; + b->Clear(); + } + b->Add((void*)pointers_array[i]); + if (b->Count() == max_count) { + sci->free_list.push_back(b); + b = nullptr; + } + } + *current_batch = b; + return true; + } + + bool PopulateFreeList(AllocatorStats *stat, AllocatorCache *c, + SizeClassInfo *sci, uptr class_id) { + const uptr region = AllocateRegion(stat, class_id); + if (UNLIKELY(!region)) + return false; + if (kRandomShuffleChunks) + if (UNLIKELY(sci->rand_state == 0)) + // The random state is initialized from ASLR (PIE) and time. + sci->rand_state = reinterpret_cast<uptr>(sci) ^ NanoTime(); + const uptr size = ClassIdToSize(class_id); + const uptr n_chunks = kRegionSize / (size + kMetadataSize); + const uptr max_count = TransferBatch::MaxCached(size); + DCHECK_GT(max_count, 0); + TransferBatch *b = nullptr; + constexpr uptr kShuffleArraySize = 48; + uptr shuffle_array[kShuffleArraySize]; + uptr count = 0; + for (uptr i = region; i < region + n_chunks * size; i += size) { + shuffle_array[count++] = i; + if (count == kShuffleArraySize) { + if (UNLIKELY(!PopulateBatches(c, sci, class_id, &b, max_count, + shuffle_array, count))) + return false; + count = 0; + } + } + if (count) { + if (UNLIKELY(!PopulateBatches(c, sci, class_id, &b, max_count, + shuffle_array, count))) + return false; + } + if (b) { + CHECK_GT(b->Count(), 0); + sci->free_list.push_back(b); + } + return true; + } + + ByteMap possible_regions; + SizeClassInfo size_class_info_array[kNumClasses]; +}; diff --git a/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_allocator_primary64.h b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_allocator_primary64.h new file mode 100644 index 0000000000..66ba71d325 --- /dev/null +++ b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_allocator_primary64.h @@ -0,0 +1,898 @@ +//===-- sanitizer_allocator_primary64.h -------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// Part of the Sanitizer Allocator. +// +//===----------------------------------------------------------------------===// +#ifndef SANITIZER_ALLOCATOR_H +#error This file must be included inside sanitizer_allocator.h +#endif + +template<class SizeClassAllocator> struct SizeClassAllocator64LocalCache; + +// SizeClassAllocator64 -- allocator for 64-bit address space. +// The template parameter Params is a class containing the actual parameters. +// +// Space: a portion of address space of kSpaceSize bytes starting at SpaceBeg. +// If kSpaceBeg is ~0 then SpaceBeg is chosen dynamically by mmap. +// Otherwise SpaceBeg=kSpaceBeg (fixed address). +// kSpaceSize is a power of two. +// At the beginning the entire space is mprotect-ed, then small parts of it +// are mapped on demand. +// +// 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. + +// FreeArray is an array free-d chunks (stored as 4-byte offsets) +// +// A Region looks like this: +// UserChunk1 ... UserChunkN <gap> MetaChunkN ... MetaChunk1 FreeArray + +struct SizeClassAllocator64FlagMasks { // Bit masks. + enum { + kRandomShuffleChunks = 1, + }; +}; + +template <typename Allocator> +class MemoryMapper { + public: + typedef typename Allocator::CompactPtrT CompactPtrT; + + explicit MemoryMapper(const Allocator &allocator) : allocator_(allocator) {} + + bool GetAndResetStats(uptr &ranges, uptr &bytes) { + ranges = released_ranges_count_; + released_ranges_count_ = 0; + bytes = released_bytes_; + released_bytes_ = 0; + return ranges != 0; + } + + u64 *MapPackedCounterArrayBuffer(uptr count) { + buffer_.clear(); + buffer_.resize(count); + return buffer_.data(); + } + + // Releases [from, to) range of pages back to OS. + void ReleasePageRangeToOS(uptr class_id, CompactPtrT from, CompactPtrT to) { + const uptr region_base = allocator_.GetRegionBeginBySizeClass(class_id); + const uptr from_page = allocator_.CompactPtrToPointer(region_base, from); + const uptr to_page = allocator_.CompactPtrToPointer(region_base, to); + ReleaseMemoryPagesToOS(from_page, to_page); + released_ranges_count_++; + released_bytes_ += to_page - from_page; + } + + private: + const Allocator &allocator_; + uptr released_ranges_count_ = 0; + uptr released_bytes_ = 0; + InternalMmapVector<u64> buffer_; +}; + +template <class Params> +class SizeClassAllocator64 { + public: + using AddressSpaceView = typename Params::AddressSpaceView; + static const uptr kSpaceBeg = Params::kSpaceBeg; + static const uptr kSpaceSize = Params::kSpaceSize; + static const uptr kMetadataSize = Params::kMetadataSize; + typedef typename Params::SizeClassMap SizeClassMap; + typedef typename Params::MapUnmapCallback MapUnmapCallback; + + static const bool kRandomShuffleChunks = + Params::kFlags & SizeClassAllocator64FlagMasks::kRandomShuffleChunks; + + typedef SizeClassAllocator64<Params> ThisT; + typedef SizeClassAllocator64LocalCache<ThisT> AllocatorCache; + typedef MemoryMapper<ThisT> MemoryMapperT; + + // When we know the size class (the region base) we can represent a pointer + // as a 4-byte integer (offset from the region start shifted right by 4). + typedef u32 CompactPtrT; + static const uptr kCompactPtrScale = 4; + CompactPtrT PointerToCompactPtr(uptr base, uptr ptr) const { + return static_cast<CompactPtrT>((ptr - base) >> kCompactPtrScale); + } + uptr CompactPtrToPointer(uptr base, CompactPtrT ptr32) const { + return base + (static_cast<uptr>(ptr32) << kCompactPtrScale); + } + + // If heap_start is nonzero, assumes kSpaceSize bytes are already mapped R/W + // at heap_start and places the heap there. This mode requires kSpaceBeg == + // ~(uptr)0. + void Init(s32 release_to_os_interval_ms, uptr heap_start = 0) { + uptr TotalSpaceSize = kSpaceSize + AdditionalSize(); + PremappedHeap = heap_start != 0; + if (PremappedHeap) { + CHECK(!kUsingConstantSpaceBeg); + NonConstSpaceBeg = heap_start; + uptr RegionInfoSize = AdditionalSize(); + RegionInfoSpace = + address_range.Init(RegionInfoSize, PrimaryAllocatorName); + CHECK_NE(RegionInfoSpace, ~(uptr)0); + CHECK_EQ(RegionInfoSpace, + address_range.MapOrDie(RegionInfoSpace, RegionInfoSize, + "SizeClassAllocator: region info")); + MapUnmapCallback().OnMap(RegionInfoSpace, RegionInfoSize); + } else { + if (kUsingConstantSpaceBeg) { + CHECK(IsAligned(kSpaceBeg, SizeClassMap::kMaxSize)); + CHECK_EQ(kSpaceBeg, + address_range.Init(TotalSpaceSize, PrimaryAllocatorName, + kSpaceBeg)); + } else { + // Combined allocator expects that an 2^N allocation is always aligned + // to 2^N. For this to work, the start of the space needs to be aligned + // as high as the largest size class (which also needs to be a power of + // 2). + NonConstSpaceBeg = address_range.InitAligned( + TotalSpaceSize, SizeClassMap::kMaxSize, PrimaryAllocatorName); + CHECK_NE(NonConstSpaceBeg, ~(uptr)0); + } + RegionInfoSpace = SpaceEnd(); + MapWithCallbackOrDie(RegionInfoSpace, AdditionalSize(), + "SizeClassAllocator: region info"); + } + SetReleaseToOSIntervalMs(release_to_os_interval_ms); + // Check that the RegionInfo array is aligned on the CacheLine size. + DCHECK_EQ(RegionInfoSpace % kCacheLineSize, 0); + } + + s32 ReleaseToOSIntervalMs() const { + return atomic_load(&release_to_os_interval_ms_, memory_order_relaxed); + } + + void SetReleaseToOSIntervalMs(s32 release_to_os_interval_ms) { + atomic_store(&release_to_os_interval_ms_, release_to_os_interval_ms, + memory_order_relaxed); + } + + void ForceReleaseToOS() { + MemoryMapperT memory_mapper(*this); + for (uptr class_id = 1; class_id < kNumClasses; class_id++) { + Lock l(&GetRegionInfo(class_id)->mutex); + MaybeReleaseToOS(&memory_mapper, class_id, true /*force*/); + } + } + + static bool CanAllocate(uptr size, uptr alignment) { + return size <= SizeClassMap::kMaxSize && + alignment <= SizeClassMap::kMaxSize; + } + + NOINLINE void ReturnToAllocator(MemoryMapperT *memory_mapper, + AllocatorStats *stat, uptr class_id, + const CompactPtrT *chunks, uptr n_chunks) { + RegionInfo *region = GetRegionInfo(class_id); + uptr region_beg = GetRegionBeginBySizeClass(class_id); + CompactPtrT *free_array = GetFreeArray(region_beg); + + Lock l(®ion->mutex); + uptr old_num_chunks = region->num_freed_chunks; + uptr new_num_freed_chunks = old_num_chunks + n_chunks; + // Failure to allocate free array space while releasing memory is non + // recoverable. + if (UNLIKELY(!EnsureFreeArraySpace(region, region_beg, + new_num_freed_chunks))) { + Report("FATAL: Internal error: %s's allocator exhausted the free list " + "space for size class %zd (%zd bytes).\n", SanitizerToolName, + class_id, ClassIdToSize(class_id)); + Die(); + } + for (uptr i = 0; i < n_chunks; i++) + free_array[old_num_chunks + i] = chunks[i]; + region->num_freed_chunks = new_num_freed_chunks; + region->stats.n_freed += n_chunks; + + MaybeReleaseToOS(memory_mapper, class_id, false /*force*/); + } + + NOINLINE bool GetFromAllocator(AllocatorStats *stat, uptr class_id, + CompactPtrT *chunks, uptr n_chunks) { + RegionInfo *region = GetRegionInfo(class_id); + uptr region_beg = GetRegionBeginBySizeClass(class_id); + CompactPtrT *free_array = GetFreeArray(region_beg); + + Lock l(®ion->mutex); +#if SANITIZER_WINDOWS + /* On Windows unmapping of memory during __sanitizer_purge_allocator is + explicit and immediate, so unmapped regions must be explicitly mapped back + in when they are accessed again. */ + if (region->rtoi.last_released_bytes > 0) { + MmapFixedOrDie(region_beg, region->mapped_user, + "SizeClassAllocator: region data"); + region->rtoi.n_freed_at_last_release = 0; + region->rtoi.last_released_bytes = 0; + } +#endif + if (UNLIKELY(region->num_freed_chunks < n_chunks)) { + if (UNLIKELY(!PopulateFreeArray(stat, class_id, region, + n_chunks - region->num_freed_chunks))) + return false; + CHECK_GE(region->num_freed_chunks, n_chunks); + } + region->num_freed_chunks -= n_chunks; + uptr base_idx = region->num_freed_chunks; + for (uptr i = 0; i < n_chunks; i++) + chunks[i] = free_array[base_idx + i]; + region->stats.n_allocated += n_chunks; + return true; + } + + bool PointerIsMine(const void *p) const { + uptr P = reinterpret_cast<uptr>(p); + if (kUsingConstantSpaceBeg && (kSpaceBeg % kSpaceSize) == 0) + return P / kSpaceSize == kSpaceBeg / kSpaceSize; + return P >= SpaceBeg() && P < SpaceEnd(); + } + + uptr GetRegionBegin(const void *p) { + if (kUsingConstantSpaceBeg) + return reinterpret_cast<uptr>(p) & ~(kRegionSize - 1); + uptr space_beg = SpaceBeg(); + return ((reinterpret_cast<uptr>(p) - space_beg) & ~(kRegionSize - 1)) + + space_beg; + } + + uptr GetRegionBeginBySizeClass(uptr class_id) const { + return SpaceBeg() + kRegionSize * class_id; + } + + uptr GetSizeClass(const void *p) { + if (kUsingConstantSpaceBeg && (kSpaceBeg % kSpaceSize) == 0) + return ((reinterpret_cast<uptr>(p)) / kRegionSize) % kNumClassesRounded; + return ((reinterpret_cast<uptr>(p) - SpaceBeg()) / kRegionSize) % + kNumClassesRounded; + } + + void *GetBlockBegin(const void *p) { + uptr class_id = GetSizeClass(p); + if (class_id >= kNumClasses) return nullptr; + uptr size = ClassIdToSize(class_id); + if (!size) return nullptr; + uptr chunk_idx = GetChunkIdx((uptr)p, size); + uptr reg_beg = GetRegionBegin(p); + uptr beg = chunk_idx * size; + uptr next_beg = beg + size; + const RegionInfo *region = AddressSpaceView::Load(GetRegionInfo(class_id)); + if (region->mapped_user >= next_beg) + return reinterpret_cast<void*>(reg_beg + beg); + return nullptr; + } + + uptr GetActuallyAllocatedSize(void *p) { + CHECK(PointerIsMine(p)); + return ClassIdToSize(GetSizeClass(p)); + } + + static uptr ClassID(uptr size) { return SizeClassMap::ClassID(size); } + + void *GetMetaData(const void *p) { + CHECK(kMetadataSize); + uptr class_id = GetSizeClass(p); + uptr size = ClassIdToSize(class_id); + if (!size) + return nullptr; + uptr chunk_idx = GetChunkIdx(reinterpret_cast<uptr>(p), size); + uptr region_beg = GetRegionBeginBySizeClass(class_id); + return reinterpret_cast<void *>(GetMetadataEnd(region_beg) - + (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() { + UnmapWithCallbackOrDie((uptr)address_range.base(), address_range.size()); + } + + static void FillMemoryProfile(uptr start, uptr rss, bool file, uptr *stats) { + for (uptr class_id = 0; class_id < kNumClasses; class_id++) + if (stats[class_id] == start) + stats[class_id] = rss; + } + + void PrintStats(uptr class_id, uptr rss) { + RegionInfo *region = GetRegionInfo(class_id); + if (region->mapped_user == 0) return; + uptr in_use = region->stats.n_allocated - region->stats.n_freed; + uptr avail_chunks = region->allocated_user / ClassIdToSize(class_id); + Printf( + "%s %02zd (%6zd): mapped: %6zdK allocs: %7zd frees: %7zd inuse: %6zd " + "num_freed_chunks %7zd avail: %6zd rss: %6zdK releases: %6zd " + "last released: %6lldK region: 0x%zx\n", + region->exhausted ? "F" : " ", class_id, ClassIdToSize(class_id), + region->mapped_user >> 10, region->stats.n_allocated, + region->stats.n_freed, in_use, region->num_freed_chunks, avail_chunks, + rss >> 10, region->rtoi.num_releases, + region->rtoi.last_released_bytes >> 10, + SpaceBeg() + kRegionSize * class_id); + } + + void PrintStats() { + uptr rss_stats[kNumClasses]; + for (uptr class_id = 0; class_id < kNumClasses; class_id++) + rss_stats[class_id] = SpaceBeg() + kRegionSize * class_id; + GetMemoryProfile(FillMemoryProfile, rss_stats); + + uptr total_mapped = 0; + uptr total_rss = 0; + uptr n_allocated = 0; + uptr n_freed = 0; + for (uptr class_id = 1; class_id < kNumClasses; class_id++) { + RegionInfo *region = GetRegionInfo(class_id); + if (region->mapped_user != 0) { + total_mapped += region->mapped_user; + total_rss += rss_stats[class_id]; + } + n_allocated += region->stats.n_allocated; + n_freed += region->stats.n_freed; + } + + Printf("Stats: SizeClassAllocator64: %zdM mapped (%zdM rss) in " + "%zd allocations; remains %zd\n", total_mapped >> 20, + total_rss >> 20, n_allocated, n_allocated - n_freed); + for (uptr class_id = 1; class_id < kNumClasses; class_id++) + PrintStats(class_id, rss_stats[class_id]); + } + + // ForceLock() and ForceUnlock() are needed to implement Darwin malloc zone + // introspection API. + void ForceLock() SANITIZER_NO_THREAD_SAFETY_ANALYSIS { + for (uptr i = 0; i < kNumClasses; i++) { + GetRegionInfo(i)->mutex.Lock(); + } + } + + void ForceUnlock() SANITIZER_NO_THREAD_SAFETY_ANALYSIS { + for (int i = (int)kNumClasses - 1; i >= 0; i--) { + GetRegionInfo(i)->mutex.Unlock(); + } + } + + // Iterate over all existing chunks. + // The allocator must be locked when calling this function. + void ForEachChunk(ForEachChunkCallback callback, void *arg) { + for (uptr class_id = 1; class_id < kNumClasses; class_id++) { + RegionInfo *region = GetRegionInfo(class_id); + uptr chunk_size = ClassIdToSize(class_id); + uptr region_beg = SpaceBeg() + class_id * kRegionSize; + uptr region_allocated_user_size = + AddressSpaceView::Load(region)->allocated_user; + for (uptr chunk = region_beg; + chunk < region_beg + region_allocated_user_size; + chunk += chunk_size) { + // Too slow: CHECK_EQ((void *)chunk, GetBlockBegin((void *)chunk)); + callback(chunk, arg); + } + } + } + + static uptr ClassIdToSize(uptr class_id) { + return SizeClassMap::Size(class_id); + } + + static uptr AdditionalSize() { + return RoundUpTo(sizeof(RegionInfo) * kNumClassesRounded, + GetPageSizeCached()); + } + + typedef SizeClassMap SizeClassMapT; + static const uptr kNumClasses = SizeClassMap::kNumClasses; + static const uptr kNumClassesRounded = SizeClassMap::kNumClassesRounded; + + // A packed array of counters. Each counter occupies 2^n bits, enough to store + // counter's max_value. Ctor will try to allocate the required buffer via + // mapper->MapPackedCounterArrayBuffer and the caller is expected to check + // whether the initialization was successful by checking IsAllocated() result. + // For the performance sake, none of the accessors check the validity of the + // arguments, it is assumed that index is always in [0, n) range and the value + // is not incremented past max_value. + class PackedCounterArray { + public: + template <typename MemoryMapper> + PackedCounterArray(u64 num_counters, u64 max_value, MemoryMapper *mapper) + : n(num_counters) { + CHECK_GT(num_counters, 0); + CHECK_GT(max_value, 0); + constexpr u64 kMaxCounterBits = sizeof(*buffer) * 8ULL; + // Rounding counter storage size up to the power of two allows for using + // bit shifts calculating particular counter's index and offset. + uptr counter_size_bits = + RoundUpToPowerOfTwo(MostSignificantSetBitIndex(max_value) + 1); + CHECK_LE(counter_size_bits, kMaxCounterBits); + counter_size_bits_log = Log2(counter_size_bits); + counter_mask = ~0ULL >> (kMaxCounterBits - counter_size_bits); + + uptr packing_ratio = kMaxCounterBits >> counter_size_bits_log; + CHECK_GT(packing_ratio, 0); + packing_ratio_log = Log2(packing_ratio); + bit_offset_mask = packing_ratio - 1; + + buffer = mapper->MapPackedCounterArrayBuffer( + RoundUpTo(n, 1ULL << packing_ratio_log) >> packing_ratio_log); + } + + bool IsAllocated() const { + return !!buffer; + } + + u64 GetCount() const { + return n; + } + + uptr Get(uptr i) const { + DCHECK_LT(i, n); + uptr index = i >> packing_ratio_log; + uptr bit_offset = (i & bit_offset_mask) << counter_size_bits_log; + return (buffer[index] >> bit_offset) & counter_mask; + } + + void Inc(uptr i) const { + DCHECK_LT(Get(i), counter_mask); + uptr index = i >> packing_ratio_log; + uptr bit_offset = (i & bit_offset_mask) << counter_size_bits_log; + buffer[index] += 1ULL << bit_offset; + } + + void IncRange(uptr from, uptr to) const { + DCHECK_LE(from, to); + for (uptr i = from; i <= to; i++) + Inc(i); + } + + private: + const u64 n; + u64 counter_size_bits_log; + u64 counter_mask; + u64 packing_ratio_log; + u64 bit_offset_mask; + u64* buffer; + }; + + template <class MemoryMapperT> + class FreePagesRangeTracker { + public: + FreePagesRangeTracker(MemoryMapperT *mapper, uptr class_id) + : memory_mapper(mapper), + class_id(class_id), + page_size_scaled_log(Log2(GetPageSizeCached() >> kCompactPtrScale)) {} + + void NextPage(bool freed) { + if (freed) { + if (!in_the_range) { + current_range_start_page = current_page; + in_the_range = true; + } + } else { + CloseOpenedRange(); + } + current_page++; + } + + void Done() { + CloseOpenedRange(); + } + + private: + void CloseOpenedRange() { + if (in_the_range) { + memory_mapper->ReleasePageRangeToOS( + class_id, current_range_start_page << page_size_scaled_log, + current_page << page_size_scaled_log); + in_the_range = false; + } + } + + MemoryMapperT *const memory_mapper = nullptr; + const uptr class_id = 0; + const uptr page_size_scaled_log = 0; + bool in_the_range = false; + uptr current_page = 0; + uptr current_range_start_page = 0; + }; + + // Iterates over the free_array to identify memory pages containing freed + // chunks only and returns these pages back to OS. + // allocated_pages_count is the total number of pages allocated for the + // current bucket. + template <typename MemoryMapper> + static void ReleaseFreeMemoryToOS(CompactPtrT *free_array, + uptr free_array_count, uptr chunk_size, + uptr allocated_pages_count, + MemoryMapper *memory_mapper, + uptr class_id) { + const uptr page_size = GetPageSizeCached(); + + // Figure out the number of chunks per page and whether we can take a fast + // path (the number of chunks per page is the same for all pages). + uptr full_pages_chunk_count_max; + bool same_chunk_count_per_page; + if (chunk_size <= page_size && page_size % chunk_size == 0) { + // Same number of chunks per page, no cross overs. + full_pages_chunk_count_max = page_size / chunk_size; + same_chunk_count_per_page = true; + } else if (chunk_size <= page_size && page_size % chunk_size != 0 && + chunk_size % (page_size % chunk_size) == 0) { + // Some chunks are crossing page boundaries, which means that the page + // contains one or two partial chunks, but all pages contain the same + // number of chunks. + full_pages_chunk_count_max = page_size / chunk_size + 1; + same_chunk_count_per_page = true; + } else if (chunk_size <= page_size) { + // Some chunks are crossing page boundaries, which means that the page + // contains one or two partial chunks. + full_pages_chunk_count_max = page_size / chunk_size + 2; + same_chunk_count_per_page = false; + } else if (chunk_size > page_size && chunk_size % page_size == 0) { + // One chunk covers multiple pages, no cross overs. + full_pages_chunk_count_max = 1; + same_chunk_count_per_page = true; + } else if (chunk_size > page_size) { + // One chunk covers multiple pages, Some chunks are crossing page + // boundaries. Some pages contain one chunk, some contain two. + full_pages_chunk_count_max = 2; + same_chunk_count_per_page = false; + } else { + UNREACHABLE("All chunk_size/page_size ratios must be handled."); + } + + PackedCounterArray counters(allocated_pages_count, + full_pages_chunk_count_max, memory_mapper); + if (!counters.IsAllocated()) + return; + + const uptr chunk_size_scaled = chunk_size >> kCompactPtrScale; + const uptr page_size_scaled = page_size >> kCompactPtrScale; + const uptr page_size_scaled_log = Log2(page_size_scaled); + + // Iterate over free chunks and count how many free chunks affect each + // allocated page. + if (chunk_size <= page_size && page_size % chunk_size == 0) { + // Each chunk affects one page only. + for (uptr i = 0; i < free_array_count; i++) + counters.Inc(free_array[i] >> page_size_scaled_log); + } else { + // In all other cases chunks might affect more than one page. + for (uptr i = 0; i < free_array_count; i++) { + counters.IncRange( + free_array[i] >> page_size_scaled_log, + (free_array[i] + chunk_size_scaled - 1) >> page_size_scaled_log); + } + } + + // Iterate over pages detecting ranges of pages with chunk counters equal + // to the expected number of chunks for the particular page. + FreePagesRangeTracker<MemoryMapper> range_tracker(memory_mapper, class_id); + if (same_chunk_count_per_page) { + // Fast path, every page has the same number of chunks affecting it. + for (uptr i = 0; i < counters.GetCount(); i++) + range_tracker.NextPage(counters.Get(i) == full_pages_chunk_count_max); + } else { + // Show path, go through the pages keeping count how many chunks affect + // each page. + const uptr pn = + chunk_size < page_size ? page_size_scaled / chunk_size_scaled : 1; + const uptr pnc = pn * chunk_size_scaled; + // The idea is to increment the current page pointer by the first chunk + // size, middle portion size (the portion of the page covered by chunks + // except the first and the last one) and then the last chunk size, adding + // up the number of chunks on the current page and checking on every step + // whether the page boundary was crossed. + uptr prev_page_boundary = 0; + uptr current_boundary = 0; + for (uptr i = 0; i < counters.GetCount(); i++) { + uptr page_boundary = prev_page_boundary + page_size_scaled; + uptr chunks_per_page = pn; + if (current_boundary < page_boundary) { + if (current_boundary > prev_page_boundary) + chunks_per_page++; + current_boundary += pnc; + if (current_boundary < page_boundary) { + chunks_per_page++; + current_boundary += chunk_size_scaled; + } + } + prev_page_boundary = page_boundary; + + range_tracker.NextPage(counters.Get(i) == chunks_per_page); + } + } + range_tracker.Done(); + } + + private: + friend class MemoryMapper<ThisT>; + + ReservedAddressRange address_range; + + static const uptr kRegionSize = kSpaceSize / kNumClassesRounded; + // FreeArray is the array of free-d chunks (stored as 4-byte offsets). + // In the worst case it may require kRegionSize/SizeClassMap::kMinSize + // elements, but in reality this will not happen. For simplicity we + // dedicate 1/8 of the region's virtual space to FreeArray. + static const uptr kFreeArraySize = kRegionSize / 8; + + static const bool kUsingConstantSpaceBeg = kSpaceBeg != ~(uptr)0; + uptr NonConstSpaceBeg; + uptr SpaceBeg() const { + return kUsingConstantSpaceBeg ? kSpaceBeg : NonConstSpaceBeg; + } + uptr SpaceEnd() const { return SpaceBeg() + kSpaceSize; } + // kRegionSize must be >= 2^32. + COMPILER_CHECK((kRegionSize) >= (1ULL << (SANITIZER_WORDSIZE / 2))); + // kRegionSize must be <= 2^36, see CompactPtrT. + COMPILER_CHECK((kRegionSize) <= (1ULL << (SANITIZER_WORDSIZE / 2 + 4))); + // Call mmap for user memory with at least this size. + static const uptr kUserMapSize = 1 << 16; + // Call mmap for metadata memory with at least this size. + static const uptr kMetaMapSize = 1 << 16; + // Call mmap for free array memory with at least this size. + static const uptr kFreeArrayMapSize = 1 << 16; + + atomic_sint32_t release_to_os_interval_ms_; + + uptr RegionInfoSpace; + + // True if the user has already mapped the entire heap R/W. + bool PremappedHeap; + + struct Stats { + uptr n_allocated; + uptr n_freed; + }; + + struct ReleaseToOsInfo { + uptr n_freed_at_last_release; + uptr num_releases; + u64 last_release_at_ns; + u64 last_released_bytes; + }; + + struct ALIGNED(SANITIZER_CACHE_LINE_SIZE) RegionInfo { + Mutex mutex; + uptr num_freed_chunks; // Number of elements in the freearray. + uptr mapped_free_array; // Bytes mapped for freearray. + uptr allocated_user; // Bytes allocated for user memory. + uptr allocated_meta; // Bytes allocated for metadata. + uptr mapped_user; // Bytes mapped for user memory. + uptr mapped_meta; // Bytes mapped for metadata. + u32 rand_state; // Seed for random shuffle, used if kRandomShuffleChunks. + bool exhausted; // Whether region is out of space for new chunks. + Stats stats; + ReleaseToOsInfo rtoi; + }; + COMPILER_CHECK(sizeof(RegionInfo) % kCacheLineSize == 0); + + RegionInfo *GetRegionInfo(uptr class_id) const { + DCHECK_LT(class_id, kNumClasses); + RegionInfo *regions = reinterpret_cast<RegionInfo *>(RegionInfoSpace); + return ®ions[class_id]; + } + + uptr GetMetadataEnd(uptr region_beg) const { + return region_beg + kRegionSize - kFreeArraySize; + } + + uptr GetChunkIdx(uptr chunk, uptr size) const { + if (!kUsingConstantSpaceBeg) + chunk -= SpaceBeg(); + + uptr offset = chunk % kRegionSize; + // Here we divide by a non-constant. This is costly. + // size always fits into 32-bits. If the offset fits too, use 32-bit div. + if (offset >> (SANITIZER_WORDSIZE / 2)) + return offset / size; + return (u32)offset / (u32)size; + } + + CompactPtrT *GetFreeArray(uptr region_beg) const { + return reinterpret_cast<CompactPtrT *>(GetMetadataEnd(region_beg)); + } + + bool MapWithCallback(uptr beg, uptr size, const char *name) { + if (PremappedHeap) + return beg >= NonConstSpaceBeg && + beg + size <= NonConstSpaceBeg + kSpaceSize; + uptr mapped = address_range.Map(beg, size, name); + if (UNLIKELY(!mapped)) + return false; + CHECK_EQ(beg, mapped); + MapUnmapCallback().OnMap(beg, size); + return true; + } + + void MapWithCallbackOrDie(uptr beg, uptr size, const char *name) { + if (PremappedHeap) { + CHECK_GE(beg, NonConstSpaceBeg); + CHECK_LE(beg + size, NonConstSpaceBeg + kSpaceSize); + return; + } + CHECK_EQ(beg, address_range.MapOrDie(beg, size, name)); + MapUnmapCallback().OnMap(beg, size); + } + + void UnmapWithCallbackOrDie(uptr beg, uptr size) { + if (PremappedHeap) + return; + MapUnmapCallback().OnUnmap(beg, size); + address_range.Unmap(beg, size); + } + + bool EnsureFreeArraySpace(RegionInfo *region, uptr region_beg, + uptr num_freed_chunks) { + uptr needed_space = num_freed_chunks * sizeof(CompactPtrT); + if (region->mapped_free_array < needed_space) { + uptr new_mapped_free_array = RoundUpTo(needed_space, kFreeArrayMapSize); + CHECK_LE(new_mapped_free_array, kFreeArraySize); + uptr current_map_end = reinterpret_cast<uptr>(GetFreeArray(region_beg)) + + region->mapped_free_array; + uptr new_map_size = new_mapped_free_array - region->mapped_free_array; + if (UNLIKELY(!MapWithCallback(current_map_end, new_map_size, + "SizeClassAllocator: freearray"))) + return false; + region->mapped_free_array = new_mapped_free_array; + } + return true; + } + + // Check whether this size class is exhausted. + bool IsRegionExhausted(RegionInfo *region, uptr class_id, + uptr additional_map_size) { + if (LIKELY(region->mapped_user + region->mapped_meta + + additional_map_size <= kRegionSize - kFreeArraySize)) + return false; + if (!region->exhausted) { + region->exhausted = true; + Printf("%s: Out of memory. ", SanitizerToolName); + Printf("The process has exhausted %zuMB for size class %zu.\n", + kRegionSize >> 20, ClassIdToSize(class_id)); + } + return true; + } + + NOINLINE bool PopulateFreeArray(AllocatorStats *stat, uptr class_id, + RegionInfo *region, uptr requested_count) { + // region->mutex is held. + const uptr region_beg = GetRegionBeginBySizeClass(class_id); + const uptr size = ClassIdToSize(class_id); + + const uptr total_user_bytes = + region->allocated_user + requested_count * size; + // Map more space for chunks, if necessary. + if (LIKELY(total_user_bytes > region->mapped_user)) { + if (UNLIKELY(region->mapped_user == 0)) { + if (!kUsingConstantSpaceBeg && kRandomShuffleChunks) + // The random state is initialized from ASLR. + region->rand_state = static_cast<u32>(region_beg >> 12); + // Postpone the first release to OS attempt for ReleaseToOSIntervalMs, + // preventing just allocated memory from being released sooner than + // necessary and also preventing extraneous ReleaseMemoryPagesToOS calls + // for short lived processes. + // Do it only when the feature is turned on, to avoid a potentially + // extraneous syscall. + if (ReleaseToOSIntervalMs() >= 0) + region->rtoi.last_release_at_ns = MonotonicNanoTime(); + } + // Do the mmap for the user memory. + const uptr user_map_size = + RoundUpTo(total_user_bytes - region->mapped_user, kUserMapSize); + if (UNLIKELY(IsRegionExhausted(region, class_id, user_map_size))) + return false; + if (UNLIKELY(!MapWithCallback(region_beg + region->mapped_user, + user_map_size, + "SizeClassAllocator: region data"))) + return false; + stat->Add(AllocatorStatMapped, user_map_size); + region->mapped_user += user_map_size; + } + const uptr new_chunks_count = + (region->mapped_user - region->allocated_user) / size; + + if (kMetadataSize) { + // Calculate the required space for metadata. + const uptr total_meta_bytes = + region->allocated_meta + new_chunks_count * kMetadataSize; + const uptr meta_map_size = (total_meta_bytes > region->mapped_meta) ? + RoundUpTo(total_meta_bytes - region->mapped_meta, kMetaMapSize) : 0; + // Map more space for metadata, if necessary. + if (meta_map_size) { + if (UNLIKELY(IsRegionExhausted(region, class_id, meta_map_size))) + return false; + if (UNLIKELY(!MapWithCallback( + GetMetadataEnd(region_beg) - region->mapped_meta - meta_map_size, + meta_map_size, "SizeClassAllocator: region metadata"))) + return false; + region->mapped_meta += meta_map_size; + } + } + + // If necessary, allocate more space for the free array and populate it with + // newly allocated chunks. + const uptr total_freed_chunks = region->num_freed_chunks + new_chunks_count; + if (UNLIKELY(!EnsureFreeArraySpace(region, region_beg, total_freed_chunks))) + return false; + CompactPtrT *free_array = GetFreeArray(region_beg); + for (uptr i = 0, chunk = region->allocated_user; i < new_chunks_count; + i++, chunk += size) + free_array[total_freed_chunks - 1 - i] = PointerToCompactPtr(0, chunk); + if (kRandomShuffleChunks) + RandomShuffle(&free_array[region->num_freed_chunks], new_chunks_count, + ®ion->rand_state); + + // All necessary memory is mapped and now it is safe to advance all + // 'allocated_*' counters. + region->num_freed_chunks += new_chunks_count; + region->allocated_user += new_chunks_count * size; + CHECK_LE(region->allocated_user, region->mapped_user); + region->allocated_meta += new_chunks_count * kMetadataSize; + CHECK_LE(region->allocated_meta, region->mapped_meta); + region->exhausted = false; + + // TODO(alekseyshl): Consider bumping last_release_at_ns here to prevent + // MaybeReleaseToOS from releasing just allocated pages or protect these + // not yet used chunks some other way. + + return true; + } + + // Attempts to release RAM occupied by freed chunks back to OS. The region is + // expected to be locked. + // + // TODO(morehouse): Support a callback on memory release so HWASan can release + // aliases as well. + void MaybeReleaseToOS(MemoryMapperT *memory_mapper, uptr class_id, + bool force) { + RegionInfo *region = GetRegionInfo(class_id); + const uptr chunk_size = ClassIdToSize(class_id); + const uptr page_size = GetPageSizeCached(); + + uptr n = region->num_freed_chunks; + if (n * chunk_size < page_size) + return; // No chance to release anything. + if ((region->stats.n_freed - + region->rtoi.n_freed_at_last_release) * chunk_size < page_size) { + return; // Nothing new to release. + } + + if (!force) { + s32 interval_ms = ReleaseToOSIntervalMs(); + if (interval_ms < 0) + return; + + if (region->rtoi.last_release_at_ns + interval_ms * 1000000ULL > + MonotonicNanoTime()) { + return; // Memory was returned recently. + } + } + + ReleaseFreeMemoryToOS( + GetFreeArray(GetRegionBeginBySizeClass(class_id)), n, chunk_size, + RoundUpTo(region->allocated_user, page_size) / page_size, memory_mapper, + class_id); + + uptr ranges, bytes; + if (memory_mapper->GetAndResetStats(ranges, bytes)) { + region->rtoi.n_freed_at_last_release = region->stats.n_freed; + region->rtoi.num_releases += ranges; + region->rtoi.last_released_bytes = bytes; + } + region->rtoi.last_release_at_ns = MonotonicNanoTime(); + } +}; diff --git a/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_allocator_report.cpp b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_allocator_report.cpp new file mode 100644 index 0000000000..1c6520819e --- /dev/null +++ b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_allocator_report.cpp @@ -0,0 +1,145 @@ +//===-- sanitizer_allocator_report.cpp --------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// Shared allocator error reporting for ThreadSanitizer, MemorySanitizer, etc. +/// +//===----------------------------------------------------------------------===// + +#include "sanitizer_allocator.h" +#include "sanitizer_allocator_report.h" +#include "sanitizer_common.h" +#include "sanitizer_report_decorator.h" + +namespace __sanitizer { + +class ScopedAllocatorErrorReport { + public: + ScopedAllocatorErrorReport(const char *error_summary_, + const StackTrace *stack_) + : error_summary(error_summary_), + stack(stack_) { + Printf("%s", d.Error()); + } + ~ScopedAllocatorErrorReport() { + Printf("%s", d.Default()); + stack->Print(); + PrintHintAllocatorCannotReturnNull(); + ReportErrorSummary(error_summary, stack); + } + + private: + ScopedErrorReportLock lock; + const char *error_summary; + const StackTrace* const stack; + const SanitizerCommonDecorator d; +}; + +void NORETURN ReportCallocOverflow(uptr count, uptr size, + const StackTrace *stack) { + { + ScopedAllocatorErrorReport report("calloc-overflow", stack); + Report("ERROR: %s: calloc parameters overflow: count * size (%zd * %zd) " + "cannot be represented in type size_t\n", SanitizerToolName, count, + size); + } + Die(); +} + +void NORETURN ReportReallocArrayOverflow(uptr count, uptr size, + const StackTrace *stack) { + { + ScopedAllocatorErrorReport report("reallocarray-overflow", stack); + Report( + "ERROR: %s: reallocarray parameters overflow: count * size (%zd * %zd) " + "cannot be represented in type size_t\n", + SanitizerToolName, count, size); + } + Die(); +} + +void NORETURN ReportPvallocOverflow(uptr size, const StackTrace *stack) { + { + ScopedAllocatorErrorReport report("pvalloc-overflow", stack); + Report("ERROR: %s: pvalloc parameters overflow: size 0x%zx rounded up to " + "system page size 0x%zx cannot be represented in type size_t\n", + SanitizerToolName, size, GetPageSizeCached()); + } + Die(); +} + +void NORETURN ReportInvalidAllocationAlignment(uptr alignment, + const StackTrace *stack) { + { + ScopedAllocatorErrorReport report("invalid-allocation-alignment", stack); + Report("ERROR: %s: invalid allocation alignment: %zd, alignment must be a " + "power of two\n", SanitizerToolName, alignment); + } + Die(); +} + +void NORETURN ReportInvalidAlignedAllocAlignment(uptr size, uptr alignment, + const StackTrace *stack) { + { + ScopedAllocatorErrorReport report("invalid-aligned-alloc-alignment", stack); +#if SANITIZER_POSIX + Report("ERROR: %s: invalid alignment requested in " + "aligned_alloc: %zd, alignment must be a power of two and the " + "requested size 0x%zx must be a multiple of alignment\n", + SanitizerToolName, alignment, size); +#else + Report("ERROR: %s: invalid alignment requested in aligned_alloc: %zd, " + "the requested size 0x%zx must be a multiple of alignment\n", + SanitizerToolName, alignment, size); +#endif + } + Die(); +} + +void NORETURN ReportInvalidPosixMemalignAlignment(uptr alignment, + const StackTrace *stack) { + { + ScopedAllocatorErrorReport report("invalid-posix-memalign-alignment", + stack); + Report( + "ERROR: %s: invalid alignment requested in " + "posix_memalign: %zd, alignment must be a power of two and a " + "multiple of sizeof(void*) == %zd\n", + SanitizerToolName, alignment, sizeof(void *)); + } + Die(); +} + +void NORETURN ReportAllocationSizeTooBig(uptr user_size, uptr max_size, + const StackTrace *stack) { + { + ScopedAllocatorErrorReport report("allocation-size-too-big", stack); + Report("ERROR: %s: requested allocation size 0x%zx exceeds maximum " + "supported size of 0x%zx\n", SanitizerToolName, user_size, max_size); + } + Die(); +} + +void NORETURN ReportOutOfMemory(uptr requested_size, const StackTrace *stack) { + { + ScopedAllocatorErrorReport report("out-of-memory", stack); + Report("ERROR: %s: allocator is out of memory trying to allocate 0x%zx " + "bytes\n", SanitizerToolName, requested_size); + } + Die(); +} + +void NORETURN ReportRssLimitExceeded(const StackTrace *stack) { + { + ScopedAllocatorErrorReport report("rss-limit-exceeded", stack); + Report("ERROR: %s: allocator exceeded the RSS limit\n", SanitizerToolName); + } + Die(); +} + +} // namespace __sanitizer diff --git a/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_allocator_report.h b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_allocator_report.h new file mode 100644 index 0000000000..6e4e6b1354 --- /dev/null +++ b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_allocator_report.h @@ -0,0 +1,40 @@ +//===-- sanitizer_allocator_report.h ----------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// Shared allocator error reporting for ThreadSanitizer, MemorySanitizer, etc. +/// +//===----------------------------------------------------------------------===// + +#ifndef SANITIZER_ALLOCATOR_REPORT_H +#define SANITIZER_ALLOCATOR_REPORT_H + +#include "sanitizer_internal_defs.h" +#include "sanitizer_stacktrace.h" + +namespace __sanitizer { + +void NORETURN ReportCallocOverflow(uptr count, uptr size, + const StackTrace *stack); +void NORETURN ReportReallocArrayOverflow(uptr count, uptr size, + const StackTrace *stack); +void NORETURN ReportPvallocOverflow(uptr size, const StackTrace *stack); +void NORETURN ReportInvalidAllocationAlignment(uptr alignment, + const StackTrace *stack); +void NORETURN ReportInvalidAlignedAllocAlignment(uptr size, uptr alignment, + const StackTrace *stack); +void NORETURN ReportInvalidPosixMemalignAlignment(uptr alignment, + const StackTrace *stack); +void NORETURN ReportAllocationSizeTooBig(uptr user_size, uptr max_size, + const StackTrace *stack); +void NORETURN ReportOutOfMemory(uptr requested_size, const StackTrace *stack); +void NORETURN ReportRssLimitExceeded(const StackTrace *stack); + +} // namespace __sanitizer + +#endif // SANITIZER_ALLOCATOR_REPORT_H diff --git a/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_allocator_secondary.h b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_allocator_secondary.h new file mode 100644 index 0000000000..48afb2a298 --- /dev/null +++ b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_allocator_secondary.h @@ -0,0 +1,322 @@ +//===-- sanitizer_allocator_secondary.h -------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// Part of the Sanitizer Allocator. +// +//===----------------------------------------------------------------------===// +#ifndef SANITIZER_ALLOCATOR_H +#error This file must be included inside sanitizer_allocator.h +#endif + +// Fixed array to store LargeMmapAllocator chunks list, limited to 32K total +// allocated chunks. To be used in memory constrained or not memory hungry cases +// (currently, 32 bits and internal allocator). +class LargeMmapAllocatorPtrArrayStatic { + public: + inline void *Init() { return &p_[0]; } + inline void EnsureSpace(uptr n) { CHECK_LT(n, kMaxNumChunks); } + private: + static const int kMaxNumChunks = 1 << 15; + uptr p_[kMaxNumChunks]; +}; + +// Much less restricted LargeMmapAllocator chunks list (comparing to +// PtrArrayStatic). Backed by mmaped memory region and can hold up to 1M chunks. +// ReservedAddressRange was used instead of just MAP_NORESERVE to achieve the +// same functionality in Fuchsia case, which does not support MAP_NORESERVE. +class LargeMmapAllocatorPtrArrayDynamic { + public: + inline void *Init() { + uptr p = address_range_.Init(kMaxNumChunks * sizeof(uptr), + SecondaryAllocatorName); + CHECK(p); + return reinterpret_cast<void*>(p); + } + + inline void EnsureSpace(uptr n) { + CHECK_LT(n, kMaxNumChunks); + DCHECK(n <= n_reserved_); + if (UNLIKELY(n == n_reserved_)) { + address_range_.MapOrDie( + reinterpret_cast<uptr>(address_range_.base()) + + n_reserved_ * sizeof(uptr), + kChunksBlockCount * sizeof(uptr)); + n_reserved_ += kChunksBlockCount; + } + } + + private: + static const int kMaxNumChunks = 1 << 20; + static const int kChunksBlockCount = 1 << 14; + ReservedAddressRange address_range_; + uptr n_reserved_; +}; + +#if SANITIZER_WORDSIZE == 32 +typedef LargeMmapAllocatorPtrArrayStatic DefaultLargeMmapAllocatorPtrArray; +#else +typedef LargeMmapAllocatorPtrArrayDynamic DefaultLargeMmapAllocatorPtrArray; +#endif + +// 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). +template <class MapUnmapCallback = NoOpMapUnmapCallback, + class PtrArrayT = DefaultLargeMmapAllocatorPtrArray, + class AddressSpaceViewTy = LocalAddressSpaceView> +class LargeMmapAllocator { + public: + using AddressSpaceView = AddressSpaceViewTy; + void InitLinkerInitialized() { + page_size_ = GetPageSizeCached(); + chunks_ = reinterpret_cast<Header**>(ptr_array_.Init()); + } + + void Init() { + internal_memset(this, 0, sizeof(*this)); + InitLinkerInitialized(); + } + + void *Allocate(AllocatorStats *stat, uptr size, uptr alignment) { + CHECK(IsPowerOfTwo(alignment)); + uptr map_size = RoundUpMapSize(size); + if (alignment > page_size_) + map_size += alignment; + // Overflow. + if (map_size < size) { + Report("WARNING: %s: LargeMmapAllocator allocation overflow: " + "0x%zx bytes with 0x%zx alignment requested\n", + SanitizerToolName, map_size, alignment); + return nullptr; + } + uptr map_beg = reinterpret_cast<uptr>( + MmapOrDieOnFatalError(map_size, SecondaryAllocatorName)); + if (!map_beg) + return nullptr; + CHECK(IsAligned(map_beg, page_size_)); + MapUnmapCallback().OnMap(map_beg, map_size); + uptr map_end = map_beg + map_size; + uptr res = map_beg + page_size_; + if (res & (alignment - 1)) // Align. + res += alignment - (res & (alignment - 1)); + CHECK(IsAligned(res, alignment)); + CHECK(IsAligned(res, page_size_)); + CHECK_GE(res + size, map_beg); + CHECK_LE(res + size, map_end); + Header *h = GetHeader(res); + h->size = size; + h->map_beg = map_beg; + h->map_size = map_size; + uptr size_log = MostSignificantSetBitIndex(map_size); + CHECK_LT(size_log, ARRAY_SIZE(stats.by_size_log)); + { + SpinMutexLock l(&mutex_); + ptr_array_.EnsureSpace(n_chunks_); + uptr idx = n_chunks_++; + h->chunk_idx = idx; + chunks_[idx] = h; + chunks_sorted_ = false; + stats.n_allocs++; + stats.currently_allocated += map_size; + stats.max_allocated = Max(stats.max_allocated, stats.currently_allocated); + stats.by_size_log[size_log]++; + stat->Add(AllocatorStatAllocated, map_size); + stat->Add(AllocatorStatMapped, map_size); + } + return reinterpret_cast<void*>(res); + } + + void Deallocate(AllocatorStats *stat, void *p) { + Header *h = GetHeader(p); + { + SpinMutexLock l(&mutex_); + uptr idx = h->chunk_idx; + CHECK_EQ(chunks_[idx], h); + CHECK_LT(idx, n_chunks_); + chunks_[idx] = chunks_[--n_chunks_]; + chunks_[idx]->chunk_idx = idx; + chunks_sorted_ = false; + stats.n_frees++; + stats.currently_allocated -= h->map_size; + stat->Sub(AllocatorStatAllocated, h->map_size); + stat->Sub(AllocatorStatMapped, h->map_size); + } + MapUnmapCallback().OnUnmap(h->map_beg, h->map_size); + UnmapOrDie(reinterpret_cast<void*>(h->map_beg), h->map_size); + } + + uptr TotalMemoryUsed() { + SpinMutexLock l(&mutex_); + uptr res = 0; + for (uptr i = 0; i < n_chunks_; i++) { + Header *h = chunks_[i]; + CHECK_EQ(h->chunk_idx, i); + res += RoundUpMapSize(h->size); + } + return res; + } + + bool PointerIsMine(const void *p) const { + return GetBlockBegin(p) != nullptr; + } + + uptr GetActuallyAllocatedSize(void *p) { + return RoundUpTo(GetHeader(p)->size, page_size_); + } + + // At least page_size_/2 metadata bytes is available. + void *GetMetaData(const void *p) { + // Too slow: CHECK_EQ(p, GetBlockBegin(p)); + if (!IsAligned(reinterpret_cast<uptr>(p), page_size_)) { + Printf("%s: bad pointer %p\n", SanitizerToolName, p); + CHECK(IsAligned(reinterpret_cast<uptr>(p), page_size_)); + } + return GetHeader(p) + 1; + } + + void *GetBlockBegin(const void *ptr) const { + uptr p = reinterpret_cast<uptr>(ptr); + SpinMutexLock l(&mutex_); + uptr nearest_chunk = 0; + Header *const *chunks = AddressSpaceView::Load(chunks_, n_chunks_); + // Cache-friendly linear search. + for (uptr i = 0; i < n_chunks_; i++) { + uptr ch = reinterpret_cast<uptr>(chunks[i]); + if (p < ch) continue; // p is at left to this chunk, skip it. + if (p - ch < p - nearest_chunk) + nearest_chunk = ch; + } + if (!nearest_chunk) + return nullptr; + const Header *h = + AddressSpaceView::Load(reinterpret_cast<Header *>(nearest_chunk)); + Header *h_ptr = reinterpret_cast<Header *>(nearest_chunk); + CHECK_GE(nearest_chunk, h->map_beg); + CHECK_LT(nearest_chunk, h->map_beg + h->map_size); + CHECK_LE(nearest_chunk, p); + if (h->map_beg + h->map_size <= p) + return nullptr; + return GetUser(h_ptr); + } + + void EnsureSortedChunks() { + if (chunks_sorted_) return; + Header **chunks = AddressSpaceView::LoadWritable(chunks_, n_chunks_); + Sort(reinterpret_cast<uptr *>(chunks), n_chunks_); + for (uptr i = 0; i < n_chunks_; i++) + AddressSpaceView::LoadWritable(chunks[i])->chunk_idx = i; + chunks_sorted_ = true; + } + + // This function does the same as GetBlockBegin, but is much faster. + // Must be called with the allocator locked. + void *GetBlockBeginFastLocked(void *ptr) { + mutex_.CheckLocked(); + uptr p = reinterpret_cast<uptr>(ptr); + uptr n = n_chunks_; + if (!n) return nullptr; + EnsureSortedChunks(); + Header *const *chunks = AddressSpaceView::Load(chunks_, n_chunks_); + auto min_mmap_ = reinterpret_cast<uptr>(chunks[0]); + auto max_mmap_ = reinterpret_cast<uptr>(chunks[n - 1]) + + AddressSpaceView::Load(chunks[n - 1])->map_size; + if (p < min_mmap_ || p >= max_mmap_) + return nullptr; + uptr beg = 0, end = n - 1; + // This loop is a log(n) lower_bound. It does not check for the exact match + // to avoid expensive cache-thrashing loads. + while (end - beg >= 2) { + uptr mid = (beg + end) / 2; // Invariant: mid >= beg + 1 + if (p < reinterpret_cast<uptr>(chunks[mid])) + end = mid - 1; // We are not interested in chunks[mid]. + else + beg = mid; // chunks[mid] may still be what we want. + } + + if (beg < end) { + CHECK_EQ(beg + 1, end); + // There are 2 chunks left, choose one. + if (p >= reinterpret_cast<uptr>(chunks[end])) + beg = end; + } + + const Header *h = AddressSpaceView::Load(chunks[beg]); + Header *h_ptr = chunks[beg]; + if (h->map_beg + h->map_size <= p || p < h->map_beg) + return nullptr; + return GetUser(h_ptr); + } + + void PrintStats() { + Printf("Stats: LargeMmapAllocator: allocated %zd times, " + "remains %zd (%zd K) max %zd M; by size logs: ", + stats.n_allocs, stats.n_allocs - stats.n_frees, + stats.currently_allocated >> 10, stats.max_allocated >> 20); + for (uptr i = 0; i < ARRAY_SIZE(stats.by_size_log); i++) { + uptr c = stats.by_size_log[i]; + if (!c) continue; + Printf("%zd:%zd; ", i, c); + } + Printf("\n"); + } + + // ForceLock() and ForceUnlock() are needed to implement Darwin malloc zone + // introspection API. + void ForceLock() SANITIZER_ACQUIRE(mutex_) { mutex_.Lock(); } + + void ForceUnlock() SANITIZER_RELEASE(mutex_) { mutex_.Unlock(); } + + // Iterate over all existing chunks. + // The allocator must be locked when calling this function. + void ForEachChunk(ForEachChunkCallback callback, void *arg) { + EnsureSortedChunks(); // Avoid doing the sort while iterating. + const Header *const *chunks = AddressSpaceView::Load(chunks_, n_chunks_); + for (uptr i = 0; i < n_chunks_; i++) { + const Header *t = chunks[i]; + callback(reinterpret_cast<uptr>(GetUser(t)), arg); + // Consistency check: verify that the array did not change. + CHECK_EQ(chunks[i], t); + CHECK_EQ(AddressSpaceView::Load(chunks[i])->chunk_idx, i); + } + } + + private: + struct Header { + uptr map_beg; + uptr map_size; + uptr size; + uptr chunk_idx; + }; + + Header *GetHeader(uptr p) { + CHECK(IsAligned(p, page_size_)); + return reinterpret_cast<Header*>(p - page_size_); + } + Header *GetHeader(const void *p) { + return GetHeader(reinterpret_cast<uptr>(p)); + } + + void *GetUser(const Header *h) const { + CHECK(IsAligned((uptr)h, page_size_)); + return reinterpret_cast<void*>(reinterpret_cast<uptr>(h) + page_size_); + } + + uptr RoundUpMapSize(uptr size) { + return RoundUpTo(size, page_size_) + page_size_; + } + + uptr page_size_; + Header **chunks_; + PtrArrayT ptr_array_; + uptr n_chunks_; + bool chunks_sorted_; + struct Stats { + uptr n_allocs, n_frees, currently_allocated, max_allocated, by_size_log[64]; + } stats; + mutable StaticSpinMutex mutex_; +}; diff --git a/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_allocator_size_class_map.h b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_allocator_size_class_map.h new file mode 100644 index 0000000000..361793f249 --- /dev/null +++ b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_allocator_size_class_map.h @@ -0,0 +1,241 @@ +//===-- sanitizer_allocator_size_class_map.h --------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// Part of the Sanitizer Allocator. +// +//===----------------------------------------------------------------------===// +#ifndef SANITIZER_ALLOCATOR_H +#error This file must be included inside sanitizer_allocator.h +#endif + +// SizeClassMap maps allocation sizes into size classes and back. +// Class 0 always corresponds to size 0. +// The other sizes are controlled by the template parameters: +// kMinSizeLog: defines the class 1 as 2^kMinSizeLog. +// kMaxSizeLog: defines the last class as 2^kMaxSizeLog. +// kMidSizeLog: the classes starting from 1 increase with step +// 2^kMinSizeLog until 2^kMidSizeLog. +// kNumBits: the number of non-zero bits in sizes after 2^kMidSizeLog. +// E.g. with kNumBits==3 all size classes after 2^kMidSizeLog +// look like 0b1xx0..0, where x is either 0 or 1. +// +// Example: kNumBits=3, kMinSizeLog=4, kMidSizeLog=8, kMaxSizeLog=17: +// +// Classes 1 - 16 correspond to sizes 16 to 256 (size = class_id * 16). +// Next 4 classes: 256 + i * 64 (i = 1 to 4). +// Next 4 classes: 512 + i * 128 (i = 1 to 4). +// ... +// Next 4 classes: 2^k + i * 2^(k-2) (i = 1 to 4). +// Last class corresponds to kMaxSize = 1 << kMaxSizeLog. +// +// This structure of the size class map gives us: +// - Efficient table-free class-to-size and size-to-class functions. +// - Difference between two consequent size classes is between 14% and 25% +// +// This class also gives a hint to a thread-caching allocator about the amount +// of chunks that need to be cached per-thread: +// - kMaxNumCachedHint is a hint for maximal number of chunks per size class. +// The actual number is computed in TransferBatch. +// - (1 << kMaxBytesCachedLog) is the maximal number of bytes per size class. +// +// Part of output of SizeClassMap::Print(): +// c00 => s: 0 diff: +0 00% l 0 cached: 0 0; id 0 +// c01 => s: 16 diff: +16 00% l 4 cached: 256 4096; id 1 +// c02 => s: 32 diff: +16 100% l 5 cached: 256 8192; id 2 +// c03 => s: 48 diff: +16 50% l 5 cached: 256 12288; id 3 +// c04 => s: 64 diff: +16 33% l 6 cached: 256 16384; id 4 +// c05 => s: 80 diff: +16 25% l 6 cached: 256 20480; id 5 +// c06 => s: 96 diff: +16 20% l 6 cached: 256 24576; id 6 +// c07 => s: 112 diff: +16 16% l 6 cached: 256 28672; id 7 +// +// c08 => s: 128 diff: +16 14% l 7 cached: 256 32768; id 8 +// c09 => s: 144 diff: +16 12% l 7 cached: 256 36864; id 9 +// c10 => s: 160 diff: +16 11% l 7 cached: 256 40960; id 10 +// c11 => s: 176 diff: +16 10% l 7 cached: 256 45056; id 11 +// c12 => s: 192 diff: +16 09% l 7 cached: 256 49152; id 12 +// c13 => s: 208 diff: +16 08% l 7 cached: 256 53248; id 13 +// c14 => s: 224 diff: +16 07% l 7 cached: 256 57344; id 14 +// c15 => s: 240 diff: +16 07% l 7 cached: 256 61440; id 15 +// +// c16 => s: 256 diff: +16 06% l 8 cached: 256 65536; id 16 +// c17 => s: 320 diff: +64 25% l 8 cached: 204 65280; id 17 +// c18 => s: 384 diff: +64 20% l 8 cached: 170 65280; id 18 +// c19 => s: 448 diff: +64 16% l 8 cached: 146 65408; id 19 +// +// c20 => s: 512 diff: +64 14% l 9 cached: 128 65536; id 20 +// c21 => s: 640 diff: +128 25% l 9 cached: 102 65280; id 21 +// c22 => s: 768 diff: +128 20% l 9 cached: 85 65280; id 22 +// c23 => s: 896 diff: +128 16% l 9 cached: 73 65408; id 23 +// +// c24 => s: 1024 diff: +128 14% l 10 cached: 64 65536; id 24 +// c25 => s: 1280 diff: +256 25% l 10 cached: 51 65280; id 25 +// c26 => s: 1536 diff: +256 20% l 10 cached: 42 64512; id 26 +// c27 => s: 1792 diff: +256 16% l 10 cached: 36 64512; id 27 +// +// ... +// +// c48 => s: 65536 diff: +8192 14% l 16 cached: 1 65536; id 48 +// c49 => s: 81920 diff: +16384 25% l 16 cached: 1 81920; id 49 +// c50 => s: 98304 diff: +16384 20% l 16 cached: 1 98304; id 50 +// c51 => s: 114688 diff: +16384 16% l 16 cached: 1 114688; id 51 +// +// c52 => s: 131072 diff: +16384 14% l 17 cached: 1 131072; id 52 +// +// +// Another example (kNumBits=2): +// c00 => s: 0 diff: +0 00% l 0 cached: 0 0; id 0 +// c01 => s: 32 diff: +32 00% l 5 cached: 64 2048; id 1 +// c02 => s: 64 diff: +32 100% l 6 cached: 64 4096; id 2 +// c03 => s: 96 diff: +32 50% l 6 cached: 64 6144; id 3 +// c04 => s: 128 diff: +32 33% l 7 cached: 64 8192; id 4 +// c05 => s: 160 diff: +32 25% l 7 cached: 64 10240; id 5 +// c06 => s: 192 diff: +32 20% l 7 cached: 64 12288; id 6 +// c07 => s: 224 diff: +32 16% l 7 cached: 64 14336; id 7 +// c08 => s: 256 diff: +32 14% l 8 cached: 64 16384; id 8 +// c09 => s: 384 diff: +128 50% l 8 cached: 42 16128; id 9 +// c10 => s: 512 diff: +128 33% l 9 cached: 32 16384; id 10 +// c11 => s: 768 diff: +256 50% l 9 cached: 21 16128; id 11 +// c12 => s: 1024 diff: +256 33% l 10 cached: 16 16384; id 12 +// c13 => s: 1536 diff: +512 50% l 10 cached: 10 15360; id 13 +// c14 => s: 2048 diff: +512 33% l 11 cached: 8 16384; id 14 +// c15 => s: 3072 diff: +1024 50% l 11 cached: 5 15360; id 15 +// c16 => s: 4096 diff: +1024 33% l 12 cached: 4 16384; id 16 +// c17 => s: 6144 diff: +2048 50% l 12 cached: 2 12288; id 17 +// c18 => s: 8192 diff: +2048 33% l 13 cached: 2 16384; id 18 +// c19 => s: 12288 diff: +4096 50% l 13 cached: 1 12288; id 19 +// c20 => s: 16384 diff: +4096 33% l 14 cached: 1 16384; id 20 +// c21 => s: 24576 diff: +8192 50% l 14 cached: 1 24576; id 21 +// c22 => s: 32768 diff: +8192 33% l 15 cached: 1 32768; id 22 +// c23 => s: 49152 diff: +16384 50% l 15 cached: 1 49152; id 23 +// c24 => s: 65536 diff: +16384 33% l 16 cached: 1 65536; id 24 +// c25 => s: 98304 diff: +32768 50% l 16 cached: 1 98304; id 25 +// c26 => s: 131072 diff: +32768 33% l 17 cached: 1 131072; id 26 + +template <uptr kNumBits, uptr kMinSizeLog, uptr kMidSizeLog, uptr kMaxSizeLog, + uptr kMaxNumCachedHintT, uptr kMaxBytesCachedLog> +class SizeClassMap { + static const uptr kMinSize = 1 << kMinSizeLog; + static const uptr kMidSize = 1 << kMidSizeLog; + static const uptr kMidClass = kMidSize / kMinSize; + static const uptr S = kNumBits - 1; + static const uptr M = (1 << S) - 1; + + public: + // kMaxNumCachedHintT is a power of two. It serves as a hint + // for the size of TransferBatch, the actual size could be a bit smaller. + static const uptr kMaxNumCachedHint = kMaxNumCachedHintT; + COMPILER_CHECK((kMaxNumCachedHint & (kMaxNumCachedHint - 1)) == 0); + + static const uptr kMaxSize = 1UL << kMaxSizeLog; + static const uptr kNumClasses = + kMidClass + ((kMaxSizeLog - kMidSizeLog) << S) + 1 + 1; + static const uptr kLargestClassID = kNumClasses - 2; + static const uptr kBatchClassID = kNumClasses - 1; + COMPILER_CHECK(kNumClasses >= 16 && kNumClasses <= 256); + static const uptr kNumClassesRounded = + kNumClasses <= 32 ? 32 : + kNumClasses <= 64 ? 64 : + kNumClasses <= 128 ? 128 : 256; + + static uptr Size(uptr class_id) { + // Estimate the result for kBatchClassID because this class does not know + // the exact size of TransferBatch. It's OK since we are using the actual + // sizeof(TransferBatch) where it matters. + if (UNLIKELY(class_id == kBatchClassID)) + return kMaxNumCachedHint * sizeof(uptr); + if (class_id <= kMidClass) + return kMinSize * class_id; + class_id -= kMidClass; + uptr t = kMidSize << (class_id >> S); + return t + (t >> S) * (class_id & M); + } + + static uptr ClassID(uptr size) { + if (UNLIKELY(size > kMaxSize)) + return 0; + if (size <= kMidSize) + return (size + kMinSize - 1) >> kMinSizeLog; + const uptr l = MostSignificantSetBitIndex(size); + const uptr hbits = (size >> (l - S)) & M; + const uptr lbits = size & ((1U << (l - S)) - 1); + const uptr l1 = l - kMidSizeLog; + return kMidClass + (l1 << S) + hbits + (lbits > 0); + } + + static uptr MaxCachedHint(uptr size) { + DCHECK_LE(size, kMaxSize); + if (UNLIKELY(size == 0)) + return 0; + uptr n; + // Force a 32-bit division if the template parameters allow for it. + if (kMaxBytesCachedLog > 31 || kMaxSizeLog > 31) + n = (1UL << kMaxBytesCachedLog) / size; + else + n = (1U << kMaxBytesCachedLog) / static_cast<u32>(size); + return Max<uptr>(1U, Min(kMaxNumCachedHint, n)); + } + + static void Print() { + uptr prev_s = 0; + uptr total_cached = 0; + for (uptr i = 0; i < kNumClasses; i++) { + uptr s = Size(i); + if (s >= kMidSize / 2 && (s & (s - 1)) == 0) + Printf("\n"); + uptr d = s - prev_s; + uptr p = prev_s ? (d * 100 / prev_s) : 0; + uptr l = s ? MostSignificantSetBitIndex(s) : 0; + uptr cached = MaxCachedHint(s) * s; + if (i == kBatchClassID) + d = p = l = 0; + Printf( + "c%02zu => s: %zu diff: +%zu %02zu%% l %zu cached: %zu %zu; id %zu\n", + i, Size(i), d, p, l, MaxCachedHint(s), cached, ClassID(s)); + total_cached += cached; + prev_s = s; + } + Printf("Total cached: %zu\n", total_cached); + } + + static void Validate() { + for (uptr c = 1; c < kNumClasses; c++) { + // Printf("Validate: c%zd\n", c); + uptr s = Size(c); + CHECK_NE(s, 0U); + if (c == kBatchClassID) + continue; + CHECK_EQ(ClassID(s), c); + if (c < kLargestClassID) + CHECK_EQ(ClassID(s + 1), c + 1); + CHECK_EQ(ClassID(s - 1), c); + CHECK_GT(Size(c), Size(c - 1)); + } + CHECK_EQ(ClassID(kMaxSize + 1), 0); + + for (uptr s = 1; s <= kMaxSize; s++) { + uptr c = ClassID(s); + // Printf("s%zd => c%zd\n", s, c); + CHECK_LT(c, kNumClasses); + CHECK_GE(Size(c), s); + if (c > 0) + CHECK_LT(Size(c - 1), s); + } + } +}; + +typedef SizeClassMap<3, 4, 8, 17, 128, 16> DefaultSizeClassMap; +typedef SizeClassMap<3, 4, 8, 17, 64, 14> CompactSizeClassMap; +typedef SizeClassMap<2, 5, 9, 16, 64, 14> VeryCompactSizeClassMap; + +// The following SizeClassMap only holds a way small number of cached entries, +// allowing for denser per-class arrays, smaller memory footprint and usually +// better performances in threaded environments. +typedef SizeClassMap<3, 4, 8, 17, 8, 10> DenseSizeClassMap; +// Similar to VeryCompact map above, this one has a small number of different +// size classes, and also reduced thread-local caches. +typedef SizeClassMap<2, 5, 9, 16, 8, 10> VeryDenseSizeClassMap; diff --git a/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_allocator_stats.h b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_allocator_stats.h new file mode 100644 index 0000000000..6f14e3863c --- /dev/null +++ b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_allocator_stats.h @@ -0,0 +1,106 @@ +//===-- sanitizer_allocator_stats.h -----------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// Part of the Sanitizer Allocator. +// +//===----------------------------------------------------------------------===// +#ifndef SANITIZER_ALLOCATOR_H +#error This file must be included inside sanitizer_allocator.h +#endif + +// Memory allocator statistics +enum AllocatorStat { + AllocatorStatAllocated, + AllocatorStatMapped, + AllocatorStatCount +}; + +typedef uptr AllocatorStatCounters[AllocatorStatCount]; + +// Per-thread stats, live in per-thread cache. +class AllocatorStats { + public: + void Init() { + internal_memset(this, 0, sizeof(*this)); + } + void InitLinkerInitialized() {} + + void Add(AllocatorStat i, uptr v) { + v += atomic_load(&stats_[i], memory_order_relaxed); + atomic_store(&stats_[i], v, memory_order_relaxed); + } + + void Sub(AllocatorStat i, uptr v) { + v = atomic_load(&stats_[i], memory_order_relaxed) - v; + atomic_store(&stats_[i], v, memory_order_relaxed); + } + + void Set(AllocatorStat i, uptr v) { + atomic_store(&stats_[i], v, memory_order_relaxed); + } + + uptr Get(AllocatorStat i) const { + return atomic_load(&stats_[i], memory_order_relaxed); + } + + private: + friend class AllocatorGlobalStats; + AllocatorStats *next_; + AllocatorStats *prev_; + atomic_uintptr_t stats_[AllocatorStatCount]; +}; + +// Global stats, used for aggregation and querying. +class AllocatorGlobalStats : public AllocatorStats { + public: + void InitLinkerInitialized() { + next_ = this; + prev_ = this; + } + void Init() { + internal_memset(this, 0, sizeof(*this)); + InitLinkerInitialized(); + } + + void Register(AllocatorStats *s) { + SpinMutexLock l(&mu_); + s->next_ = next_; + s->prev_ = this; + next_->prev_ = s; + next_ = s; + } + + void Unregister(AllocatorStats *s) { + SpinMutexLock l(&mu_); + s->prev_->next_ = s->next_; + s->next_->prev_ = s->prev_; + for (int i = 0; i < AllocatorStatCount; i++) + Add(AllocatorStat(i), s->Get(AllocatorStat(i))); + } + + void Get(AllocatorStatCounters s) const { + internal_memset(s, 0, AllocatorStatCount * sizeof(uptr)); + SpinMutexLock l(&mu_); + const AllocatorStats *stats = this; + for (;;) { + for (int i = 0; i < AllocatorStatCount; i++) + s[i] += stats->Get(AllocatorStat(i)); + stats = stats->next_; + if (stats == this) + break; + } + // All stats must be non-negative. + for (int i = 0; i < AllocatorStatCount; i++) + s[i] = ((sptr)s[i]) >= 0 ? s[i] : 0; + } + + private: + mutable StaticSpinMutex mu_; +}; + + diff --git a/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_asm.h b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_asm.h new file mode 100644 index 0000000000..9ebba91da7 --- /dev/null +++ b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_asm.h @@ -0,0 +1,75 @@ +//===-- sanitizer_asm.h -----------------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// Various support for assembler. +// +//===----------------------------------------------------------------------===// + +// Some toolchains do not support .cfi asm directives, so we have to hide +// them inside macros. +#if defined(__clang__) || \ + (defined(__GNUC__) && defined(__GCC_HAVE_DWARF2_CFI_ASM)) + // GCC defined __GCC_HAVE_DWARF2_CFI_ASM if it supports CFI. + // Clang seems to support CFI by default (or not?). + // We need two versions of macros: for inline asm and standalone asm files. +# define CFI_INL_ADJUST_CFA_OFFSET(n) ".cfi_adjust_cfa_offset " #n ";" + +# define CFI_STARTPROC .cfi_startproc +# define CFI_ENDPROC .cfi_endproc +# define CFI_ADJUST_CFA_OFFSET(n) .cfi_adjust_cfa_offset n +# define CFI_DEF_CFA_OFFSET(n) .cfi_def_cfa_offset n +# define CFI_REL_OFFSET(reg, n) .cfi_rel_offset reg, n +# define CFI_OFFSET(reg, n) .cfi_offset reg, n +# define CFI_DEF_CFA_REGISTER(reg) .cfi_def_cfa_register reg +# define CFI_DEF_CFA(reg, n) .cfi_def_cfa reg, n +# define CFI_RESTORE(reg) .cfi_restore reg + +#else // No CFI +# define CFI_INL_ADJUST_CFA_OFFSET(n) +# define CFI_STARTPROC +# define CFI_ENDPROC +# define CFI_ADJUST_CFA_OFFSET(n) +# define CFI_DEF_CFA_OFFSET(n) +# define CFI_REL_OFFSET(reg, n) +# define CFI_OFFSET(reg, n) +# define CFI_DEF_CFA_REGISTER(reg) +# define CFI_DEF_CFA(reg, n) +# define CFI_RESTORE(reg) +#endif + +#if !defined(__APPLE__) +# define ASM_HIDDEN(symbol) .hidden symbol +# define ASM_TYPE_FUNCTION(symbol) .type symbol, %function +# define ASM_SIZE(symbol) .size symbol, .-symbol +# define ASM_SYMBOL(symbol) symbol +# define ASM_SYMBOL_INTERCEPTOR(symbol) symbol +# define ASM_WRAPPER_NAME(symbol) __interceptor_##symbol +#else +# define ASM_HIDDEN(symbol) +# define ASM_TYPE_FUNCTION(symbol) +# define ASM_SIZE(symbol) +# define ASM_SYMBOL(symbol) _##symbol +# define ASM_SYMBOL_INTERCEPTOR(symbol) _wrap_##symbol +# define ASM_WRAPPER_NAME(symbol) __interceptor_##symbol +#endif + +#if defined(__ELF__) && (defined(__GNU__) || defined(__FreeBSD__) || \ + defined(__Fuchsia__) || defined(__linux__)) +// clang-format off +#define NO_EXEC_STACK_DIRECTIVE .section .note.GNU-stack,"",%progbits +// clang-format on +#else +#define NO_EXEC_STACK_DIRECTIVE +#endif + +#if (defined(__x86_64__) || defined(__i386__)) && defined(__has_include) && __has_include(<cet.h>) +#include <cet.h> +#endif +#ifndef _CET_ENDBR +#define _CET_ENDBR +#endif diff --git a/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_atomic.h b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_atomic.h new file mode 100644 index 0000000000..46f0695722 --- /dev/null +++ b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_atomic.h @@ -0,0 +1,86 @@ +//===-- sanitizer_atomic.h --------------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// 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_sint32_t { + typedef s32 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; + // On 32-bit platforms u64 is not necessary aligned on 8 bytes. + volatile ALIGNED(8) Type val_dont_use; +}; + +struct atomic_uintptr_t { + typedef uptr Type; + volatile Type val_dont_use; +}; + +} // namespace __sanitizer + +#if defined(__clang__) || defined(__GNUC__) +# include "sanitizer_atomic_clang.h" +#elif defined(_MSC_VER) +# include "sanitizer_atomic_msvc.h" +#else +# error "Unsupported compiler" +#endif + +namespace __sanitizer { + +// Clutter-reducing helpers. + +template<typename T> +inline typename T::Type atomic_load_relaxed(const volatile T *a) { + return atomic_load(a, memory_order_relaxed); +} + +template<typename T> +inline void atomic_store_relaxed(volatile T *a, typename T::Type v) { + atomic_store(a, v, memory_order_relaxed); +} + +} // namespace __sanitizer + +#endif // SANITIZER_ATOMIC_H diff --git a/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_atomic_clang.h b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_atomic_clang.h new file mode 100644 index 0000000000..c2b22cf572 --- /dev/null +++ b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_atomic_clang.h @@ -0,0 +1,104 @@ +//===-- sanitizer_atomic_clang.h --------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// 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 + +#if defined(__i386__) || defined(__x86_64__) +# include "sanitizer_atomic_clang_x86.h" +#else +# include "sanitizer_atomic_clang_other.h" +#endif + +namespace __sanitizer { + +// We would like to just use compiler builtin atomic operations +// for loads and stores, but they are mostly broken in clang: +// - they lead to vastly inefficient code generation +// (http://llvm.org/bugs/show_bug.cgi?id=17281) +// - 64-bit atomic operations are not implemented on x86_32 +// (http://llvm.org/bugs/show_bug.cgi?id=15034) +// - they are not implemented on ARM +// error: undefined reference to '__atomic_load_4' + +// See http://www.cl.cam.ac.uk/~pes20/cpp/cpp0xmappings.html +// for mappings of the memory model to different processors. + +inline void atomic_signal_fence(memory_order) { + __asm__ __volatile__("" ::: "memory"); +} + +inline void atomic_thread_fence(memory_order) { + __sync_synchronize(); +} + +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) { + // Transitioned from __sync_val_compare_and_swap to support targets like + // SPARC V8 that cannot inline atomic cmpxchg. __atomic_compare_exchange + // can then be resolved from libatomic. __ATOMIC_SEQ_CST is used to best + // match the __sync builtin memory order. + return __atomic_compare_exchange(&a->val_dont_use, cmp, &xchg, false, + __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST); +} + +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 + +// This include provides explicit template instantiations for atomic_uint64_t +// on MIPS32, which does not directly support 8 byte atomics. It has to +// proceed the template definitions above. +#if defined(_MIPS_SIM) && defined(_ABIO32) + #include "sanitizer_atomic_clang_mips.h" +#endif + +#undef ATOMIC_ORDER + +#endif // SANITIZER_ATOMIC_CLANG_H diff --git a/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_atomic_clang_mips.h b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_atomic_clang_mips.h new file mode 100644 index 0000000000..f3d3052e5b --- /dev/null +++ b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_atomic_clang_mips.h @@ -0,0 +1,117 @@ +//===-- sanitizer_atomic_clang_mips.h ---------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file is a part of ThreadSanitizer/AddressSanitizer runtime. +// Not intended for direct inclusion. Include sanitizer_atomic.h. +// +//===----------------------------------------------------------------------===// + +#ifndef SANITIZER_ATOMIC_CLANG_MIPS_H +#define SANITIZER_ATOMIC_CLANG_MIPS_H + +namespace __sanitizer { + +// MIPS32 does not support atomics > 4 bytes. To address this lack of +// functionality, the sanitizer library provides helper methods which use an +// internal spin lock mechanism to emulate atomic operations when the size is +// 8 bytes. +static void __spin_lock(volatile int *lock) { + while (__sync_lock_test_and_set(lock, 1)) + while (*lock) { + } +} + +static void __spin_unlock(volatile int *lock) { __sync_lock_release(lock); } + +// Make sure the lock is on its own cache line to prevent false sharing. +// Put it inside a struct that is aligned and padded to the typical MIPS +// cacheline which is 32 bytes. +static struct { + int lock; + char pad[32 - sizeof(int)]; +} __attribute__((aligned(32))) lock = {0, {0}}; + +template <> +inline atomic_uint64_t::Type atomic_fetch_add(volatile atomic_uint64_t *ptr, + atomic_uint64_t::Type val, + memory_order mo) { + DCHECK(mo & + (memory_order_relaxed | memory_order_release | memory_order_seq_cst)); + DCHECK(!((uptr)ptr % sizeof(*ptr))); + + atomic_uint64_t::Type ret; + + __spin_lock(&lock.lock); + ret = *(const_cast<atomic_uint64_t::Type volatile *>(&ptr->val_dont_use)); + ptr->val_dont_use = ret + val; + __spin_unlock(&lock.lock); + + return ret; +} + +template <> +inline atomic_uint64_t::Type atomic_fetch_sub(volatile atomic_uint64_t *ptr, + atomic_uint64_t::Type val, + memory_order mo) { + return atomic_fetch_add(ptr, -val, mo); +} + +template <> +inline bool atomic_compare_exchange_strong(volatile atomic_uint64_t *ptr, + atomic_uint64_t::Type *cmp, + atomic_uint64_t::Type xchg, + memory_order mo) { + DCHECK(mo & + (memory_order_relaxed | memory_order_release | memory_order_seq_cst)); + DCHECK(!((uptr)ptr % sizeof(*ptr))); + + typedef atomic_uint64_t::Type Type; + Type cmpv = *cmp; + Type prev; + bool ret = false; + + __spin_lock(&lock.lock); + prev = *(const_cast<Type volatile *>(&ptr->val_dont_use)); + if (prev == cmpv) { + ret = true; + ptr->val_dont_use = xchg; + } + __spin_unlock(&lock.lock); + + return ret; +} + +template <> +inline atomic_uint64_t::Type atomic_load(const volatile atomic_uint64_t *ptr, + memory_order mo) { + DCHECK(mo & + (memory_order_relaxed | memory_order_release | memory_order_seq_cst)); + DCHECK(!((uptr)ptr % sizeof(*ptr))); + + atomic_uint64_t::Type zero = 0; + volatile atomic_uint64_t *Newptr = + const_cast<volatile atomic_uint64_t *>(ptr); + return atomic_fetch_add(Newptr, zero, mo); +} + +template <> +inline void atomic_store(volatile atomic_uint64_t *ptr, atomic_uint64_t::Type v, + memory_order mo) { + DCHECK(mo & + (memory_order_relaxed | memory_order_release | memory_order_seq_cst)); + DCHECK(!((uptr)ptr % sizeof(*ptr))); + + __spin_lock(&lock.lock); + ptr->val_dont_use = v; + __spin_unlock(&lock.lock); +} + +} // namespace __sanitizer + +#endif // SANITIZER_ATOMIC_CLANG_MIPS_H + diff --git a/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_atomic_clang_other.h b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_atomic_clang_other.h new file mode 100644 index 0000000000..4a39889e53 --- /dev/null +++ b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_atomic_clang_other.h @@ -0,0 +1,85 @@ +//===-- sanitizer_atomic_clang_other.h --------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file is a part of ThreadSanitizer/AddressSanitizer runtime. +// Not intended for direct inclusion. Include sanitizer_atomic.h. +// +//===----------------------------------------------------------------------===// + +#ifndef SANITIZER_ATOMIC_CLANG_OTHER_H +#define SANITIZER_ATOMIC_CLANG_OTHER_H + +namespace __sanitizer { + + +inline void proc_yield(int cnt) { + __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 (sizeof(*a) < 8 || sizeof(void*) == 8) { + // Assume that aligned loads are atomic. + if (mo == memory_order_relaxed) { + v = a->val_dont_use; + } else if (mo == memory_order_consume) { + // Assume that processor respects data dependencies + // (and that compiler won't break them). + __asm__ __volatile__("" ::: "memory"); + v = a->val_dont_use; + __asm__ __volatile__("" ::: "memory"); + } else if (mo == memory_order_acquire) { + __asm__ __volatile__("" ::: "memory"); + v = a->val_dont_use; + __sync_synchronize(); + } else { // seq_cst + // E.g. on POWER we need a hw fence even before the store. + __sync_synchronize(); + v = a->val_dont_use; + __sync_synchronize(); + } + } else { + __atomic_load(const_cast<typename T::Type volatile *>(&a->val_dont_use), &v, + __ATOMIC_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 (sizeof(*a) < 8 || sizeof(void*) == 8) { + // Assume that aligned loads are atomic. + if (mo == memory_order_relaxed) { + a->val_dont_use = v; + } else if (mo == memory_order_release) { + __sync_synchronize(); + a->val_dont_use = v; + __asm__ __volatile__("" ::: "memory"); + } else { // seq_cst + __sync_synchronize(); + a->val_dont_use = v; + __sync_synchronize(); + } + } else { + __atomic_store(&a->val_dont_use, &v, __ATOMIC_SEQ_CST); + } +} + +} // namespace __sanitizer + +#endif // #ifndef SANITIZER_ATOMIC_CLANG_OTHER_H diff --git a/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_atomic_clang_x86.h b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_atomic_clang_x86.h new file mode 100644 index 0000000000..51597b4927 --- /dev/null +++ b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_atomic_clang_x86.h @@ -0,0 +1,113 @@ +//===-- sanitizer_atomic_clang_x86.h ----------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file is a part of ThreadSanitizer/AddressSanitizer runtime. +// Not intended for direct inclusion. Include sanitizer_atomic.h. +// +//===----------------------------------------------------------------------===// + +#ifndef SANITIZER_ATOMIC_CLANG_X86_H +#define SANITIZER_ATOMIC_CLANG_X86_H + +namespace __sanitizer { + +inline void proc_yield(int cnt) { + __asm__ __volatile__("" ::: "memory"); + for (int i = 0; i < cnt; i++) + __asm__ __volatile__("pause"); + __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 (sizeof(*a) < 8 || sizeof(void*) == 8) { + // Assume that aligned loads are atomic. + if (mo == memory_order_relaxed) { + v = a->val_dont_use; + } else if (mo == memory_order_consume) { + // Assume that processor respects data dependencies + // (and that compiler won't break them). + __asm__ __volatile__("" ::: "memory"); + v = a->val_dont_use; + __asm__ __volatile__("" ::: "memory"); + } else if (mo == memory_order_acquire) { + __asm__ __volatile__("" ::: "memory"); + v = a->val_dont_use; + // On x86 loads are implicitly acquire. + __asm__ __volatile__("" ::: "memory"); + } else { // seq_cst + // On x86 plain MOV is enough for seq_cst store. + __asm__ __volatile__("" ::: "memory"); + v = a->val_dont_use; + __asm__ __volatile__("" ::: "memory"); + } + } else { + // 64-bit load on 32-bit platform. + __asm__ __volatile__( + "movq %1, %%mm0;" // Use mmx reg for 64-bit atomic moves + "movq %%mm0, %0;" // (ptr could be read-only) + "emms;" // Empty mmx state/Reset FP regs + : "=m" (v) + : "m" (a->val_dont_use) + : // mark the mmx registers as clobbered +#ifdef __MMX__ + "mm0", "mm1", "mm2", "mm3", "mm4", "mm5", "mm6", "mm7", +#endif // #ifdef __MMX__ + "memory"); + } + 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 (sizeof(*a) < 8 || sizeof(void*) == 8) { + // Assume that aligned loads are atomic. + if (mo == memory_order_relaxed) { + a->val_dont_use = v; + } else if (mo == memory_order_release) { + // On x86 stores are implicitly release. + __asm__ __volatile__("" ::: "memory"); + a->val_dont_use = v; + __asm__ __volatile__("" ::: "memory"); + } else { // seq_cst + // On x86 stores are implicitly release. + __asm__ __volatile__("" ::: "memory"); + a->val_dont_use = v; + __sync_synchronize(); + } + } else { + // 64-bit store on 32-bit platform. + __asm__ __volatile__( + "movq %1, %%mm0;" // Use mmx reg for 64-bit atomic moves + "movq %%mm0, %0;" + "emms;" // Empty mmx state/Reset FP regs + : "=m" (a->val_dont_use) + : "m" (v) + : // mark the mmx registers as clobbered +#ifdef __MMX__ + "mm0", "mm1", "mm2", "mm3", "mm4", "mm5", "mm6", "mm7", +#endif // #ifdef __MMX__ + "memory"); + if (mo == memory_order_seq_cst) + __sync_synchronize(); + } +} + +} // namespace __sanitizer + +#endif // #ifndef SANITIZER_ATOMIC_CLANG_X86_H diff --git a/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_atomic_msvc.h b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_atomic_msvc.h new file mode 100644 index 0000000000..31317adcdf --- /dev/null +++ b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_atomic_msvc.h @@ -0,0 +1,256 @@ +//===-- sanitizer_atomic_msvc.h ---------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// 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" char _InterlockedExchange8(char volatile *Addend, char Value); +#pragma intrinsic(_InterlockedExchange8) +extern "C" short _InterlockedExchange16(short volatile *Addend, short Value); +#pragma intrinsic(_InterlockedExchange16) +extern "C" long _InterlockedExchange(long volatile *Addend, long Value); +#pragma intrinsic(_InterlockedExchange) +extern "C" long _InterlockedExchangeAdd(long volatile *Addend, long Value); +#pragma intrinsic(_InterlockedExchangeAdd) +extern "C" char _InterlockedCompareExchange8(char volatile *Destination, + char Exchange, char Comparand); +#pragma intrinsic(_InterlockedCompareExchange8) +extern "C" short _InterlockedCompareExchange16(short volatile *Destination, + short Exchange, short Comparand); +#pragma intrinsic(_InterlockedCompareExchange16) +extern "C" long long _InterlockedCompareExchange64( + long long volatile *Destination, long long Exchange, long long Comparand); +#pragma intrinsic(_InterlockedCompareExchange64) +extern "C" void *_InterlockedCompareExchangePointer( + void *volatile *Destination, + void *Exchange, void *Comparand); +#pragma intrinsic(_InterlockedCompareExchangePointer) +extern "C" long __cdecl _InterlockedCompareExchange(long volatile *Destination, + long Exchange, + long Comparand); +#pragma intrinsic(_InterlockedCompareExchange) + +#ifdef _WIN64 +extern "C" long long _InterlockedExchangeAdd64(long long volatile *Addend, + long long Value); +#pragma intrinsic(_InterlockedExchangeAdd64) +#endif + +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; + // FIXME(dvyukov): 64-bit load is not atomic on 32-bits. + 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))); + // FIXME(dvyukov): 64-bit store is not atomic on 32-bits. + 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); +} + +inline uptr atomic_fetch_add(volatile atomic_uintptr_t *a, + uptr v, memory_order mo) { + (void)mo; + DCHECK(!((uptr)a % sizeof(*a))); +#ifdef _WIN64 + return (uptr)_InterlockedExchangeAdd64((volatile long long *)&a->val_dont_use, + (long long)v); +#else + return (uptr)_InterlockedExchangeAdd((volatile long *)&a->val_dont_use, + (long)v); +#endif +} + +inline u32 atomic_fetch_sub(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); +} + +inline uptr atomic_fetch_sub(volatile atomic_uintptr_t *a, + uptr v, memory_order mo) { + (void)mo; + DCHECK(!((uptr)a % sizeof(*a))); +#ifdef _WIN64 + return (uptr)_InterlockedExchangeAdd64((volatile long long *)&a->val_dont_use, + -(long long)v); +#else + return (uptr)_InterlockedExchangeAdd((volatile long *)&a->val_dont_use, + -(long)v); +#endif +} + +inline u8 atomic_exchange(volatile atomic_uint8_t *a, + u8 v, memory_order mo) { + (void)mo; + DCHECK(!((uptr)a % sizeof(*a))); + return (u8)_InterlockedExchange8((volatile char*)&a->val_dont_use, v); +} + +inline u16 atomic_exchange(volatile atomic_uint16_t *a, + u16 v, memory_order mo) { + (void)mo; + DCHECK(!((uptr)a % sizeof(*a))); + return (u16)_InterlockedExchange16((volatile short*)&a->val_dont_use, v); +} + +inline u32 atomic_exchange(volatile atomic_uint32_t *a, + u32 v, memory_order mo) { + (void)mo; + DCHECK(!((uptr)a % sizeof(*a))); + return (u32)_InterlockedExchange((volatile long*)&a->val_dont_use, v); +} + +inline bool atomic_compare_exchange_strong(volatile atomic_uint8_t *a, + u8 *cmp, + u8 xchgv, + memory_order mo) { + (void)mo; + DCHECK(!((uptr)a % sizeof(*a))); + u8 cmpv = *cmp; +#ifdef _WIN64 + u8 prev = (u8)_InterlockedCompareExchange8( + (volatile char*)&a->val_dont_use, (char)xchgv, (char)cmpv); +#else + u8 prev; + __asm { + mov al, cmpv + mov ecx, a + mov dl, xchgv + lock cmpxchg [ecx], dl + mov prev, al + } +#endif + if (prev == cmpv) + return true; + *cmp = prev; + return false; +} + +inline bool atomic_compare_exchange_strong(volatile atomic_uintptr_t *a, + uptr *cmp, + uptr xchg, + memory_order mo) { + uptr cmpv = *cmp; + uptr prev = (uptr)_InterlockedCompareExchangePointer( + (void*volatile*)&a->val_dont_use, (void*)xchg, (void*)cmpv); + if (prev == cmpv) + return true; + *cmp = prev; + return false; +} + +inline bool atomic_compare_exchange_strong(volatile atomic_uint16_t *a, + u16 *cmp, + u16 xchg, + memory_order mo) { + u16 cmpv = *cmp; + u16 prev = (u16)_InterlockedCompareExchange16( + (volatile short*)&a->val_dont_use, (short)xchg, (short)cmpv); + if (prev == cmpv) + return true; + *cmp = prev; + return false; +} + +inline bool atomic_compare_exchange_strong(volatile atomic_uint32_t *a, + u32 *cmp, + u32 xchg, + memory_order mo) { + u32 cmpv = *cmp; + u32 prev = (u32)_InterlockedCompareExchange( + (volatile long*)&a->val_dont_use, (long)xchg, (long)cmpv); + if (prev == cmpv) + return true; + *cmp = prev; + return false; +} + +inline bool atomic_compare_exchange_strong(volatile atomic_uint64_t *a, + u64 *cmp, + u64 xchg, + memory_order mo) { + u64 cmpv = *cmp; + u64 prev = (u64)_InterlockedCompareExchange64( + (volatile long long*)&a->val_dont_use, (long long)xchg, (long long)cmpv); + 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/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_bitvector.h b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_bitvector.h new file mode 100644 index 0000000000..07a59ab11c --- /dev/null +++ b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_bitvector.h @@ -0,0 +1,350 @@ +//===-- sanitizer_bitvector.h -----------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// Specializer BitVector implementation. +// +//===----------------------------------------------------------------------===// + +#ifndef SANITIZER_BITVECTOR_H +#define SANITIZER_BITVECTOR_H + +#include "sanitizer_common.h" + +namespace __sanitizer { + +// Fixed size bit vector based on a single basic integer. +template <class basic_int_t = uptr> +class BasicBitVector { + public: + enum SizeEnum : uptr { kSize = sizeof(basic_int_t) * 8 }; + + uptr size() const { return kSize; } + // No CTOR. + void clear() { bits_ = 0; } + void setAll() { bits_ = ~(basic_int_t)0; } + bool empty() const { return bits_ == 0; } + + // Returns true if the bit has changed from 0 to 1. + bool setBit(uptr idx) { + basic_int_t old = bits_; + bits_ |= mask(idx); + return bits_ != old; + } + + // Returns true if the bit has changed from 1 to 0. + bool clearBit(uptr idx) { + basic_int_t old = bits_; + bits_ &= ~mask(idx); + return bits_ != old; + } + + bool getBit(uptr idx) const { return (bits_ & mask(idx)) != 0; } + + uptr getAndClearFirstOne() { + CHECK(!empty()); + uptr idx = LeastSignificantSetBitIndex(bits_); + clearBit(idx); + return idx; + } + + // Do "this |= v" and return whether new bits have been added. + bool setUnion(const BasicBitVector &v) { + basic_int_t old = bits_; + bits_ |= v.bits_; + return bits_ != old; + } + + // Do "this &= v" and return whether any bits have been removed. + bool setIntersection(const BasicBitVector &v) { + basic_int_t old = bits_; + bits_ &= v.bits_; + return bits_ != old; + } + + // Do "this &= ~v" and return whether any bits have been removed. + bool setDifference(const BasicBitVector &v) { + basic_int_t old = bits_; + bits_ &= ~v.bits_; + return bits_ != old; + } + + void copyFrom(const BasicBitVector &v) { bits_ = v.bits_; } + + // Returns true if 'this' intersects with 'v'. + bool intersectsWith(const BasicBitVector &v) const { + return (bits_ & v.bits_) != 0; + } + + // for (BasicBitVector<>::Iterator it(bv); it.hasNext();) { + // uptr idx = it.next(); + // use(idx); + // } + class Iterator { + public: + Iterator() { } + explicit Iterator(const BasicBitVector &bv) : bv_(bv) {} + bool hasNext() const { return !bv_.empty(); } + uptr next() { return bv_.getAndClearFirstOne(); } + void clear() { bv_.clear(); } + private: + BasicBitVector bv_; + }; + + private: + basic_int_t mask(uptr idx) const { + CHECK_LT(idx, size()); + return (basic_int_t)1UL << idx; + } + basic_int_t bits_; +}; + +// Fixed size bit vector of (kLevel1Size*BV::kSize**2) bits. +// The implementation is optimized for better performance on +// sparse bit vectors, i.e. the those with few set bits. +template <uptr kLevel1Size = 1, class BV = BasicBitVector<> > +class TwoLevelBitVector { + // This is essentially a 2-level bit vector. + // Set bit in the first level BV indicates that there are set bits + // in the corresponding BV of the second level. + // This structure allows O(kLevel1Size) time for clear() and empty(), + // as well fast handling of sparse BVs. + public: + enum SizeEnum : uptr { kSize = BV::kSize * BV::kSize * kLevel1Size }; + // No CTOR. + + uptr size() const { return kSize; } + + void clear() { + for (uptr i = 0; i < kLevel1Size; i++) + l1_[i].clear(); + } + + void setAll() { + for (uptr i0 = 0; i0 < kLevel1Size; i0++) { + l1_[i0].setAll(); + for (uptr i1 = 0; i1 < BV::kSize; i1++) + l2_[i0][i1].setAll(); + } + } + + bool empty() const { + for (uptr i = 0; i < kLevel1Size; i++) + if (!l1_[i].empty()) + return false; + return true; + } + + // Returns true if the bit has changed from 0 to 1. + bool setBit(uptr idx) { + check(idx); + uptr i0 = idx0(idx); + uptr i1 = idx1(idx); + uptr i2 = idx2(idx); + if (!l1_[i0].getBit(i1)) { + l1_[i0].setBit(i1); + l2_[i0][i1].clear(); + } + bool res = l2_[i0][i1].setBit(i2); + // Printf("%s: %zd => %zd %zd %zd; %d\n", __func__, + // idx, i0, i1, i2, res); + return res; + } + + bool clearBit(uptr idx) { + check(idx); + uptr i0 = idx0(idx); + uptr i1 = idx1(idx); + uptr i2 = idx2(idx); + bool res = false; + if (l1_[i0].getBit(i1)) { + res = l2_[i0][i1].clearBit(i2); + if (l2_[i0][i1].empty()) + l1_[i0].clearBit(i1); + } + return res; + } + + bool getBit(uptr idx) const { + check(idx); + uptr i0 = idx0(idx); + uptr i1 = idx1(idx); + uptr i2 = idx2(idx); + // Printf("%s: %zd => %zd %zd %zd\n", __func__, idx, i0, i1, i2); + return l1_[i0].getBit(i1) && l2_[i0][i1].getBit(i2); + } + + uptr getAndClearFirstOne() { + for (uptr i0 = 0; i0 < kLevel1Size; i0++) { + if (l1_[i0].empty()) continue; + uptr i1 = l1_[i0].getAndClearFirstOne(); + uptr i2 = l2_[i0][i1].getAndClearFirstOne(); + if (!l2_[i0][i1].empty()) + l1_[i0].setBit(i1); + uptr res = i0 * BV::kSize * BV::kSize + i1 * BV::kSize + i2; + // Printf("getAndClearFirstOne: %zd %zd %zd => %zd\n", i0, i1, i2, res); + return res; + } + CHECK(0); + return 0; + } + + // Do "this |= v" and return whether new bits have been added. + bool setUnion(const TwoLevelBitVector &v) { + bool res = false; + for (uptr i0 = 0; i0 < kLevel1Size; i0++) { + BV t = v.l1_[i0]; + while (!t.empty()) { + uptr i1 = t.getAndClearFirstOne(); + if (l1_[i0].setBit(i1)) + l2_[i0][i1].clear(); + if (l2_[i0][i1].setUnion(v.l2_[i0][i1])) + res = true; + } + } + return res; + } + + // Do "this &= v" and return whether any bits have been removed. + bool setIntersection(const TwoLevelBitVector &v) { + bool res = false; + for (uptr i0 = 0; i0 < kLevel1Size; i0++) { + if (l1_[i0].setIntersection(v.l1_[i0])) + res = true; + if (!l1_[i0].empty()) { + BV t = l1_[i0]; + while (!t.empty()) { + uptr i1 = t.getAndClearFirstOne(); + if (l2_[i0][i1].setIntersection(v.l2_[i0][i1])) + res = true; + if (l2_[i0][i1].empty()) + l1_[i0].clearBit(i1); + } + } + } + return res; + } + + // Do "this &= ~v" and return whether any bits have been removed. + bool setDifference(const TwoLevelBitVector &v) { + bool res = false; + for (uptr i0 = 0; i0 < kLevel1Size; i0++) { + BV t = l1_[i0]; + t.setIntersection(v.l1_[i0]); + while (!t.empty()) { + uptr i1 = t.getAndClearFirstOne(); + if (l2_[i0][i1].setDifference(v.l2_[i0][i1])) + res = true; + if (l2_[i0][i1].empty()) + l1_[i0].clearBit(i1); + } + } + return res; + } + + void copyFrom(const TwoLevelBitVector &v) { + clear(); + setUnion(v); + } + + // Returns true if 'this' intersects with 'v'. + bool intersectsWith(const TwoLevelBitVector &v) const { + for (uptr i0 = 0; i0 < kLevel1Size; i0++) { + BV t = l1_[i0]; + t.setIntersection(v.l1_[i0]); + while (!t.empty()) { + uptr i1 = t.getAndClearFirstOne(); + if (!v.l1_[i0].getBit(i1)) continue; + if (l2_[i0][i1].intersectsWith(v.l2_[i0][i1])) + return true; + } + } + return false; + } + + // for (TwoLevelBitVector<>::Iterator it(bv); it.hasNext();) { + // uptr idx = it.next(); + // use(idx); + // } + class Iterator { + public: + Iterator() { } + explicit Iterator(const TwoLevelBitVector &bv) : bv_(bv), i0_(0), i1_(0) { + it1_.clear(); + it2_.clear(); + } + + bool hasNext() const { + if (it1_.hasNext()) return true; + for (uptr i = i0_; i < kLevel1Size; i++) + if (!bv_.l1_[i].empty()) return true; + return false; + } + + uptr next() { + // Printf("++++: %zd %zd; %d %d; size %zd\n", i0_, i1_, it1_.hasNext(), + // it2_.hasNext(), kSize); + if (!it1_.hasNext() && !it2_.hasNext()) { + for (; i0_ < kLevel1Size; i0_++) { + if (bv_.l1_[i0_].empty()) continue; + it1_ = typename BV::Iterator(bv_.l1_[i0_]); + // Printf("+i0: %zd %zd; %d %d; size %zd\n", i0_, i1_, it1_.hasNext(), + // it2_.hasNext(), kSize); + break; + } + } + if (!it2_.hasNext()) { + CHECK(it1_.hasNext()); + i1_ = it1_.next(); + it2_ = typename BV::Iterator(bv_.l2_[i0_][i1_]); + // Printf("++i1: %zd %zd; %d %d; size %zd\n", i0_, i1_, it1_.hasNext(), + // it2_.hasNext(), kSize); + } + CHECK(it2_.hasNext()); + uptr i2 = it2_.next(); + uptr res = i0_ * BV::kSize * BV::kSize + i1_ * BV::kSize + i2; + // Printf("+ret: %zd %zd; %d %d; size %zd; res: %zd\n", i0_, i1_, + // it1_.hasNext(), it2_.hasNext(), kSize, res); + if (!it1_.hasNext() && !it2_.hasNext()) + i0_++; + return res; + } + + private: + const TwoLevelBitVector &bv_; + uptr i0_, i1_; + typename BV::Iterator it1_, it2_; + }; + + private: + void check(uptr idx) const { CHECK_LE(idx, size()); } + + uptr idx0(uptr idx) const { + uptr res = idx / (BV::kSize * BV::kSize); + CHECK_LE(res, kLevel1Size); + return res; + } + + uptr idx1(uptr idx) const { + uptr res = (idx / BV::kSize) % BV::kSize; + CHECK_LE(res, BV::kSize); + return res; + } + + uptr idx2(uptr idx) const { + uptr res = idx % BV::kSize; + CHECK_LE(res, BV::kSize); + return res; + } + + BV l1_[kLevel1Size]; + BV l2_[kLevel1Size][BV::kSize]; +}; + +} // namespace __sanitizer + +#endif // SANITIZER_BITVECTOR_H diff --git a/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_bvgraph.h b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_bvgraph.h new file mode 100644 index 0000000000..e7249055be --- /dev/null +++ b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_bvgraph.h @@ -0,0 +1,164 @@ +//===-- sanitizer_bvgraph.h -------------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file is a part of Sanitizer runtime. +// BVGraph -- a directed graph. +// +//===----------------------------------------------------------------------===// + +#ifndef SANITIZER_BVGRAPH_H +#define SANITIZER_BVGRAPH_H + +#include "sanitizer_common.h" +#include "sanitizer_bitvector.h" + +namespace __sanitizer { + +// Directed graph of fixed size implemented as an array of bit vectors. +// Not thread-safe, all accesses should be protected by an external lock. +template<class BV> +class BVGraph { + public: + enum SizeEnum : uptr { kSize = BV::kSize }; + uptr size() const { return kSize; } + // No CTOR. + void clear() { + for (uptr i = 0; i < size(); i++) + v[i].clear(); + } + + bool empty() const { + for (uptr i = 0; i < size(); i++) + if (!v[i].empty()) + return false; + return true; + } + + // Returns true if a new edge was added. + bool addEdge(uptr from, uptr to) { + check(from, to); + return v[from].setBit(to); + } + + // Returns true if at least one new edge was added. + uptr addEdges(const BV &from, uptr to, uptr added_edges[], + uptr max_added_edges) { + uptr res = 0; + t1.copyFrom(from); + while (!t1.empty()) { + uptr node = t1.getAndClearFirstOne(); + if (v[node].setBit(to)) + if (res < max_added_edges) + added_edges[res++] = node; + } + return res; + } + + // *EXPERIMENTAL* + // Returns true if an edge from=>to exist. + // This function does not use any global state except for 'this' itself, + // and thus can be called from different threads w/o locking. + // This would be racy. + // FIXME: investigate how much we can prove about this race being "benign". + bool hasEdge(uptr from, uptr to) { return v[from].getBit(to); } + + // Returns true if the edge from=>to was removed. + bool removeEdge(uptr from, uptr to) { + return v[from].clearBit(to); + } + + // Returns true if at least one edge *=>to was removed. + bool removeEdgesTo(const BV &to) { + bool res = 0; + for (uptr from = 0; from < size(); from++) { + if (v[from].setDifference(to)) + res = true; + } + return res; + } + + // Returns true if at least one edge from=>* was removed. + bool removeEdgesFrom(const BV &from) { + bool res = false; + t1.copyFrom(from); + while (!t1.empty()) { + uptr idx = t1.getAndClearFirstOne(); + if (!v[idx].empty()) { + v[idx].clear(); + res = true; + } + } + return res; + } + + void removeEdgesFrom(uptr from) { + return v[from].clear(); + } + + bool hasEdge(uptr from, uptr to) const { + check(from, to); + return v[from].getBit(to); + } + + // Returns true if there is a path from the node 'from' + // to any of the nodes in 'targets'. + bool isReachable(uptr from, const BV &targets) { + BV &to_visit = t1, + &visited = t2; + to_visit.copyFrom(v[from]); + visited.clear(); + visited.setBit(from); + while (!to_visit.empty()) { + uptr idx = to_visit.getAndClearFirstOne(); + if (visited.setBit(idx)) + to_visit.setUnion(v[idx]); + } + return targets.intersectsWith(visited); + } + + // Finds a path from 'from' to one of the nodes in 'target', + // stores up to 'path_size' items of the path into 'path', + // returns the path length, or 0 if there is no path of size 'path_size'. + uptr findPath(uptr from, const BV &targets, uptr *path, uptr path_size) { + if (path_size == 0) + return 0; + path[0] = from; + if (targets.getBit(from)) + return 1; + // The function is recursive, so we don't want to create BV on stack. + // Instead of a getAndClearFirstOne loop we use the slower iterator. + for (typename BV::Iterator it(v[from]); it.hasNext(); ) { + uptr idx = it.next(); + if (uptr res = findPath(idx, targets, path + 1, path_size - 1)) + return res + 1; + } + return 0; + } + + // Same as findPath, but finds a shortest path. + uptr findShortestPath(uptr from, const BV &targets, uptr *path, + uptr path_size) { + for (uptr p = 1; p <= path_size; p++) + if (findPath(from, targets, path, p) == p) + return p; + return 0; + } + + private: + void check(uptr idx1, uptr idx2) const { + CHECK_LT(idx1, size()); + CHECK_LT(idx2, size()); + } + BV v[kSize]; + // Keep temporary vectors here since we can not create large objects on stack. + BV t1, t2; +}; + +} // namespace __sanitizer + +#endif // SANITIZER_BVGRAPH_H diff --git a/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_chained_origin_depot.cpp b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_chained_origin_depot.cpp new file mode 100644 index 0000000000..472b83d63a --- /dev/null +++ b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_chained_origin_depot.cpp @@ -0,0 +1,146 @@ +//===-- sanitizer_chained_origin_depot.cpp --------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// A storage for chained origins. +//===----------------------------------------------------------------------===// + +#include "sanitizer_chained_origin_depot.h" + +#include "sanitizer_stackdepotbase.h" + +namespace __sanitizer { + +namespace { +struct ChainedOriginDepotDesc { + u32 here_id; + u32 prev_id; +}; + +struct ChainedOriginDepotNode { + using hash_type = u32; + u32 link; + u32 here_id; + u32 prev_id; + + typedef ChainedOriginDepotDesc args_type; + + bool eq(hash_type hash, const args_type &args) const; + + static uptr allocated() { return 0; } + + static hash_type hash(const args_type &args); + + static bool is_valid(const args_type &args); + + void store(u32 id, const args_type &args, hash_type other_hash); + + args_type load(u32 id) const; + + struct Handle { + const ChainedOriginDepotNode *node_ = nullptr; + u32 id_ = 0; + Handle(const ChainedOriginDepotNode *node, u32 id) : node_(node), id_(id) {} + bool valid() const { return node_; } + u32 id() const { return id_; } + int here_id() const { return node_->here_id; } + int prev_id() const { return node_->prev_id; } + }; + + static Handle get_handle(u32 id); + + typedef Handle handle_type; +}; + +} // namespace + +static StackDepotBase<ChainedOriginDepotNode, 4, 20> depot; + +bool ChainedOriginDepotNode::eq(hash_type hash, const args_type &args) const { + return here_id == args.here_id && prev_id == args.prev_id; +} + +/* This is murmur2 hash for the 64->32 bit case. + It does not behave all that well because the keys have a very biased + distribution (I've seen 7-element buckets with the table only 14% full). + + here_id is built of + * (1 bits) Reserved, zero. + * (8 bits) Part id = bits 13..20 of the hash value of here_id's key. + * (23 bits) Sequential number (each part has each own sequence). + + prev_id has either the same distribution as here_id (but with 3:8:21) + split, or one of two reserved values (-1) or (-2). Either case can + dominate depending on the workload. +*/ +ChainedOriginDepotNode::hash_type ChainedOriginDepotNode::hash( + const args_type &args) { + const u32 m = 0x5bd1e995; + const u32 seed = 0x9747b28c; + const u32 r = 24; + u32 h = seed; + u32 k = args.here_id; + k *= m; + k ^= k >> r; + k *= m; + h *= m; + h ^= k; + + k = args.prev_id; + k *= m; + k ^= k >> r; + k *= m; + h *= m; + h ^= k; + + h ^= h >> 13; + h *= m; + h ^= h >> 15; + return h; +} + +bool ChainedOriginDepotNode::is_valid(const args_type &args) { return true; } + +void ChainedOriginDepotNode::store(u32 id, const args_type &args, + hash_type other_hash) { + here_id = args.here_id; + prev_id = args.prev_id; +} + +ChainedOriginDepotNode::args_type ChainedOriginDepotNode::load(u32 id) const { + args_type ret = {here_id, prev_id}; + return ret; +} + +ChainedOriginDepotNode::Handle ChainedOriginDepotNode::get_handle(u32 id) { + return Handle(&depot.nodes[id], id); +} + +ChainedOriginDepot::ChainedOriginDepot() {} + +StackDepotStats ChainedOriginDepot::GetStats() const { + return depot.GetStats(); +} + +bool ChainedOriginDepot::Put(u32 here_id, u32 prev_id, u32 *new_id) { + ChainedOriginDepotDesc desc = {here_id, prev_id}; + bool inserted; + *new_id = depot.Put(desc, &inserted); + return inserted; +} + +u32 ChainedOriginDepot::Get(u32 id, u32 *other) { + ChainedOriginDepotDesc desc = depot.Get(id); + *other = desc.prev_id; + return desc.here_id; +} + +void ChainedOriginDepot::LockAll() { depot.LockAll(); } + +void ChainedOriginDepot::UnlockAll() { depot.UnlockAll(); } + +} // namespace __sanitizer diff --git a/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_chained_origin_depot.h b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_chained_origin_depot.h new file mode 100644 index 0000000000..2e800964a4 --- /dev/null +++ b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_chained_origin_depot.h @@ -0,0 +1,45 @@ +//===-- sanitizer_chained_origin_depot.h ------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// A storage for chained origins. +//===----------------------------------------------------------------------===// + +#ifndef SANITIZER_CHAINED_ORIGIN_DEPOT_H +#define SANITIZER_CHAINED_ORIGIN_DEPOT_H + +#include "sanitizer_common.h" + +namespace __sanitizer { + +class ChainedOriginDepot { + public: + ChainedOriginDepot(); + + // Gets the statistic of the origin chain storage. + StackDepotStats GetStats() const; + + // Stores a chain with StackDepot ID here_id and previous chain ID prev_id. + // If successful, returns true and the new chain id new_id. + // If the same element already exists, returns false and sets new_id to the + // existing ID. + bool Put(u32 here_id, u32 prev_id, u32 *new_id); + + // Retrieves the stored StackDepot ID for the given origin ID. + u32 Get(u32 id, u32 *other); + + void LockAll(); + void UnlockAll(); + + private: + ChainedOriginDepot(const ChainedOriginDepot &) = delete; + void operator=(const ChainedOriginDepot &) = delete; +}; + +} // namespace __sanitizer + +#endif // SANITIZER_CHAINED_ORIGIN_DEPOT_H diff --git a/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_common.cpp b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_common.cpp new file mode 100644 index 0000000000..e9379b7bdc --- /dev/null +++ b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_common.cpp @@ -0,0 +1,371 @@ +//===-- sanitizer_common.cpp ----------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file is shared between AddressSanitizer and ThreadSanitizer +// run-time libraries. +//===----------------------------------------------------------------------===// + +#include "sanitizer_common.h" +#include "sanitizer_allocator_interface.h" +#include "sanitizer_allocator_internal.h" +#include "sanitizer_atomic.h" +#include "sanitizer_flags.h" +#include "sanitizer_libc.h" +#include "sanitizer_placement_new.h" + +namespace __sanitizer { + +const char *SanitizerToolName = "SanitizerTool"; + +atomic_uint32_t current_verbosity; +uptr PageSizeCached; +u32 NumberOfCPUsCached; + +// PID of the tracer task in StopTheWorld. It shares the address space with the +// main process, but has a different PID and thus requires special handling. +uptr stoptheworld_tracer_pid = 0; +// Cached pid of parent process - if the parent process dies, we want to keep +// writing to the same log file. +uptr stoptheworld_tracer_ppid = 0; + +void NORETURN ReportMmapFailureAndDie(uptr size, const char *mem_type, + const char *mmap_type, error_t err, + bool raw_report) { + static int recursion_count; + if (raw_report || recursion_count) { + // If raw report is requested or we went into recursion just die. The + // Report() and CHECK calls below may call mmap recursively and fail. + RawWrite("ERROR: Failed to mmap\n"); + Die(); + } + recursion_count++; + Report("ERROR: %s failed to " + "%s 0x%zx (%zd) bytes of %s (error code: %d)\n", + SanitizerToolName, mmap_type, size, size, mem_type, err); +#if !SANITIZER_GO + DumpProcessMap(); +#endif + UNREACHABLE("unable to mmap"); +} + +typedef bool UptrComparisonFunction(const uptr &a, const uptr &b); +typedef bool U32ComparisonFunction(const u32 &a, const u32 &b); + +const char *StripPathPrefix(const char *filepath, + const char *strip_path_prefix) { + if (!filepath) return nullptr; + if (!strip_path_prefix) return filepath; + const char *res = filepath; + if (const char *pos = internal_strstr(filepath, strip_path_prefix)) + res = pos + internal_strlen(strip_path_prefix); + if (res[0] == '.' && res[1] == '/') + res += 2; + return res; +} + +const char *StripModuleName(const char *module) { + if (!module) + return nullptr; + if (SANITIZER_WINDOWS) { + // On Windows, both slash and backslash are possible. + // Pick the one that goes last. + if (const char *bslash_pos = internal_strrchr(module, '\\')) + return StripModuleName(bslash_pos + 1); + } + if (const char *slash_pos = internal_strrchr(module, '/')) { + return slash_pos + 1; + } + return module; +} + +void ReportErrorSummary(const char *error_message, const char *alt_tool_name) { + if (!common_flags()->print_summary) + return; + InternalScopedString buff; + buff.append("SUMMARY: %s: %s", + alt_tool_name ? alt_tool_name : SanitizerToolName, error_message); + __sanitizer_report_error_summary(buff.data()); +} + +// Removes the ANSI escape sequences from the input string (in-place). +void RemoveANSIEscapeSequencesFromString(char *str) { + if (!str) + return; + + // We are going to remove the escape sequences in place. + char *s = str; + char *z = str; + while (*s != '\0') { + CHECK_GE(s, z); + // Skip over ANSI escape sequences with pointer 's'. + if (*s == '\033' && *(s + 1) == '[') { + s = internal_strchrnul(s, 'm'); + if (*s == '\0') { + break; + } + s++; + continue; + } + // 's' now points at a character we want to keep. Copy over the buffer + // content if the escape sequence has been perviously skipped andadvance + // both pointers. + if (s != z) + *z = *s; + + // If we have not seen an escape sequence, just advance both pointers. + z++; + s++; + } + + // Null terminate the string. + *z = '\0'; +} + +void LoadedModule::set(const char *module_name, uptr base_address) { + clear(); + full_name_ = internal_strdup(module_name); + base_address_ = base_address; +} + +void LoadedModule::set(const char *module_name, uptr base_address, + ModuleArch arch, u8 uuid[kModuleUUIDSize], + bool instrumented) { + set(module_name, base_address); + arch_ = arch; + internal_memcpy(uuid_, uuid, sizeof(uuid_)); + uuid_size_ = kModuleUUIDSize; + instrumented_ = instrumented; +} + +void LoadedModule::setUuid(const char *uuid, uptr size) { + if (size > kModuleUUIDSize) + size = kModuleUUIDSize; + internal_memcpy(uuid_, uuid, size); + uuid_size_ = size; +} + +void LoadedModule::clear() { + InternalFree(full_name_); + base_address_ = 0; + max_executable_address_ = 0; + full_name_ = nullptr; + arch_ = kModuleArchUnknown; + internal_memset(uuid_, 0, kModuleUUIDSize); + instrumented_ = false; + while (!ranges_.empty()) { + AddressRange *r = ranges_.front(); + ranges_.pop_front(); + InternalFree(r); + } +} + +void LoadedModule::addAddressRange(uptr beg, uptr end, bool executable, + bool writable, const char *name) { + void *mem = InternalAlloc(sizeof(AddressRange)); + AddressRange *r = + new(mem) AddressRange(beg, end, executable, writable, name); + ranges_.push_back(r); + if (executable && end > max_executable_address_) + max_executable_address_ = end; +} + +bool LoadedModule::containsAddress(uptr address) const { + for (const AddressRange &r : ranges()) { + if (r.beg <= address && address < r.end) + return true; + } + return false; +} + +static atomic_uintptr_t g_total_mmaped; + +void IncreaseTotalMmap(uptr size) { + if (!common_flags()->mmap_limit_mb) return; + uptr total_mmaped = + atomic_fetch_add(&g_total_mmaped, size, memory_order_relaxed) + size; + // Since for now mmap_limit_mb is not a user-facing flag, just kill + // a program. Use RAW_CHECK to avoid extra mmaps in reporting. + RAW_CHECK((total_mmaped >> 20) < common_flags()->mmap_limit_mb); +} + +void DecreaseTotalMmap(uptr size) { + if (!common_flags()->mmap_limit_mb) return; + atomic_fetch_sub(&g_total_mmaped, size, memory_order_relaxed); +} + +bool TemplateMatch(const char *templ, const char *str) { + if ((!str) || str[0] == 0) + return false; + bool start = false; + if (templ && templ[0] == '^') { + start = true; + templ++; + } + bool asterisk = false; + while (templ && templ[0]) { + if (templ[0] == '*') { + templ++; + start = false; + asterisk = true; + continue; + } + if (templ[0] == '$') + return str[0] == 0 || asterisk; + if (str[0] == 0) + return false; + char *tpos = (char*)internal_strchr(templ, '*'); + char *tpos1 = (char*)internal_strchr(templ, '$'); + if ((!tpos) || (tpos1 && tpos1 < tpos)) + tpos = tpos1; + if (tpos) + tpos[0] = 0; + const char *str0 = str; + const char *spos = internal_strstr(str, templ); + str = spos + internal_strlen(templ); + templ = tpos; + if (tpos) + tpos[0] = tpos == tpos1 ? '$' : '*'; + if (!spos) + return false; + if (start && spos != str0) + return false; + start = false; + asterisk = false; + } + return true; +} + +static char binary_name_cache_str[kMaxPathLength]; +static char process_name_cache_str[kMaxPathLength]; + +const char *GetProcessName() { + return process_name_cache_str; +} + +static uptr ReadProcessName(/*out*/ char *buf, uptr buf_len) { + ReadLongProcessName(buf, buf_len); + char *s = const_cast<char *>(StripModuleName(buf)); + uptr len = internal_strlen(s); + if (s != buf) { + internal_memmove(buf, s, len); + buf[len] = '\0'; + } + return len; +} + +void UpdateProcessName() { + ReadProcessName(process_name_cache_str, sizeof(process_name_cache_str)); +} + +// Call once to make sure that binary_name_cache_str is initialized +void CacheBinaryName() { + if (binary_name_cache_str[0] != '\0') + return; + ReadBinaryName(binary_name_cache_str, sizeof(binary_name_cache_str)); + ReadProcessName(process_name_cache_str, sizeof(process_name_cache_str)); +} + +uptr ReadBinaryNameCached(/*out*/char *buf, uptr buf_len) { + CacheBinaryName(); + uptr name_len = internal_strlen(binary_name_cache_str); + name_len = (name_len < buf_len - 1) ? name_len : buf_len - 1; + if (buf_len == 0) + return 0; + internal_memcpy(buf, binary_name_cache_str, name_len); + buf[name_len] = '\0'; + return name_len; +} + +uptr ReadBinaryDir(/*out*/ char *buf, uptr buf_len) { + ReadBinaryNameCached(buf, buf_len); + const char *exec_name_pos = StripModuleName(buf); + uptr name_len = exec_name_pos - buf; + buf[name_len] = '\0'; + return name_len; +} + +#if !SANITIZER_GO +void PrintCmdline() { + char **argv = GetArgv(); + if (!argv) return; + Printf("\nCommand: "); + for (uptr i = 0; argv[i]; ++i) + Printf("%s ", argv[i]); + Printf("\n\n"); +} +#endif + +// Malloc hooks. +static const int kMaxMallocFreeHooks = 5; +struct MallocFreeHook { + void (*malloc_hook)(const void *, uptr); + void (*free_hook)(const void *); +}; + +static MallocFreeHook MFHooks[kMaxMallocFreeHooks]; + +void RunMallocHooks(const void *ptr, uptr size) { + for (int i = 0; i < kMaxMallocFreeHooks; i++) { + auto hook = MFHooks[i].malloc_hook; + if (!hook) return; + hook(ptr, size); + } +} + +void RunFreeHooks(const void *ptr) { + for (int i = 0; i < kMaxMallocFreeHooks; i++) { + auto hook = MFHooks[i].free_hook; + if (!hook) return; + hook(ptr); + } +} + +static int InstallMallocFreeHooks(void (*malloc_hook)(const void *, uptr), + void (*free_hook)(const void *)) { + if (!malloc_hook || !free_hook) return 0; + for (int i = 0; i < kMaxMallocFreeHooks; i++) { + if (MFHooks[i].malloc_hook == nullptr) { + MFHooks[i].malloc_hook = malloc_hook; + MFHooks[i].free_hook = free_hook; + return i + 1; + } + } + return 0; +} + +void internal_sleep(unsigned seconds) { + internal_usleep((u64)seconds * 1000 * 1000); +} +void SleepForSeconds(unsigned seconds) { + internal_usleep((u64)seconds * 1000 * 1000); +} +void SleepForMillis(unsigned millis) { internal_usleep((u64)millis * 1000); } + +} // namespace __sanitizer + +using namespace __sanitizer; + +extern "C" { +SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_report_error_summary, + const char *error_summary) { + Printf("%s\n", error_summary); +} + +SANITIZER_INTERFACE_ATTRIBUTE +int __sanitizer_acquire_crash_state() { + static atomic_uint8_t in_crash_state = {}; + return !atomic_exchange(&in_crash_state, 1, memory_order_relaxed); +} + +SANITIZER_INTERFACE_ATTRIBUTE +int __sanitizer_install_malloc_and_free_hooks(void (*malloc_hook)(const void *, + uptr), + void (*free_hook)(const void *)) { + return InstallMallocFreeHooks(malloc_hook, free_hook); +} +} // extern "C" diff --git a/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_common.h b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_common.h new file mode 100644 index 0000000000..3302590c67 --- /dev/null +++ b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_common.h @@ -0,0 +1,1078 @@ +//===-- sanitizer_common.h --------------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// 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" + +#if defined(_MSC_VER) && !defined(__clang__) +extern "C" void _ReadWriteBarrier(); +#pragma intrinsic(_ReadWriteBarrier) +#endif + +namespace __sanitizer { + +struct AddressInfo; +struct BufferedStackTrace; +struct SignalContext; +struct StackTrace; + +// Constants. +const uptr kWordSize = SANITIZER_WORDSIZE / 8; +const uptr kWordSizeInBits = 8 * kWordSize; + +const uptr kCacheLineSize = SANITIZER_CACHE_LINE_SIZE; + +const uptr kMaxPathLength = 4096; + +const uptr kMaxThreadStackSize = 1 << 30; // 1Gb + +const uptr kErrorMessageBufferSize = 1 << 16; + +// Denotes fake PC values that come from JIT/JAVA/etc. +// For such PC values __tsan_symbolize_external_ex() will be called. +const u64 kExternalPCBit = 1ULL << 60; + +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); +} + +#if SANITIZER_ANDROID +inline uptr GetPageSize() { +// Android post-M sysconf(_SC_PAGESIZE) crashes if called from .preinit_array. + return 4096; +} +inline uptr GetPageSizeCached() { + return 4096; +} +#else +uptr GetPageSize(); +extern uptr PageSizeCached; +inline uptr GetPageSizeCached() { + if (!PageSizeCached) + PageSizeCached = GetPageSize(); + return PageSizeCached; +} +#endif +uptr GetMmapGranularity(); +uptr GetMaxVirtualAddress(); +uptr GetMaxUserVirtualAddress(); +// Threads +tid_t GetTid(); +int TgKill(pid_t pid, tid_t tid, int sig); +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, bool raw_report = false); +inline void *MmapOrDieQuietly(uptr size, const char *mem_type) { + return MmapOrDie(size, mem_type, /*raw_report*/ true); +} +void UnmapOrDie(void *addr, uptr size); +// Behaves just like MmapOrDie, but tolerates out of memory condition, in that +// case returns nullptr. +void *MmapOrDieOnFatalError(uptr size, const char *mem_type); +bool MmapFixedNoReserve(uptr fixed_addr, uptr size, const char *name = nullptr) + WARN_UNUSED_RESULT; +bool MmapFixedSuperNoReserve(uptr fixed_addr, uptr size, + const char *name = nullptr) WARN_UNUSED_RESULT; +void *MmapNoReserveOrDie(uptr size, const char *mem_type); +void *MmapFixedOrDie(uptr fixed_addr, uptr size, const char *name = nullptr); +// Behaves just like MmapFixedOrDie, but tolerates out of memory condition, in +// that case returns nullptr. +void *MmapFixedOrDieOnFatalError(uptr fixed_addr, uptr size, + const char *name = nullptr); +void *MmapFixedNoAccess(uptr fixed_addr, uptr size, const char *name = nullptr); +void *MmapNoAccess(uptr size); +// Map aligned chunk of address space; size and alignment are powers of two. +// Dies on all but out of memory errors, in the latter case returns nullptr. +void *MmapAlignedOrDieOnFatalError(uptr size, uptr alignment, + const char *mem_type); +// Disallow access to a memory range. Use MmapFixedNoAccess to allocate an +// unaccessible memory. +bool MprotectNoAccess(uptr addr, uptr size); +bool MprotectReadOnly(uptr addr, uptr size); + +void MprotectMallocZones(void *addr, int prot); + +#if SANITIZER_LINUX +// Unmap memory. Currently only used on Linux. +void UnmapFromTo(uptr from, uptr to); +#endif + +// Maps shadow_size_bytes of shadow memory and returns shadow address. It will +// be aligned to the mmap granularity * 2^shadow_scale, or to +// 2^min_shadow_base_alignment if that is larger. The returned address will +// have max(2^min_shadow_base_alignment, mmap granularity) on the left, and +// shadow_size_bytes bytes on the right, which on linux is mapped no access. +// The high_mem_end may be updated if the original shadow size doesn't fit. +uptr MapDynamicShadow(uptr shadow_size_bytes, uptr shadow_scale, + uptr min_shadow_base_alignment, uptr &high_mem_end); + +// Let S = max(shadow_size, num_aliases * alias_size, ring_buffer_size). +// Reserves 2*S bytes of address space to the right of the returned address and +// ring_buffer_size bytes to the left. The returned address is aligned to 2*S. +// Also creates num_aliases regions of accessible memory starting at offset S +// from the returned address. Each region has size alias_size and is backed by +// the same physical memory. +uptr MapDynamicShadowAndAliases(uptr shadow_size, uptr alias_size, + uptr num_aliases, uptr ring_buffer_size); + +// Reserve memory range [beg, end]. If madvise_shadow is true then apply +// madvise (e.g. hugepages, core dumping) requested by options. +void ReserveShadowMemoryRange(uptr beg, uptr end, const char *name, + bool madvise_shadow = true); + +// Protect size bytes of memory starting at addr. Also try to protect +// several pages at the start of the address space as specified by +// zero_base_shadow_start, at most up to the size or zero_base_max_shadow_start. +void ProtectGap(uptr addr, uptr size, uptr zero_base_shadow_start, + uptr zero_base_max_shadow_start); + +// Find an available address space. +uptr FindAvailableMemoryRange(uptr size, uptr alignment, uptr left_padding, + uptr *largest_gap_found, uptr *max_occupied_addr); + +// Used to check if we can map shadow memory to a fixed location. +bool MemoryRangeIsAvailable(uptr range_start, uptr range_end); +// Releases memory pages entirely within the [beg, end] address range. Noop if +// the provided range does not contain at least one entire page. +void ReleaseMemoryPagesToOS(uptr beg, uptr end); +void IncreaseTotalMmap(uptr size); +void DecreaseTotalMmap(uptr size); +uptr GetRSS(); +void SetShadowRegionHugePageMode(uptr addr, uptr length); +bool DontDumpShadowMemory(uptr addr, uptr length); +// Check if the built VMA size matches the runtime one. +void CheckVMASize(); +void RunMallocHooks(const void *ptr, uptr size); +void RunFreeHooks(const void *ptr); + +class ReservedAddressRange { + public: + uptr Init(uptr size, const char *name = nullptr, uptr fixed_addr = 0); + uptr InitAligned(uptr size, uptr align, const char *name = nullptr); + uptr Map(uptr fixed_addr, uptr size, const char *name = nullptr); + uptr MapOrDie(uptr fixed_addr, uptr size, const char *name = nullptr); + void Unmap(uptr addr, uptr size); + void *base() const { return base_; } + uptr size() const { return size_; } + + private: + void* base_; + uptr size_; + const char* name_; + uptr os_handle_; +}; + +typedef void (*fill_profile_f)(uptr start, uptr rss, bool file, + /*out*/ uptr *stats); + +// Parse the contents of /proc/self/smaps and generate a memory profile. +// |cb| is a tool-specific callback that fills the |stats| array. +void GetMemoryProfile(fill_profile_f cb, uptr *stats); +void ParseUnixMemoryProfile(fill_profile_f cb, uptr *stats, char *smaps, + uptr smaps_len); + +// 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_; +}; +// Set the min alignment of LowLevelAllocator to at least alignment. +void SetLowLevelAllocateMinAlignment(uptr alignment); +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 CatastrophicErrorWrite(const char *buffer, uptr length); +void RawWrite(const char *buffer); +bool ColorizeReports(); +void RemoveANSIEscapeSequencesFromString(char *buffer); +void Printf(const char *format, ...) FORMAT(1, 2); +void Report(const char *format, ...) FORMAT(1, 2); +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) + +// Lock sanitizer error reporting and protects against nested errors. +class ScopedErrorReportLock { + public: + ScopedErrorReportLock() SANITIZER_ACQUIRE(mutex_) { Lock(); } + ~ScopedErrorReportLock() SANITIZER_RELEASE(mutex_) { Unlock(); } + + static void Lock() SANITIZER_ACQUIRE(mutex_); + static void Unlock() SANITIZER_RELEASE(mutex_); + static void CheckLocked() SANITIZER_CHECK_LOCKED(mutex_); + + private: + static atomic_uintptr_t reporting_thread_; + static StaticSpinMutex mutex_; +}; + +extern uptr stoptheworld_tracer_pid; +extern uptr stoptheworld_tracer_ppid; + +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 +uptr ReadBinaryName(/*out*/char *buf, uptr buf_len); +uptr ReadBinaryNameCached(/*out*/char *buf, uptr buf_len); +uptr ReadBinaryDir(/*out*/ char *buf, uptr buf_len); +uptr ReadLongProcessName(/*out*/ char *buf, uptr buf_len); +const char *GetProcessName(); +void UpdateProcessName(); +void CacheBinaryName(); +void DisableCoreDumperIfNecessary(); +void DumpProcessMap(); +const char *GetEnv(const char *name); +bool SetEnv(const char *name, const char *value); + +u32 GetUid(); +void ReExec(); +void CheckASLR(); +void CheckMPROTECT(); +char **GetArgv(); +char **GetEnviron(); +void PrintCmdline(); +bool StackSizeIsUnlimited(); +void SetStackSizeLimitInBytes(uptr limit); +bool AddressSpaceIsUnlimited(); +void SetAddressSpaceUnlimited(); +void AdjustStackSize(void *attr); +void PlatformPrepareForSandboxing(__sanitizer_sandbox_arguments *args); +void SetSandboxingCallback(void (*f)()); + +void InitializeCoverage(bool enabled, const char *coverage_dir); + +void InitTlsSize(); +uptr GetTlsSize(); + +// Other +void SleepForSeconds(unsigned seconds); +void SleepForMillis(unsigned millis); +u64 NanoTime(); +u64 MonotonicNanoTime(); +int Atexit(void (*function)(void)); +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); +void NORETURN ReportMmapFailureAndDie(uptr size, const char *mem_type, + const char *mmap_type, error_t err, + bool raw_report = false); + +// Specific tools may override behavior of "Die" function to do tool-specific +// job. +typedef void (*DieCallbackType)(void); + +// It's possible to add several callbacks that would be run when "Die" is +// called. The callbacks will be run in the opposite order. The tools are +// strongly recommended to setup all callbacks during initialization, when there +// is only a single thread. +bool AddDieCallback(DieCallbackType callback); +bool RemoveDieCallback(DieCallbackType callback); + +void SetUserDieCallback(DieCallbackType callback); + +void SetCheckUnwindCallback(void (*callback)()); + +// Functions related to signal handling. +typedef void (*SignalHandlerType)(int, void *, void *); +HandleSignalMode GetHandleSignalMode(int signum); +void InstallDeadlySignalHandlers(SignalHandlerType handler); + +// Signal reporting. +// Each sanitizer uses slightly different implementation of stack unwinding. +typedef void (*UnwindSignalStackCallbackType)(const SignalContext &sig, + const void *callback_context, + BufferedStackTrace *stack); +// Print deadly signal report and die. +void HandleDeadlySignal(void *siginfo, void *context, u32 tid, + UnwindSignalStackCallbackType unwind, + const void *unwind_context); + +// Part of HandleDeadlySignal, exposed for asan. +void StartReportDeadlySignal(); +// Part of HandleDeadlySignal, exposed for asan. +void ReportDeadlySignal(const SignalContext &sig, u32 tid, + UnwindSignalStackCallbackType unwind, + const void *unwind_context); + +// Alternative signal stack (POSIX-only). +void SetAlternateSignalStack(); +void UnsetAlternateSignalStack(); + +// Construct a one-line string: +// SUMMARY: SanitizerToolName: error_message +// and pass it to __sanitizer_report_error_summary. +// If alt_tool_name is provided, it's used in place of SanitizerToolName. +void ReportErrorSummary(const char *error_message, + const char *alt_tool_name = nullptr); +// Same as above, but construct error_message as: +// error_type file:line[:column][ function] +void ReportErrorSummary(const char *error_type, const AddressInfo &info, + const char *alt_tool_name = nullptr); +// Same as above, but obtains AddressInfo by symbolizing top stack trace frame. +void ReportErrorSummary(const char *error_type, const StackTrace *trace, + const char *alt_tool_name = nullptr); + +void ReportMmapWriteExec(int prot, int mflags); + +// Math +#if SANITIZER_WINDOWS && !defined(__clang__) && !defined(__GNUC__) +extern "C" { +unsigned char _BitScanForward(unsigned long *index, unsigned long mask); +unsigned char _BitScanReverse(unsigned long *index, unsigned long mask); +#if defined(_WIN64) +unsigned char _BitScanForward64(unsigned long *index, unsigned __int64 mask); +unsigned char _BitScanReverse64(unsigned long *index, unsigned __int64 mask); +#endif +} +#endif + +inline uptr MostSignificantSetBitIndex(uptr x) { + CHECK_NE(x, 0U); + unsigned long up; +#if !SANITIZER_WINDOWS || defined(__clang__) || defined(__GNUC__) +# ifdef _WIN64 + up = SANITIZER_WORDSIZE - 1 - __builtin_clzll(x); +# else + up = SANITIZER_WORDSIZE - 1 - __builtin_clzl(x); +# endif +#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; +#if !SANITIZER_WINDOWS || defined(__clang__) || defined(__GNUC__) +# ifdef _WIN64 + up = __builtin_ctzll(x); +# else + up = __builtin_ctzl(x); +# endif +#elif defined(_WIN64) + _BitScanForward64(&up, x); +#else + _BitScanForward(&up, x); +#endif + return up; +} + +inline constexpr 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_LT(size, (1ULL << (up + 1))); + CHECK_GT(size, (1ULL << up)); + return 1ULL << (up + 1); +} + +inline constexpr uptr RoundUpTo(uptr size, uptr boundary) { + RAW_CHECK(IsPowerOfTwo(boundary)); + return (size + boundary - 1) & ~(boundary - 1); +} + +inline constexpr uptr RoundDownTo(uptr x, uptr boundary) { + return x & ~(boundary - 1); +} + +inline constexpr bool IsAligned(uptr a, uptr alignment) { + return (a & (alignment - 1)) == 0; +} + +inline uptr Log2(uptr x) { + CHECK(IsPowerOfTwo(x)); + return LeastSignificantSetBitIndex(x); +} + +// Don't use std::min, std::max or std::swap, to minimize dependency +// on libstdc++. +template <class T> +constexpr T Min(T a, T b) { + return a < b ? a : b; +} +template <class T> +constexpr T Max(T a, T b) { + return a > b ? a : b; +} +template <class T> +constexpr T Abs(T a) { + return a < 0 ? -a : a; +} +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: + using value_type = T; + void Initialize(uptr initial_capacity) { + capacity_bytes_ = 0; + size_ = 0; + data_ = 0; + reserve(initial_capacity); + } + void Destroy() { UnmapOrDie(data_, capacity_bytes_); } + 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); + Realloc(new_capacity); + } + internal_memcpy(&data_[size_++], &element, sizeof(T)); + } + 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_; + } + T *data() { + return data_; + } + uptr capacity() const { return capacity_bytes_ / sizeof(T); } + void reserve(uptr new_size) { + // Never downsize internal buffer. + if (new_size > capacity()) + Realloc(new_size); + } + void resize(uptr new_size) { + if (new_size > size_) { + reserve(new_size); + internal_memset(&data_[size_], 0, sizeof(T) * (new_size - size_)); + } + size_ = new_size; + } + + void clear() { size_ = 0; } + bool empty() const { return size() == 0; } + + const T *begin() const { + return data(); + } + T *begin() { + return data(); + } + const T *end() const { + return data() + size(); + } + T *end() { + return data() + size(); + } + + void swap(InternalMmapVectorNoCtor &other) { + Swap(data_, other.data_); + Swap(capacity_bytes_, other.capacity_bytes_); + Swap(size_, other.size_); + } + + private: + void Realloc(uptr new_capacity) { + CHECK_GT(new_capacity, 0); + CHECK_LE(size_, new_capacity); + uptr new_capacity_bytes = + RoundUpTo(new_capacity * sizeof(T), GetPageSizeCached()); + T *new_data = (T *)MmapOrDie(new_capacity_bytes, "InternalMmapVector"); + internal_memcpy(new_data, data_, size_ * sizeof(T)); + UnmapOrDie(data_, capacity_bytes_); + data_ = new_data; + capacity_bytes_ = new_capacity_bytes; + } + + T *data_; + uptr capacity_bytes_; + uptr size_; +}; + +template <typename T> +bool operator==(const InternalMmapVectorNoCtor<T> &lhs, + const InternalMmapVectorNoCtor<T> &rhs) { + if (lhs.size() != rhs.size()) return false; + return internal_memcmp(lhs.data(), rhs.data(), lhs.size() * sizeof(T)) == 0; +} + +template <typename T> +bool operator!=(const InternalMmapVectorNoCtor<T> &lhs, + const InternalMmapVectorNoCtor<T> &rhs) { + return !(lhs == rhs); +} + +template<typename T> +class InternalMmapVector : public InternalMmapVectorNoCtor<T> { + public: + InternalMmapVector() { InternalMmapVectorNoCtor<T>::Initialize(0); } + explicit InternalMmapVector(uptr cnt) { + InternalMmapVectorNoCtor<T>::Initialize(cnt); + this->resize(cnt); + } + ~InternalMmapVector() { InternalMmapVectorNoCtor<T>::Destroy(); } + // Disallow copies and moves. + InternalMmapVector(const InternalMmapVector &) = delete; + InternalMmapVector &operator=(const InternalMmapVector &) = delete; + InternalMmapVector(InternalMmapVector &&) = delete; + InternalMmapVector &operator=(InternalMmapVector &&) = delete; +}; + +class InternalScopedString { + public: + InternalScopedString() : buffer_(1) { buffer_[0] = '\0'; } + + uptr length() const { return buffer_.size() - 1; } + void clear() { + buffer_.resize(1); + buffer_[0] = '\0'; + } + void append(const char *format, ...) FORMAT(2, 3); + const char *data() const { return buffer_.data(); } + char *data() { return buffer_.data(); } + + private: + InternalMmapVector<char> buffer_; +}; + +template <class T> +struct CompareLess { + bool operator()(const T &a, const T &b) const { return a < b; } +}; + +// HeapSort for arrays and InternalMmapVector. +template <class T, class Compare = CompareLess<T>> +void Sort(T *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; + } + } +} + +// Works like std::lower_bound: finds the first element that is not less +// than the val. +template <class Container, class T, + class Compare = CompareLess<typename Container::value_type>> +uptr InternalLowerBound(const Container &v, const T &val, Compare comp = {}) { + uptr first = 0; + uptr last = v.size(); + while (last > first) { + uptr mid = (first + last) / 2; + if (comp(v[mid], val)) + first = mid + 1; + else + last = mid; + } + return first; +} + +enum ModuleArch { + kModuleArchUnknown, + kModuleArchI386, + kModuleArchX86_64, + kModuleArchX86_64H, + kModuleArchARMV6, + kModuleArchARMV7, + kModuleArchARMV7S, + kModuleArchARMV7K, + kModuleArchARM64, + kModuleArchRISCV64, + kModuleArchHexagon +}; + +// Sorts and removes duplicates from the container. +template <class Container, + class Compare = CompareLess<typename Container::value_type>> +void SortAndDedup(Container &v, Compare comp = {}) { + Sort(v.data(), v.size(), comp); + uptr size = v.size(); + if (size < 2) + return; + uptr last = 0; + for (uptr i = 1; i < size; ++i) { + if (comp(v[last], v[i])) { + ++last; + if (last != i) + v[last] = v[i]; + } else { + CHECK(!comp(v[i], v[last])); + } + } + v.resize(last + 1); +} + +constexpr uptr kDefaultFileMaxSize = FIRST_32_SECOND_64(1 << 26, 1 << 28); + +// Opens the file 'file_name" and reads up to 'max_len' bytes. +// The resulting buffer is mmaped and stored in '*buff'. +// Returns true if file was successfully opened and read. +bool ReadFileToVector(const char *file_name, + InternalMmapVectorNoCtor<char> *buff, + uptr max_len = kDefaultFileMaxSize, + error_t *errno_p = nullptr); + +// Opens the file 'file_name" and reads up to 'max_len' bytes. +// This function is less I/O efficient than ReadFileToVector as it may reread +// file multiple times to avoid mmap during read attempts. It's used to read +// procmap, so short reads with mmap in between can produce inconsistent result. +// The resulting buffer is mmaped and stored in '*buff'. +// The size of the mmaped region is stored in '*buff_size'. +// The total number of read bytes is stored in '*read_len'. +// Returns true if file was successfully opened and read. +bool ReadFileToBuffer(const char *file_name, char **buff, uptr *buff_size, + uptr *read_len, uptr max_len = kDefaultFileMaxSize, + error_t *errno_p = nullptr); + +// When adding a new architecture, don't forget to also update +// script/asan_symbolize.py and sanitizer_symbolizer_libcdep.cpp. +inline const char *ModuleArchToString(ModuleArch arch) { + switch (arch) { + case kModuleArchUnknown: + return ""; + case kModuleArchI386: + return "i386"; + case kModuleArchX86_64: + return "x86_64"; + case kModuleArchX86_64H: + return "x86_64h"; + case kModuleArchARMV6: + return "armv6"; + case kModuleArchARMV7: + return "armv7"; + case kModuleArchARMV7S: + return "armv7s"; + case kModuleArchARMV7K: + return "armv7k"; + case kModuleArchARM64: + return "arm64"; + case kModuleArchRISCV64: + return "riscv64"; + case kModuleArchHexagon: + return "hexagon"; + } + CHECK(0 && "Invalid module arch"); + return ""; +} + +const uptr kModuleUUIDSize = 32; +const uptr kMaxSegName = 16; + +// Represents a binary loaded into virtual memory (e.g. this can be an +// executable or a shared object). +class LoadedModule { + public: + LoadedModule() + : full_name_(nullptr), + base_address_(0), + max_executable_address_(0), + arch_(kModuleArchUnknown), + uuid_size_(0), + instrumented_(false) { + internal_memset(uuid_, 0, kModuleUUIDSize); + ranges_.clear(); + } + void set(const char *module_name, uptr base_address); + void set(const char *module_name, uptr base_address, ModuleArch arch, + u8 uuid[kModuleUUIDSize], bool instrumented); + void setUuid(const char *uuid, uptr size); + void clear(); + void addAddressRange(uptr beg, uptr end, bool executable, bool writable, + const char *name = nullptr); + bool containsAddress(uptr address) const; + + const char *full_name() const { return full_name_; } + uptr base_address() const { return base_address_; } + uptr max_executable_address() const { return max_executable_address_; } + ModuleArch arch() const { return arch_; } + const u8 *uuid() const { return uuid_; } + uptr uuid_size() const { return uuid_size_; } + bool instrumented() const { return instrumented_; } + + struct AddressRange { + AddressRange *next; + uptr beg; + uptr end; + bool executable; + bool writable; + char name[kMaxSegName]; + + AddressRange(uptr beg, uptr end, bool executable, bool writable, + const char *name) + : next(nullptr), + beg(beg), + end(end), + executable(executable), + writable(writable) { + internal_strncpy(this->name, (name ? name : ""), ARRAY_SIZE(this->name)); + } + }; + + const IntrusiveList<AddressRange> &ranges() const { return ranges_; } + + private: + char *full_name_; // Owned. + uptr base_address_; + uptr max_executable_address_; + ModuleArch arch_; + uptr uuid_size_; + u8 uuid_[kModuleUUIDSize]; + bool instrumented_; + IntrusiveList<AddressRange> ranges_; +}; + +// List of LoadedModules. OS-dependent implementation is responsible for +// filling this information. +class ListOfModules { + public: + ListOfModules() : initialized(false) {} + ~ListOfModules() { clear(); } + void init(); + void fallbackInit(); // Uses fallback init if available, otherwise clears + const LoadedModule *begin() const { return modules_.begin(); } + LoadedModule *begin() { return modules_.begin(); } + const LoadedModule *end() const { return modules_.end(); } + LoadedModule *end() { return modules_.end(); } + uptr size() const { return modules_.size(); } + const LoadedModule &operator[](uptr i) const { + CHECK_LT(i, modules_.size()); + return modules_[i]; + } + + private: + void clear() { + for (auto &module : modules_) module.clear(); + modules_.clear(); + } + void clearOrInit() { + initialized ? clear() : modules_.Initialize(kInitialCapacity); + initialized = true; + } + + InternalMmapVectorNoCtor<LoadedModule> modules_; + // We rarely have more than 16K loaded modules. + static const uptr kInitialCapacity = 1 << 14; + bool initialized; +}; + +// Callback type for iterating over a set of memory ranges. +typedef void (*RangeIteratorCallback)(uptr begin, uptr end, void *arg); + +enum AndroidApiLevel { + ANDROID_NOT_ANDROID = 0, + ANDROID_KITKAT = 19, + ANDROID_LOLLIPOP_MR1 = 22, + ANDROID_POST_LOLLIPOP = 23 +}; + +void WriteToSyslog(const char *buffer); + +#if defined(SANITIZER_WINDOWS) && defined(_MSC_VER) && !defined(__clang__) +#define SANITIZER_WIN_TRACE 1 +#else +#define SANITIZER_WIN_TRACE 0 +#endif + +#if SANITIZER_MAC || SANITIZER_WIN_TRACE +void LogFullErrorReport(const char *buffer); +#else +inline void LogFullErrorReport(const char *buffer) {} +#endif + +#if SANITIZER_LINUX || SANITIZER_MAC +void WriteOneLineToSyslog(const char *s); +void LogMessageOnPrintf(const char *str); +#else +inline void WriteOneLineToSyslog(const char *s) {} +inline void LogMessageOnPrintf(const char *str) {} +#endif + +#if SANITIZER_LINUX || SANITIZER_WIN_TRACE +// Initialize Android logging. Any writes before this are silently lost. +void AndroidLogInit(); +void SetAbortMessage(const char *); +#else +inline void AndroidLogInit() {} +// FIXME: MacOS implementation could use CRSetCrashLogMessage. +inline void SetAbortMessage(const char *) {} +#endif + +#if SANITIZER_ANDROID +void SanitizerInitializeUnwinder(); +AndroidApiLevel AndroidGetApiLevel(); +#else +inline void AndroidLogWrite(const char *buffer_unused) {} +inline void SanitizerInitializeUnwinder() {} +inline AndroidApiLevel AndroidGetApiLevel() { return ANDROID_NOT_ANDROID; } +#endif + +inline uptr GetPthreadDestructorIterations() { +#if SANITIZER_ANDROID + return (AndroidGetApiLevel() == ANDROID_LOLLIPOP_MR1) ? 8 : 4; +#elif SANITIZER_POSIX + return 4; +#else +// Unused on Windows. + return 0; +#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 defined(_MSC_VER) && !defined(__clang__) + _ReadWriteBarrier(); +#else + __asm__ __volatile__("" : : "r" (arg) : "memory"); +#endif +} + +struct SignalContext { + void *siginfo; + void *context; + uptr addr; + uptr pc; + uptr sp; + uptr bp; + bool is_memory_access; + enum WriteFlag { Unknown, Read, Write } write_flag; + + // In some cases the kernel cannot provide the true faulting address; `addr` + // will be zero then. This field allows to distinguish between these cases + // and dereferences of null. + bool is_true_faulting_addr; + + // VS2013 doesn't implement unrestricted unions, so we need a trivial default + // constructor + SignalContext() = default; + + // Creates signal context in a platform-specific manner. + // SignalContext is going to keep pointers to siginfo and context without + // owning them. + SignalContext(void *siginfo, void *context) + : siginfo(siginfo), + context(context), + addr(GetAddress()), + is_memory_access(IsMemoryAccess()), + write_flag(GetWriteFlag()), + is_true_faulting_addr(IsTrueFaultingAddress()) { + InitPcSpBp(); + } + + static void DumpAllRegisters(void *context); + + // Type of signal e.g. SIGSEGV or EXCEPTION_ACCESS_VIOLATION. + int GetType() const; + + // String description of the signal. + const char *Describe() const; + + // Returns true if signal is stack overflow. + bool IsStackOverflow() const; + + private: + // Platform specific initialization. + void InitPcSpBp(); + uptr GetAddress() const; + WriteFlag GetWriteFlag() const; + bool IsMemoryAccess() const; + bool IsTrueFaultingAddress() const; +}; + +void InitializePlatformEarly(); +void MaybeReexec(); + +template <typename Fn> +class RunOnDestruction { + public: + explicit RunOnDestruction(Fn fn) : fn_(fn) {} + ~RunOnDestruction() { fn_(); } + + private: + Fn fn_; +}; + +// A simple scope guard. Usage: +// auto cleanup = at_scope_exit([]{ do_cleanup; }); +template <typename Fn> +RunOnDestruction<Fn> at_scope_exit(Fn fn) { + return RunOnDestruction<Fn>(fn); +} + +// Linux on 64-bit s390 had a nasty bug that crashes the whole machine +// if a process uses virtual memory over 4TB (as many sanitizers like +// to do). This function will abort the process if running on a kernel +// that looks vulnerable. +#if SANITIZER_LINUX && SANITIZER_S390_64 +void AvoidCVE_2016_2143(); +#else +inline void AvoidCVE_2016_2143() {} +#endif + +struct StackDepotStats { + uptr n_uniq_ids; + uptr allocated; +}; + +// The default value for allocator_release_to_os_interval_ms common flag to +// indicate that sanitizer allocator should not attempt to release memory to OS. +const s32 kReleaseToOSIntervalNever = -1; + +void CheckNoDeepBind(const char *filename, int flag); + +// Returns the requested amount of random data (up to 256 bytes) that can then +// be used to seed a PRNG. Defaults to blocking like the underlying syscall. +bool GetRandom(void *buffer, uptr length, bool blocking = true); + +// Returns the number of logical processors on the system. +u32 GetNumberOfCPUs(); +extern u32 NumberOfCPUsCached; +inline u32 GetNumberOfCPUsCached() { + if (!NumberOfCPUsCached) + NumberOfCPUsCached = GetNumberOfCPUs(); + return NumberOfCPUsCached; +} + +template <typename T> +class ArrayRef { + public: + ArrayRef() {} + ArrayRef(T *begin, T *end) : begin_(begin), end_(end) {} + + T *begin() { return begin_; } + T *end() { return end_; } + + private: + T *begin_ = nullptr; + T *end_ = nullptr; +}; + +} // namespace __sanitizer + +inline void *operator new(__sanitizer::operator_new_size_type size, + __sanitizer::LowLevelAllocator &alloc) { + return alloc.Allocate(size); +} + +#endif // SANITIZER_COMMON_H diff --git a/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_common_interceptors.inc b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_common_interceptors.inc new file mode 100644 index 0000000000..b0ab08dff1 --- /dev/null +++ b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_common_interceptors.inc @@ -0,0 +1,10534 @@ +//===-- sanitizer_common_interceptors.inc -----------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// Common function interceptors for tools like AddressSanitizer, +// ThreadSanitizer, MemorySanitizer, etc. +// +// This file should be included into the tool's interceptor file, +// which has to define its own macros: +// COMMON_INTERCEPTOR_ENTER +// COMMON_INTERCEPTOR_ENTER_NOIGNORE +// COMMON_INTERCEPTOR_READ_RANGE +// COMMON_INTERCEPTOR_WRITE_RANGE +// COMMON_INTERCEPTOR_INITIALIZE_RANGE +// COMMON_INTERCEPTOR_DIR_ACQUIRE +// COMMON_INTERCEPTOR_FD_ACQUIRE +// COMMON_INTERCEPTOR_FD_RELEASE +// COMMON_INTERCEPTOR_FD_ACCESS +// COMMON_INTERCEPTOR_SET_THREAD_NAME +// COMMON_INTERCEPTOR_DLOPEN +// COMMON_INTERCEPTOR_ON_EXIT +// COMMON_INTERCEPTOR_MUTEX_PRE_LOCK +// COMMON_INTERCEPTOR_MUTEX_POST_LOCK +// COMMON_INTERCEPTOR_MUTEX_UNLOCK +// COMMON_INTERCEPTOR_MUTEX_REPAIR +// COMMON_INTERCEPTOR_SET_PTHREAD_NAME +// COMMON_INTERCEPTOR_HANDLE_RECVMSG +// COMMON_INTERCEPTOR_NOTHING_IS_INITIALIZED +// COMMON_INTERCEPTOR_MEMSET_IMPL +// COMMON_INTERCEPTOR_MEMMOVE_IMPL +// COMMON_INTERCEPTOR_MEMCPY_IMPL +// COMMON_INTERCEPTOR_MMAP_IMPL +// COMMON_INTERCEPTOR_COPY_STRING +// COMMON_INTERCEPTOR_STRNDUP_IMPL +// COMMON_INTERCEPTOR_STRERROR +//===----------------------------------------------------------------------===// + +#include "interception/interception.h" +#include "sanitizer_addrhashmap.h" +#include "sanitizer_errno.h" +#include "sanitizer_placement_new.h" +#include "sanitizer_platform_interceptors.h" +#include "sanitizer_symbolizer.h" +#include "sanitizer_tls_get_addr.h" + +#include <stdarg.h> + +#if SANITIZER_INTERCEPTOR_HOOKS +#define CALL_WEAK_INTERCEPTOR_HOOK(f, ...) f(__VA_ARGS__); +#define DECLARE_WEAK_INTERCEPTOR_HOOK(f, ...) \ + SANITIZER_INTERFACE_WEAK_DEF(void, f, __VA_ARGS__) {} +#else +#define DECLARE_WEAK_INTERCEPTOR_HOOK(f, ...) +#define CALL_WEAK_INTERCEPTOR_HOOK(f, ...) + +#endif // SANITIZER_INTERCEPTOR_HOOKS + +#if SANITIZER_WINDOWS && !defined(va_copy) +#define va_copy(dst, src) ((dst) = (src)) +#endif // _WIN32 + +#if SANITIZER_FREEBSD +#define pthread_setname_np pthread_set_name_np +#define inet_aton __inet_aton +#define inet_pton __inet_pton +#define iconv __bsd_iconv +#endif + +#if SANITIZER_NETBSD +#define clock_getres __clock_getres50 +#define clock_gettime __clock_gettime50 +#define clock_settime __clock_settime50 +#define ctime __ctime50 +#define ctime_r __ctime_r50 +#define devname __devname50 +#define fgetpos __fgetpos50 +#define fsetpos __fsetpos50 +#define fstatvfs __fstatvfs90 +#define fstatvfs1 __fstatvfs190 +#define fts_children __fts_children60 +#define fts_close __fts_close60 +#define fts_open __fts_open60 +#define fts_read __fts_read60 +#define fts_set __fts_set60 +#define getitimer __getitimer50 +#define getmntinfo __getmntinfo90 +#define getpwent __getpwent50 +#define getpwnam __getpwnam50 +#define getpwnam_r __getpwnam_r50 +#define getpwuid __getpwuid50 +#define getpwuid_r __getpwuid_r50 +#define getutent __getutent50 +#define getutxent __getutxent50 +#define getutxid __getutxid50 +#define getutxline __getutxline50 +#define getvfsstat __getvfsstat90 +#define pututxline __pututxline50 +#define glob __glob30 +#define gmtime __gmtime50 +#define gmtime_r __gmtime_r50 +#define localtime __locatime50 +#define localtime_r __localtime_r50 +#define mktime __mktime50 +#define lstat __lstat50 +#define opendir __opendir30 +#define readdir __readdir30 +#define readdir_r __readdir_r30 +#define scandir __scandir30 +#define setitimer __setitimer50 +#define setlocale __setlocale50 +#define shmctl __shmctl50 +#define sigaltstack __sigaltstack14 +#define sigemptyset __sigemptyset14 +#define sigfillset __sigfillset14 +#define sigpending __sigpending14 +#define sigprocmask __sigprocmask14 +#define sigtimedwait __sigtimedwait50 +#define stat __stat50 +#define statvfs __statvfs90 +#define statvfs1 __statvfs190 +#define time __time50 +#define times __times13 +#define unvis __unvis50 +#define wait3 __wait350 +#define wait4 __wait450 +extern const unsigned short *_ctype_tab_; +extern const short *_toupper_tab_; +extern const short *_tolower_tab_; +#endif + +// Platform-specific options. +#if SANITIZER_MAC +#define PLATFORM_HAS_DIFFERENT_MEMCPY_AND_MEMMOVE 0 +#elif SANITIZER_WINDOWS64 +#define PLATFORM_HAS_DIFFERENT_MEMCPY_AND_MEMMOVE 0 +#else +#define PLATFORM_HAS_DIFFERENT_MEMCPY_AND_MEMMOVE 1 +#endif // SANITIZER_MAC + +#ifndef COMMON_INTERCEPTOR_INITIALIZE_RANGE +#define COMMON_INTERCEPTOR_INITIALIZE_RANGE(p, size) {} +#endif + +#ifndef COMMON_INTERCEPTOR_UNPOISON_PARAM +#define COMMON_INTERCEPTOR_UNPOISON_PARAM(count) {} +#endif + +#ifndef COMMON_INTERCEPTOR_FD_ACCESS +#define COMMON_INTERCEPTOR_FD_ACCESS(ctx, fd) {} +#endif + +#ifndef COMMON_INTERCEPTOR_MUTEX_PRE_LOCK +#define COMMON_INTERCEPTOR_MUTEX_PRE_LOCK(ctx, m) {} +#endif + +#ifndef COMMON_INTERCEPTOR_MUTEX_POST_LOCK +#define COMMON_INTERCEPTOR_MUTEX_POST_LOCK(ctx, m) {} +#endif + +#ifndef COMMON_INTERCEPTOR_MUTEX_UNLOCK +#define COMMON_INTERCEPTOR_MUTEX_UNLOCK(ctx, m) {} +#endif + +#ifndef COMMON_INTERCEPTOR_MUTEX_REPAIR +#define COMMON_INTERCEPTOR_MUTEX_REPAIR(ctx, m) {} +#endif + +#ifndef COMMON_INTERCEPTOR_MUTEX_INVALID +#define COMMON_INTERCEPTOR_MUTEX_INVALID(ctx, m) {} +#endif + +#ifndef COMMON_INTERCEPTOR_HANDLE_RECVMSG +#define COMMON_INTERCEPTOR_HANDLE_RECVMSG(ctx, msg) ((void)(msg)) +#endif + +#ifndef COMMON_INTERCEPTOR_FILE_OPEN +#define COMMON_INTERCEPTOR_FILE_OPEN(ctx, file, path) {} +#endif + +#ifndef COMMON_INTERCEPTOR_FILE_CLOSE +#define COMMON_INTERCEPTOR_FILE_CLOSE(ctx, file) {} +#endif + +#ifndef COMMON_INTERCEPTOR_LIBRARY_LOADED +#define COMMON_INTERCEPTOR_LIBRARY_LOADED(filename, handle) {} +#endif + +#ifndef COMMON_INTERCEPTOR_LIBRARY_UNLOADED +#define COMMON_INTERCEPTOR_LIBRARY_UNLOADED() {} +#endif + +#ifndef COMMON_INTERCEPTOR_ENTER_NOIGNORE +#define COMMON_INTERCEPTOR_ENTER_NOIGNORE(ctx, ...) \ + COMMON_INTERCEPTOR_ENTER(ctx, __VA_ARGS__) +#endif + +#ifndef COMMON_INTERCEPTOR_NOTHING_IS_INITIALIZED +#define COMMON_INTERCEPTOR_NOTHING_IS_INITIALIZED (0) +#endif + +#define COMMON_INTERCEPTOR_READ_STRING(ctx, s, n) \ + COMMON_INTERCEPTOR_READ_RANGE((ctx), (s), \ + common_flags()->strict_string_checks ? (internal_strlen(s)) + 1 : (n) ) + +#ifndef COMMON_INTERCEPTOR_DLOPEN +#define COMMON_INTERCEPTOR_DLOPEN(filename, flag) \ + ({ CheckNoDeepBind(filename, flag); REAL(dlopen)(filename, flag); }) +#endif + +#ifndef COMMON_INTERCEPTOR_GET_TLS_RANGE +#define COMMON_INTERCEPTOR_GET_TLS_RANGE(begin, end) *begin = *end = 0; +#endif + +#ifndef COMMON_INTERCEPTOR_ACQUIRE +#define COMMON_INTERCEPTOR_ACQUIRE(ctx, u) {} +#endif + +#ifndef COMMON_INTERCEPTOR_RELEASE +#define COMMON_INTERCEPTOR_RELEASE(ctx, u) {} +#endif + +#ifndef COMMON_INTERCEPTOR_USER_CALLBACK_START +#define COMMON_INTERCEPTOR_USER_CALLBACK_START() {} +#endif + +#ifndef COMMON_INTERCEPTOR_USER_CALLBACK_END +#define COMMON_INTERCEPTOR_USER_CALLBACK_END() {} +#endif + +#ifdef SANITIZER_NLDBL_VERSION +#define COMMON_INTERCEPT_FUNCTION_LDBL(fn) \ + COMMON_INTERCEPT_FUNCTION_VER(fn, SANITIZER_NLDBL_VERSION) +#else +#define COMMON_INTERCEPT_FUNCTION_LDBL(fn) \ + COMMON_INTERCEPT_FUNCTION(fn) +#endif + +#if SANITIZER_GLIBC +// If we could not find the versioned symbol, fall back to an unversioned +// lookup. This is needed to work around a GLibc bug that causes dlsym +// with RTLD_NEXT to return the oldest versioned symbol. +// See https://sourceware.org/bugzilla/show_bug.cgi?id=14932. +// For certain symbols (e.g. regexec) we have to perform a versioned lookup, +// but that versioned symbol will only exist for architectures where the +// oldest Glibc version pre-dates support for that architecture. +// For example, regexec@GLIBC_2.3.4 exists on x86_64, but not RISC-V. +// See also https://gcc.gnu.org/bugzilla/show_bug.cgi?id=98920. +#define COMMON_INTERCEPT_FUNCTION_GLIBC_VER_MIN(fn, ver) \ + COMMON_INTERCEPT_FUNCTION_VER_UNVERSIONED_FALLBACK(fn, ver) +#else +#define COMMON_INTERCEPT_FUNCTION_GLIBC_VER_MIN(fn, ver) \ + COMMON_INTERCEPT_FUNCTION(fn) +#endif + +#ifndef COMMON_INTERCEPTOR_MEMSET_IMPL +#define COMMON_INTERCEPTOR_MEMSET_IMPL(ctx, dst, v, size) \ + { \ + if (COMMON_INTERCEPTOR_NOTHING_IS_INITIALIZED) \ + return internal_memset(dst, v, size); \ + COMMON_INTERCEPTOR_ENTER(ctx, memset, dst, v, size); \ + if (common_flags()->intercept_intrin) \ + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, dst, size); \ + return REAL(memset)(dst, v, size); \ + } +#endif + +#ifndef COMMON_INTERCEPTOR_MEMMOVE_IMPL +#define COMMON_INTERCEPTOR_MEMMOVE_IMPL(ctx, dst, src, size) \ + { \ + if (COMMON_INTERCEPTOR_NOTHING_IS_INITIALIZED) \ + return internal_memmove(dst, src, size); \ + COMMON_INTERCEPTOR_ENTER(ctx, memmove, dst, src, size); \ + if (common_flags()->intercept_intrin) { \ + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, dst, size); \ + COMMON_INTERCEPTOR_READ_RANGE(ctx, src, size); \ + } \ + return REAL(memmove)(dst, src, size); \ + } +#endif + +#ifndef COMMON_INTERCEPTOR_MEMCPY_IMPL +#define COMMON_INTERCEPTOR_MEMCPY_IMPL(ctx, dst, src, size) \ + { \ + if (COMMON_INTERCEPTOR_NOTHING_IS_INITIALIZED) { \ + return internal_memmove(dst, src, size); \ + } \ + COMMON_INTERCEPTOR_ENTER(ctx, memcpy, dst, src, size); \ + if (common_flags()->intercept_intrin) { \ + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, dst, size); \ + COMMON_INTERCEPTOR_READ_RANGE(ctx, src, size); \ + } \ + return REAL(memcpy)(dst, src, size); \ + } +#endif + +#ifndef COMMON_INTERCEPTOR_MMAP_IMPL +#define COMMON_INTERCEPTOR_MMAP_IMPL(ctx, mmap, addr, sz, prot, flags, fd, \ + off) \ + { return REAL(mmap)(addr, sz, prot, flags, fd, off); } +#endif + +#ifndef COMMON_INTERCEPTOR_COPY_STRING +#define COMMON_INTERCEPTOR_COPY_STRING(ctx, to, from, size) {} +#endif + +#ifndef COMMON_INTERCEPTOR_STRNDUP_IMPL +#define COMMON_INTERCEPTOR_STRNDUP_IMPL(ctx, s, size) \ + COMMON_INTERCEPTOR_ENTER(ctx, strndup, s, size); \ + uptr copy_length = internal_strnlen(s, size); \ + char *new_mem = (char *)WRAP(malloc)(copy_length + 1); \ + if (common_flags()->intercept_strndup) { \ + COMMON_INTERCEPTOR_READ_STRING(ctx, s, Min(size, copy_length + 1)); \ + } \ + COMMON_INTERCEPTOR_COPY_STRING(ctx, new_mem, s, copy_length); \ + internal_memcpy(new_mem, s, copy_length); \ + new_mem[copy_length] = '\0'; \ + return new_mem; +#endif + +#ifndef COMMON_INTERCEPTOR_STRERROR +#define COMMON_INTERCEPTOR_STRERROR() {} +#endif + +struct FileMetadata { + // For open_memstream(). + char **addr; + SIZE_T *size; +}; + +struct CommonInterceptorMetadata { + enum { + CIMT_INVALID = 0, + CIMT_FILE + } type; + union { + FileMetadata file; + }; +}; + +#if SI_POSIX +typedef AddrHashMap<CommonInterceptorMetadata, 31051> MetadataHashMap; + +static MetadataHashMap *interceptor_metadata_map; + +UNUSED static void SetInterceptorMetadata(__sanitizer_FILE *addr, + const FileMetadata &file) { + MetadataHashMap::Handle h(interceptor_metadata_map, (uptr)addr); + CHECK(h.created()); + h->type = CommonInterceptorMetadata::CIMT_FILE; + h->file = file; +} + +UNUSED static const FileMetadata *GetInterceptorMetadata( + __sanitizer_FILE *addr) { + MetadataHashMap::Handle h(interceptor_metadata_map, (uptr)addr, + /* remove */ false, + /* create */ false); + if (addr && h.exists()) { + CHECK(!h.created()); + CHECK(h->type == CommonInterceptorMetadata::CIMT_FILE); + return &h->file; + } else { + return 0; + } +} + +UNUSED static void DeleteInterceptorMetadata(void *addr) { + MetadataHashMap::Handle h(interceptor_metadata_map, (uptr)addr, true); + CHECK(h.exists()); +} +#endif // SI_POSIX + +#if SANITIZER_INTERCEPT_STRLEN +INTERCEPTOR(SIZE_T, strlen, const char *s) { + // Sometimes strlen is called prior to InitializeCommonInterceptors, + // in which case the REAL(strlen) typically used in + // COMMON_INTERCEPTOR_ENTER will fail. We use internal_strlen here + // to handle that. + if (COMMON_INTERCEPTOR_NOTHING_IS_INITIALIZED) + return internal_strlen(s); + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, strlen, s); + SIZE_T result = REAL(strlen)(s); + if (common_flags()->intercept_strlen) + COMMON_INTERCEPTOR_READ_RANGE(ctx, s, result + 1); + return result; +} +#define INIT_STRLEN COMMON_INTERCEPT_FUNCTION(strlen) +#else +#define INIT_STRLEN +#endif + +#if SANITIZER_INTERCEPT_STRNLEN +INTERCEPTOR(SIZE_T, strnlen, const char *s, SIZE_T maxlen) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, strnlen, s, maxlen); + SIZE_T length = REAL(strnlen)(s, maxlen); + if (common_flags()->intercept_strlen) + COMMON_INTERCEPTOR_READ_RANGE(ctx, s, Min(length + 1, maxlen)); + return length; +} +#define INIT_STRNLEN COMMON_INTERCEPT_FUNCTION(strnlen) +#else +#define INIT_STRNLEN +#endif + +#if SANITIZER_INTERCEPT_STRNDUP +INTERCEPTOR(char*, strndup, const char *s, uptr size) { + void *ctx; + COMMON_INTERCEPTOR_STRNDUP_IMPL(ctx, s, size); +} +#define INIT_STRNDUP COMMON_INTERCEPT_FUNCTION(strndup) +#else +#define INIT_STRNDUP +#endif // SANITIZER_INTERCEPT_STRNDUP + +#if SANITIZER_INTERCEPT___STRNDUP +INTERCEPTOR(char*, __strndup, const char *s, uptr size) { + void *ctx; + COMMON_INTERCEPTOR_STRNDUP_IMPL(ctx, s, size); +} +#define INIT___STRNDUP COMMON_INTERCEPT_FUNCTION(__strndup) +#else +#define INIT___STRNDUP +#endif // SANITIZER_INTERCEPT___STRNDUP + +#if SANITIZER_INTERCEPT_TEXTDOMAIN +INTERCEPTOR(char*, textdomain, const char *domainname) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, textdomain, domainname); + if (domainname) COMMON_INTERCEPTOR_READ_STRING(ctx, domainname, 0); + char *domain = REAL(textdomain)(domainname); + if (domain) { + COMMON_INTERCEPTOR_INITIALIZE_RANGE(domain, internal_strlen(domain) + 1); + } + return domain; +} +#define INIT_TEXTDOMAIN COMMON_INTERCEPT_FUNCTION(textdomain) +#else +#define INIT_TEXTDOMAIN +#endif + +#if SANITIZER_INTERCEPT_STRCMP +static inline int CharCmpX(unsigned char c1, unsigned char c2) { + return (c1 == c2) ? 0 : (c1 < c2) ? -1 : 1; +} + +DECLARE_WEAK_INTERCEPTOR_HOOK(__sanitizer_weak_hook_strcmp, uptr called_pc, + const char *s1, const char *s2, int result) + +INTERCEPTOR(int, strcmp, const char *s1, const char *s2) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, strcmp, s1, s2); + unsigned char c1, c2; + uptr i; + for (i = 0;; i++) { + c1 = (unsigned char)s1[i]; + c2 = (unsigned char)s2[i]; + if (c1 != c2 || c1 == '\0') break; + } + if (common_flags()->intercept_strcmp) { + COMMON_INTERCEPTOR_READ_STRING(ctx, s1, i + 1); + COMMON_INTERCEPTOR_READ_STRING(ctx, s2, i + 1); + } + int result = CharCmpX(c1, c2); + CALL_WEAK_INTERCEPTOR_HOOK(__sanitizer_weak_hook_strcmp, GET_CALLER_PC(), s1, + s2, result); + return result; +} + +DECLARE_WEAK_INTERCEPTOR_HOOK(__sanitizer_weak_hook_strncmp, uptr called_pc, + const char *s1, const char *s2, uptr n, + int result) + +INTERCEPTOR(int, strncmp, const char *s1, const char *s2, uptr size) { + if (COMMON_INTERCEPTOR_NOTHING_IS_INITIALIZED) + return internal_strncmp(s1, s2, size); + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, strncmp, s1, s2, size); + unsigned char c1 = 0, c2 = 0; + uptr i; + for (i = 0; i < size; i++) { + c1 = (unsigned char)s1[i]; + c2 = (unsigned char)s2[i]; + if (c1 != c2 || c1 == '\0') break; + } + uptr i1 = i; + uptr i2 = i; + if (common_flags()->strict_string_checks) { + for (; i1 < size && s1[i1]; i1++) {} + for (; i2 < size && s2[i2]; i2++) {} + } + COMMON_INTERCEPTOR_READ_RANGE((ctx), (s1), Min(i1 + 1, size)); + COMMON_INTERCEPTOR_READ_RANGE((ctx), (s2), Min(i2 + 1, size)); + int result = CharCmpX(c1, c2); + CALL_WEAK_INTERCEPTOR_HOOK(__sanitizer_weak_hook_strncmp, GET_CALLER_PC(), s1, + s2, size, result); + return result; +} + +#define INIT_STRCMP COMMON_INTERCEPT_FUNCTION(strcmp) +#define INIT_STRNCMP COMMON_INTERCEPT_FUNCTION(strncmp) +#else +#define INIT_STRCMP +#define INIT_STRNCMP +#endif + +#if SANITIZER_INTERCEPT_STRCASECMP +static inline int CharCaseCmp(unsigned char c1, unsigned char c2) { + int c1_low = ToLower(c1); + int c2_low = ToLower(c2); + return c1_low - c2_low; +} + +DECLARE_WEAK_INTERCEPTOR_HOOK(__sanitizer_weak_hook_strcasecmp, uptr called_pc, + const char *s1, const char *s2, int result) + +INTERCEPTOR(int, strcasecmp, const char *s1, const char *s2) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, strcasecmp, s1, s2); + unsigned char c1 = 0, c2 = 0; + uptr i; + for (i = 0;; i++) { + c1 = (unsigned char)s1[i]; + c2 = (unsigned char)s2[i]; + if (CharCaseCmp(c1, c2) != 0 || c1 == '\0') break; + } + COMMON_INTERCEPTOR_READ_STRING(ctx, s1, i + 1); + COMMON_INTERCEPTOR_READ_STRING(ctx, s2, i + 1); + int result = CharCaseCmp(c1, c2); + CALL_WEAK_INTERCEPTOR_HOOK(__sanitizer_weak_hook_strcasecmp, GET_CALLER_PC(), + s1, s2, result); + return result; +} + +DECLARE_WEAK_INTERCEPTOR_HOOK(__sanitizer_weak_hook_strncasecmp, uptr called_pc, + const char *s1, const char *s2, uptr size, + int result) + +INTERCEPTOR(int, strncasecmp, const char *s1, const char *s2, SIZE_T size) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, strncasecmp, s1, s2, size); + unsigned char c1 = 0, c2 = 0; + uptr i; + for (i = 0; i < size; i++) { + c1 = (unsigned char)s1[i]; + c2 = (unsigned char)s2[i]; + if (CharCaseCmp(c1, c2) != 0 || c1 == '\0') break; + } + uptr i1 = i; + uptr i2 = i; + if (common_flags()->strict_string_checks) { + for (; i1 < size && s1[i1]; i1++) {} + for (; i2 < size && s2[i2]; i2++) {} + } + COMMON_INTERCEPTOR_READ_RANGE((ctx), (s1), Min(i1 + 1, size)); + COMMON_INTERCEPTOR_READ_RANGE((ctx), (s2), Min(i2 + 1, size)); + int result = CharCaseCmp(c1, c2); + CALL_WEAK_INTERCEPTOR_HOOK(__sanitizer_weak_hook_strncasecmp, GET_CALLER_PC(), + s1, s2, size, result); + return result; +} + +#define INIT_STRCASECMP COMMON_INTERCEPT_FUNCTION(strcasecmp) +#define INIT_STRNCASECMP COMMON_INTERCEPT_FUNCTION(strncasecmp) +#else +#define INIT_STRCASECMP +#define INIT_STRNCASECMP +#endif + +#if SANITIZER_INTERCEPT_STRSTR || SANITIZER_INTERCEPT_STRCASESTR +static inline void StrstrCheck(void *ctx, char *r, const char *s1, + const char *s2) { + uptr len1 = internal_strlen(s1); + uptr len2 = internal_strlen(s2); + COMMON_INTERCEPTOR_READ_STRING(ctx, s1, r ? r - s1 + len2 : len1 + 1); + COMMON_INTERCEPTOR_READ_RANGE(ctx, s2, len2 + 1); +} +#endif + +#if SANITIZER_INTERCEPT_STRSTR + +DECLARE_WEAK_INTERCEPTOR_HOOK(__sanitizer_weak_hook_strstr, uptr called_pc, + const char *s1, const char *s2, char *result) + +INTERCEPTOR(char*, strstr, const char *s1, const char *s2) { + if (COMMON_INTERCEPTOR_NOTHING_IS_INITIALIZED) + return internal_strstr(s1, s2); + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, strstr, s1, s2); + char *r = REAL(strstr)(s1, s2); + if (common_flags()->intercept_strstr) + StrstrCheck(ctx, r, s1, s2); + CALL_WEAK_INTERCEPTOR_HOOK(__sanitizer_weak_hook_strstr, GET_CALLER_PC(), s1, + s2, r); + return r; +} + +#define INIT_STRSTR COMMON_INTERCEPT_FUNCTION(strstr); +#else +#define INIT_STRSTR +#endif + +#if SANITIZER_INTERCEPT_STRCASESTR + +DECLARE_WEAK_INTERCEPTOR_HOOK(__sanitizer_weak_hook_strcasestr, uptr called_pc, + const char *s1, const char *s2, char *result) + +INTERCEPTOR(char*, strcasestr, const char *s1, const char *s2) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, strcasestr, s1, s2); + char *r = REAL(strcasestr)(s1, s2); + if (common_flags()->intercept_strstr) + StrstrCheck(ctx, r, s1, s2); + CALL_WEAK_INTERCEPTOR_HOOK(__sanitizer_weak_hook_strcasestr, GET_CALLER_PC(), + s1, s2, r); + return r; +} + +#define INIT_STRCASESTR COMMON_INTERCEPT_FUNCTION(strcasestr); +#else +#define INIT_STRCASESTR +#endif + +#if SANITIZER_INTERCEPT_STRTOK + +INTERCEPTOR(char*, strtok, char *str, const char *delimiters) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, strtok, str, delimiters); + if (!common_flags()->intercept_strtok) { + return REAL(strtok)(str, delimiters); + } + if (common_flags()->strict_string_checks) { + // If strict_string_checks is enabled, we check the whole first argument + // string on the first call (strtok saves this string in a static buffer + // for subsequent calls). We do not need to check strtok's result. + // As the delimiters can change, we check them every call. + if (str != nullptr) { + COMMON_INTERCEPTOR_READ_RANGE(ctx, str, internal_strlen(str) + 1); + } + COMMON_INTERCEPTOR_READ_RANGE(ctx, delimiters, + internal_strlen(delimiters) + 1); + return REAL(strtok)(str, delimiters); + } else { + // However, when strict_string_checks is disabled we cannot check the + // whole string on the first call. Instead, we check the result string + // which is guaranteed to be a NULL-terminated substring of the first + // argument. We also conservatively check one character of str and the + // delimiters. + if (str != nullptr) { + COMMON_INTERCEPTOR_READ_STRING(ctx, str, 1); + } + COMMON_INTERCEPTOR_READ_RANGE(ctx, delimiters, 1); + char *result = REAL(strtok)(str, delimiters); + if (result != nullptr) { + COMMON_INTERCEPTOR_READ_RANGE(ctx, result, internal_strlen(result) + 1); + } else if (str != nullptr) { + // No delimiter were found, it's safe to assume that the entire str was + // scanned. + COMMON_INTERCEPTOR_READ_RANGE(ctx, str, internal_strlen(str) + 1); + } + return result; + } +} + +#define INIT_STRTOK COMMON_INTERCEPT_FUNCTION(strtok) +#else +#define INIT_STRTOK +#endif + +#if SANITIZER_INTERCEPT_MEMMEM +DECLARE_WEAK_INTERCEPTOR_HOOK(__sanitizer_weak_hook_memmem, uptr called_pc, + const void *s1, SIZE_T len1, const void *s2, + SIZE_T len2, void *result) + +INTERCEPTOR(void*, memmem, const void *s1, SIZE_T len1, const void *s2, + SIZE_T len2) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, memmem, s1, len1, s2, len2); + void *r = REAL(memmem)(s1, len1, s2, len2); + if (common_flags()->intercept_memmem) { + COMMON_INTERCEPTOR_READ_RANGE(ctx, s1, len1); + COMMON_INTERCEPTOR_READ_RANGE(ctx, s2, len2); + } + CALL_WEAK_INTERCEPTOR_HOOK(__sanitizer_weak_hook_memmem, GET_CALLER_PC(), + s1, len1, s2, len2, r); + return r; +} + +#define INIT_MEMMEM COMMON_INTERCEPT_FUNCTION(memmem); +#else +#define INIT_MEMMEM +#endif // SANITIZER_INTERCEPT_MEMMEM + +#if SANITIZER_INTERCEPT_STRCHR +INTERCEPTOR(char*, strchr, const char *s, int c) { + void *ctx; + if (COMMON_INTERCEPTOR_NOTHING_IS_INITIALIZED) + return internal_strchr(s, c); + COMMON_INTERCEPTOR_ENTER(ctx, strchr, s, c); + char *result = REAL(strchr)(s, c); + if (common_flags()->intercept_strchr) { + // Keep strlen as macro argument, as macro may ignore it. + COMMON_INTERCEPTOR_READ_STRING(ctx, s, + (result ? result - s : internal_strlen(s)) + 1); + } + return result; +} +#define INIT_STRCHR COMMON_INTERCEPT_FUNCTION(strchr) +#else +#define INIT_STRCHR +#endif + +#if SANITIZER_INTERCEPT_STRCHRNUL +INTERCEPTOR(char*, strchrnul, const char *s, int c) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, strchrnul, s, c); + char *result = REAL(strchrnul)(s, c); + uptr len = result - s + 1; + if (common_flags()->intercept_strchr) + COMMON_INTERCEPTOR_READ_STRING(ctx, s, len); + return result; +} +#define INIT_STRCHRNUL COMMON_INTERCEPT_FUNCTION(strchrnul) +#else +#define INIT_STRCHRNUL +#endif + +#if SANITIZER_INTERCEPT_STRRCHR +INTERCEPTOR(char*, strrchr, const char *s, int c) { + void *ctx; + if (COMMON_INTERCEPTOR_NOTHING_IS_INITIALIZED) + return internal_strrchr(s, c); + COMMON_INTERCEPTOR_ENTER(ctx, strrchr, s, c); + if (common_flags()->intercept_strchr) + COMMON_INTERCEPTOR_READ_RANGE(ctx, s, internal_strlen(s) + 1); + return REAL(strrchr)(s, c); +} +#define INIT_STRRCHR COMMON_INTERCEPT_FUNCTION(strrchr) +#else +#define INIT_STRRCHR +#endif + +#if SANITIZER_INTERCEPT_STRSPN +INTERCEPTOR(SIZE_T, strspn, const char *s1, const char *s2) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, strspn, s1, s2); + SIZE_T r = REAL(strspn)(s1, s2); + if (common_flags()->intercept_strspn) { + COMMON_INTERCEPTOR_READ_RANGE(ctx, s2, internal_strlen(s2) + 1); + COMMON_INTERCEPTOR_READ_STRING(ctx, s1, r + 1); + } + return r; +} + +INTERCEPTOR(SIZE_T, strcspn, const char *s1, const char *s2) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, strcspn, s1, s2); + SIZE_T r = REAL(strcspn)(s1, s2); + if (common_flags()->intercept_strspn) { + COMMON_INTERCEPTOR_READ_RANGE(ctx, s2, internal_strlen(s2) + 1); + COMMON_INTERCEPTOR_READ_STRING(ctx, s1, r + 1); + } + return r; +} + +#define INIT_STRSPN \ + COMMON_INTERCEPT_FUNCTION(strspn); \ + COMMON_INTERCEPT_FUNCTION(strcspn); +#else +#define INIT_STRSPN +#endif + +#if SANITIZER_INTERCEPT_STRPBRK +INTERCEPTOR(char *, strpbrk, const char *s1, const char *s2) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, strpbrk, s1, s2); + char *r = REAL(strpbrk)(s1, s2); + if (common_flags()->intercept_strpbrk) { + COMMON_INTERCEPTOR_READ_RANGE(ctx, s2, internal_strlen(s2) + 1); + COMMON_INTERCEPTOR_READ_STRING(ctx, s1, + r ? r - s1 + 1 : internal_strlen(s1) + 1); + } + return r; +} + +#define INIT_STRPBRK COMMON_INTERCEPT_FUNCTION(strpbrk); +#else +#define INIT_STRPBRK +#endif + +#if SANITIZER_INTERCEPT_MEMSET +INTERCEPTOR(void *, memset, void *dst, int v, uptr size) { + void *ctx; + COMMON_INTERCEPTOR_MEMSET_IMPL(ctx, dst, v, size); +} + +#define INIT_MEMSET COMMON_INTERCEPT_FUNCTION(memset) +#else +#define INIT_MEMSET +#endif + +#if SANITIZER_INTERCEPT_MEMMOVE +INTERCEPTOR(void *, memmove, void *dst, const void *src, uptr size) { + void *ctx; + COMMON_INTERCEPTOR_MEMMOVE_IMPL(ctx, dst, src, size); +} + +#define INIT_MEMMOVE COMMON_INTERCEPT_FUNCTION(memmove) +#else +#define INIT_MEMMOVE +#endif + +#if SANITIZER_INTERCEPT_MEMCPY +INTERCEPTOR(void *, memcpy, void *dst, const void *src, uptr size) { + // On OS X, calling internal_memcpy here will cause memory corruptions, + // because memcpy and memmove are actually aliases of the same + // implementation. We need to use internal_memmove here. + // N.B.: If we switch this to internal_ we'll have to use internal_memmove + // due to memcpy being an alias of memmove on OS X. + void *ctx; +#if PLATFORM_HAS_DIFFERENT_MEMCPY_AND_MEMMOVE + COMMON_INTERCEPTOR_MEMCPY_IMPL(ctx, dst, src, size); +#else + COMMON_INTERCEPTOR_MEMMOVE_IMPL(ctx, dst, src, size); +#endif +} + +#define INIT_MEMCPY \ + do { \ + if (PLATFORM_HAS_DIFFERENT_MEMCPY_AND_MEMMOVE) { \ + COMMON_INTERCEPT_FUNCTION(memcpy); \ + } else { \ + ASSIGN_REAL(memcpy, memmove); \ + } \ + CHECK(REAL(memcpy)); \ + } while (false) + +#else +#define INIT_MEMCPY +#endif + +#if SANITIZER_INTERCEPT_MEMCMP +DECLARE_WEAK_INTERCEPTOR_HOOK(__sanitizer_weak_hook_memcmp, uptr called_pc, + const void *s1, const void *s2, uptr n, + int result) + +// Common code for `memcmp` and `bcmp`. +int MemcmpInterceptorCommon(void *ctx, + int (*real_fn)(const void *, const void *, uptr), + const void *a1, const void *a2, uptr size) { + if (common_flags()->intercept_memcmp) { + if (common_flags()->strict_memcmp) { + // Check the entire regions even if the first bytes of the buffers are + // different. + COMMON_INTERCEPTOR_READ_RANGE(ctx, a1, size); + COMMON_INTERCEPTOR_READ_RANGE(ctx, a2, size); + // Fallthrough to REAL(memcmp) below. + } else { + unsigned char c1 = 0, c2 = 0; + const unsigned char *s1 = (const unsigned char*)a1; + const unsigned char *s2 = (const unsigned char*)a2; + uptr i; + for (i = 0; i < size; i++) { + c1 = s1[i]; + c2 = s2[i]; + if (c1 != c2) break; + } + COMMON_INTERCEPTOR_READ_RANGE(ctx, s1, Min(i + 1, size)); + COMMON_INTERCEPTOR_READ_RANGE(ctx, s2, Min(i + 1, size)); + int r = CharCmpX(c1, c2); + CALL_WEAK_INTERCEPTOR_HOOK(__sanitizer_weak_hook_memcmp, GET_CALLER_PC(), + a1, a2, size, r); + return r; + } + } + int result = real_fn(a1, a2, size); + CALL_WEAK_INTERCEPTOR_HOOK(__sanitizer_weak_hook_memcmp, GET_CALLER_PC(), a1, + a2, size, result); + return result; +} + +INTERCEPTOR(int, memcmp, const void *a1, const void *a2, uptr size) { + if (COMMON_INTERCEPTOR_NOTHING_IS_INITIALIZED) + return internal_memcmp(a1, a2, size); + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, memcmp, a1, a2, size); + return MemcmpInterceptorCommon(ctx, REAL(memcmp), a1, a2, size); +} + +#define INIT_MEMCMP COMMON_INTERCEPT_FUNCTION(memcmp) +#else +#define INIT_MEMCMP +#endif + +#if SANITIZER_INTERCEPT_BCMP +INTERCEPTOR(int, bcmp, const void *a1, const void *a2, uptr size) { + if (COMMON_INTERCEPTOR_NOTHING_IS_INITIALIZED) + return internal_memcmp(a1, a2, size); + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, bcmp, a1, a2, size); + return MemcmpInterceptorCommon(ctx, REAL(bcmp), a1, a2, size); +} + +#define INIT_BCMP COMMON_INTERCEPT_FUNCTION(bcmp) +#else +#define INIT_BCMP +#endif + +#if SANITIZER_INTERCEPT_MEMCHR +INTERCEPTOR(void*, memchr, const void *s, int c, SIZE_T n) { + if (COMMON_INTERCEPTOR_NOTHING_IS_INITIALIZED) + return internal_memchr(s, c, n); + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, memchr, s, c, n); +#if SANITIZER_WINDOWS + void *res; + if (REAL(memchr)) { + res = REAL(memchr)(s, c, n); + } else { + res = internal_memchr(s, c, n); + } +#else + void *res = REAL(memchr)(s, c, n); +#endif + uptr len = res ? (char *)res - (const char *)s + 1 : n; + COMMON_INTERCEPTOR_READ_RANGE(ctx, s, len); + return res; +} + +#define INIT_MEMCHR COMMON_INTERCEPT_FUNCTION(memchr) +#else +#define INIT_MEMCHR +#endif + +#if SANITIZER_INTERCEPT_MEMRCHR +INTERCEPTOR(void*, memrchr, const void *s, int c, SIZE_T n) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, memrchr, s, c, n); + COMMON_INTERCEPTOR_READ_RANGE(ctx, s, n); + return REAL(memrchr)(s, c, n); +} + +#define INIT_MEMRCHR COMMON_INTERCEPT_FUNCTION(memrchr) +#else +#define INIT_MEMRCHR +#endif + +#if SANITIZER_INTERCEPT_FREXP +INTERCEPTOR(double, frexp, double x, int *exp) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, frexp, x, exp); + // Assuming frexp() always writes to |exp|. + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, exp, sizeof(*exp)); + double res = REAL(frexp)(x, exp); + COMMON_INTERCEPTOR_INITIALIZE_RANGE(exp, sizeof(*exp)); + return res; +} + +#define INIT_FREXP COMMON_INTERCEPT_FUNCTION(frexp); +#else +#define INIT_FREXP +#endif // SANITIZER_INTERCEPT_FREXP + +#if SANITIZER_INTERCEPT_FREXPF_FREXPL +INTERCEPTOR(float, frexpf, float x, int *exp) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, frexpf, x, exp); + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, exp, sizeof(*exp)); + float res = REAL(frexpf)(x, exp); + COMMON_INTERCEPTOR_INITIALIZE_RANGE(exp, sizeof(*exp)); + return res; +} + +INTERCEPTOR(long double, frexpl, long double x, int *exp) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, frexpl, x, exp); + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, exp, sizeof(*exp)); + long double res = REAL(frexpl)(x, exp); + COMMON_INTERCEPTOR_INITIALIZE_RANGE(exp, sizeof(*exp)); + return res; +} + +#define INIT_FREXPF_FREXPL \ + COMMON_INTERCEPT_FUNCTION(frexpf); \ + COMMON_INTERCEPT_FUNCTION_LDBL(frexpl) +#else +#define INIT_FREXPF_FREXPL +#endif // SANITIZER_INTERCEPT_FREXPF_FREXPL + +#if SI_POSIX +static void write_iovec(void *ctx, struct __sanitizer_iovec *iovec, + SIZE_T iovlen, SIZE_T maxlen) { + for (SIZE_T i = 0; i < iovlen && maxlen; ++i) { + SSIZE_T sz = Min(iovec[i].iov_len, maxlen); + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, iovec[i].iov_base, sz); + maxlen -= sz; + } +} + +static void read_iovec(void *ctx, struct __sanitizer_iovec *iovec, + SIZE_T iovlen, SIZE_T maxlen) { + COMMON_INTERCEPTOR_READ_RANGE(ctx, iovec, sizeof(*iovec) * iovlen); + for (SIZE_T i = 0; i < iovlen && maxlen; ++i) { + SSIZE_T sz = Min(iovec[i].iov_len, maxlen); + COMMON_INTERCEPTOR_READ_RANGE(ctx, iovec[i].iov_base, sz); + maxlen -= sz; + } +} +#endif + +#if SANITIZER_INTERCEPT_READ +INTERCEPTOR(SSIZE_T, read, int fd, void *ptr, SIZE_T count) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, read, fd, ptr, count); + COMMON_INTERCEPTOR_FD_ACCESS(ctx, fd); + // FIXME: under ASan the call below may write to freed memory and corrupt + // its metadata. See + // https://github.com/google/sanitizers/issues/321. + SSIZE_T res = REAL(read)(fd, ptr, count); + if (res > 0) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ptr, res); + if (res >= 0 && fd >= 0) COMMON_INTERCEPTOR_FD_ACQUIRE(ctx, fd); + return res; +} +#define INIT_READ COMMON_INTERCEPT_FUNCTION(read) +#else +#define INIT_READ +#endif + +#if SANITIZER_INTERCEPT_FREAD +INTERCEPTOR(SIZE_T, fread, void *ptr, SIZE_T size, SIZE_T nmemb, void *file) { + // libc file streams can call user-supplied functions, see fopencookie. + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, fread, ptr, size, nmemb, file); + // FIXME: under ASan the call below may write to freed memory and corrupt + // its metadata. See + // https://github.com/google/sanitizers/issues/321. + SIZE_T res = REAL(fread)(ptr, size, nmemb, file); + if (res > 0) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ptr, res * size); + return res; +} +#define INIT_FREAD COMMON_INTERCEPT_FUNCTION(fread) +#else +#define INIT_FREAD +#endif + +#if SANITIZER_INTERCEPT_PREAD +INTERCEPTOR(SSIZE_T, pread, int fd, void *ptr, SIZE_T count, OFF_T offset) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, pread, fd, ptr, count, offset); + COMMON_INTERCEPTOR_FD_ACCESS(ctx, fd); + // FIXME: under ASan the call below may write to freed memory and corrupt + // its metadata. See + // https://github.com/google/sanitizers/issues/321. + SSIZE_T res = REAL(pread)(fd, ptr, count, offset); + if (res > 0) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ptr, res); + if (res >= 0 && fd >= 0) COMMON_INTERCEPTOR_FD_ACQUIRE(ctx, fd); + return res; +} +#define INIT_PREAD COMMON_INTERCEPT_FUNCTION(pread) +#else +#define INIT_PREAD +#endif + +#if SANITIZER_INTERCEPT_PREAD64 +INTERCEPTOR(SSIZE_T, pread64, int fd, void *ptr, SIZE_T count, OFF64_T offset) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, pread64, fd, ptr, count, offset); + COMMON_INTERCEPTOR_FD_ACCESS(ctx, fd); + // FIXME: under ASan the call below may write to freed memory and corrupt + // its metadata. See + // https://github.com/google/sanitizers/issues/321. + SSIZE_T res = REAL(pread64)(fd, ptr, count, offset); + if (res > 0) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ptr, res); + if (res >= 0 && fd >= 0) COMMON_INTERCEPTOR_FD_ACQUIRE(ctx, fd); + return res; +} +#define INIT_PREAD64 COMMON_INTERCEPT_FUNCTION(pread64) +#else +#define INIT_PREAD64 +#endif + +#if SANITIZER_INTERCEPT_READV +INTERCEPTOR_WITH_SUFFIX(SSIZE_T, readv, int fd, __sanitizer_iovec *iov, + int iovcnt) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, readv, fd, iov, iovcnt); + COMMON_INTERCEPTOR_FD_ACCESS(ctx, fd); + SSIZE_T res = REAL(readv)(fd, iov, iovcnt); + if (res > 0) write_iovec(ctx, iov, iovcnt, res); + if (res >= 0 && fd >= 0) COMMON_INTERCEPTOR_FD_ACQUIRE(ctx, fd); + return res; +} +#define INIT_READV COMMON_INTERCEPT_FUNCTION(readv) +#else +#define INIT_READV +#endif + +#if SANITIZER_INTERCEPT_PREADV +INTERCEPTOR(SSIZE_T, preadv, int fd, __sanitizer_iovec *iov, int iovcnt, + OFF_T offset) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, preadv, fd, iov, iovcnt, offset); + COMMON_INTERCEPTOR_FD_ACCESS(ctx, fd); + SSIZE_T res = REAL(preadv)(fd, iov, iovcnt, offset); + if (res > 0) write_iovec(ctx, iov, iovcnt, res); + if (res >= 0 && fd >= 0) COMMON_INTERCEPTOR_FD_ACQUIRE(ctx, fd); + return res; +} +#define INIT_PREADV COMMON_INTERCEPT_FUNCTION(preadv) +#else +#define INIT_PREADV +#endif + +#if SANITIZER_INTERCEPT_PREADV64 +INTERCEPTOR(SSIZE_T, preadv64, int fd, __sanitizer_iovec *iov, int iovcnt, + OFF64_T offset) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, preadv64, fd, iov, iovcnt, offset); + COMMON_INTERCEPTOR_FD_ACCESS(ctx, fd); + SSIZE_T res = REAL(preadv64)(fd, iov, iovcnt, offset); + if (res > 0) write_iovec(ctx, iov, iovcnt, res); + if (res >= 0 && fd >= 0) COMMON_INTERCEPTOR_FD_ACQUIRE(ctx, fd); + return res; +} +#define INIT_PREADV64 COMMON_INTERCEPT_FUNCTION(preadv64) +#else +#define INIT_PREADV64 +#endif + +#if SANITIZER_INTERCEPT_WRITE +INTERCEPTOR(SSIZE_T, write, int fd, void *ptr, SIZE_T count) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, write, fd, ptr, count); + COMMON_INTERCEPTOR_FD_ACCESS(ctx, fd); + if (fd >= 0) COMMON_INTERCEPTOR_FD_RELEASE(ctx, fd); + SSIZE_T res = REAL(write)(fd, ptr, count); + // FIXME: this check should be _before_ the call to REAL(write), not after + if (res > 0) COMMON_INTERCEPTOR_READ_RANGE(ctx, ptr, res); + return res; +} +#define INIT_WRITE COMMON_INTERCEPT_FUNCTION(write) +#else +#define INIT_WRITE +#endif + +#if SANITIZER_INTERCEPT_FWRITE +INTERCEPTOR(SIZE_T, fwrite, const void *p, uptr size, uptr nmemb, void *file) { + // libc file streams can call user-supplied functions, see fopencookie. + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, fwrite, p, size, nmemb, file); + SIZE_T res = REAL(fwrite)(p, size, nmemb, file); + if (res > 0) COMMON_INTERCEPTOR_READ_RANGE(ctx, p, res * size); + return res; +} +#define INIT_FWRITE COMMON_INTERCEPT_FUNCTION(fwrite) +#else +#define INIT_FWRITE +#endif + +#if SANITIZER_INTERCEPT_PWRITE +INTERCEPTOR(SSIZE_T, pwrite, int fd, void *ptr, SIZE_T count, OFF_T offset) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, pwrite, fd, ptr, count, offset); + COMMON_INTERCEPTOR_FD_ACCESS(ctx, fd); + if (fd >= 0) COMMON_INTERCEPTOR_FD_RELEASE(ctx, fd); + SSIZE_T res = REAL(pwrite)(fd, ptr, count, offset); + if (res > 0) COMMON_INTERCEPTOR_READ_RANGE(ctx, ptr, res); + return res; +} +#define INIT_PWRITE COMMON_INTERCEPT_FUNCTION(pwrite) +#else +#define INIT_PWRITE +#endif + +#if SANITIZER_INTERCEPT_PWRITE64 +INTERCEPTOR(SSIZE_T, pwrite64, int fd, void *ptr, OFF64_T count, + OFF64_T offset) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, pwrite64, fd, ptr, count, offset); + COMMON_INTERCEPTOR_FD_ACCESS(ctx, fd); + if (fd >= 0) COMMON_INTERCEPTOR_FD_RELEASE(ctx, fd); + SSIZE_T res = REAL(pwrite64)(fd, ptr, count, offset); + if (res > 0) COMMON_INTERCEPTOR_READ_RANGE(ctx, ptr, res); + return res; +} +#define INIT_PWRITE64 COMMON_INTERCEPT_FUNCTION(pwrite64) +#else +#define INIT_PWRITE64 +#endif + +#if SANITIZER_INTERCEPT_WRITEV +INTERCEPTOR_WITH_SUFFIX(SSIZE_T, writev, int fd, __sanitizer_iovec *iov, + int iovcnt) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, writev, fd, iov, iovcnt); + COMMON_INTERCEPTOR_FD_ACCESS(ctx, fd); + if (fd >= 0) COMMON_INTERCEPTOR_FD_RELEASE(ctx, fd); + SSIZE_T res = REAL(writev)(fd, iov, iovcnt); + if (res > 0) read_iovec(ctx, iov, iovcnt, res); + return res; +} +#define INIT_WRITEV COMMON_INTERCEPT_FUNCTION(writev) +#else +#define INIT_WRITEV +#endif + +#if SANITIZER_INTERCEPT_PWRITEV +INTERCEPTOR(SSIZE_T, pwritev, int fd, __sanitizer_iovec *iov, int iovcnt, + OFF_T offset) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, pwritev, fd, iov, iovcnt, offset); + COMMON_INTERCEPTOR_FD_ACCESS(ctx, fd); + if (fd >= 0) COMMON_INTERCEPTOR_FD_RELEASE(ctx, fd); + SSIZE_T res = REAL(pwritev)(fd, iov, iovcnt, offset); + if (res > 0) read_iovec(ctx, iov, iovcnt, res); + return res; +} +#define INIT_PWRITEV COMMON_INTERCEPT_FUNCTION(pwritev) +#else +#define INIT_PWRITEV +#endif + +#if SANITIZER_INTERCEPT_PWRITEV64 +INTERCEPTOR(SSIZE_T, pwritev64, int fd, __sanitizer_iovec *iov, int iovcnt, + OFF64_T offset) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, pwritev64, fd, iov, iovcnt, offset); + COMMON_INTERCEPTOR_FD_ACCESS(ctx, fd); + if (fd >= 0) COMMON_INTERCEPTOR_FD_RELEASE(ctx, fd); + SSIZE_T res = REAL(pwritev64)(fd, iov, iovcnt, offset); + if (res > 0) read_iovec(ctx, iov, iovcnt, res); + return res; +} +#define INIT_PWRITEV64 COMMON_INTERCEPT_FUNCTION(pwritev64) +#else +#define INIT_PWRITEV64 +#endif + +#if SANITIZER_INTERCEPT_FGETS +INTERCEPTOR(char *, fgets, char *s, SIZE_T size, void *file) { + // libc file streams can call user-supplied functions, see fopencookie. + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, fgets, s, size, file); + // FIXME: under ASan the call below may write to freed memory and corrupt + // its metadata. See + // https://github.com/google/sanitizers/issues/321. + char *res = REAL(fgets)(s, size, file); + if (res) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, s, internal_strlen(s) + 1); + return res; +} +#define INIT_FGETS COMMON_INTERCEPT_FUNCTION(fgets) +#else +#define INIT_FGETS +#endif + +#if SANITIZER_INTERCEPT_FPUTS +INTERCEPTOR_WITH_SUFFIX(int, fputs, char *s, void *file) { + // libc file streams can call user-supplied functions, see fopencookie. + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, fputs, s, file); + if (!SANITIZER_MAC || s) { // `fputs(NULL, file)` is supported on Darwin. + COMMON_INTERCEPTOR_READ_RANGE(ctx, s, internal_strlen(s) + 1); + } + return REAL(fputs)(s, file); +} +#define INIT_FPUTS COMMON_INTERCEPT_FUNCTION(fputs) +#else +#define INIT_FPUTS +#endif + +#if SANITIZER_INTERCEPT_PUTS +INTERCEPTOR(int, puts, char *s) { + // libc file streams can call user-supplied functions, see fopencookie. + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, puts, s); + if (!SANITIZER_MAC || s) { // `puts(NULL)` is supported on Darwin. + COMMON_INTERCEPTOR_READ_RANGE(ctx, s, internal_strlen(s) + 1); + } + return REAL(puts)(s); +} +#define INIT_PUTS COMMON_INTERCEPT_FUNCTION(puts) +#else +#define INIT_PUTS +#endif + +#if SANITIZER_INTERCEPT_PRCTL +INTERCEPTOR(int, prctl, int option, unsigned long arg2, unsigned long arg3, + unsigned long arg4, unsigned long arg5) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, prctl, option, arg2, arg3, arg4, arg5); + static const int PR_SET_NAME = 15; + int res = REAL(prctl(option, arg2, arg3, arg4, arg5)); + if (option == PR_SET_NAME) { + char buff[16]; + internal_strncpy(buff, (char *)arg2, 15); + buff[15] = 0; + COMMON_INTERCEPTOR_SET_THREAD_NAME(ctx, buff); + } + return res; +} +#define INIT_PRCTL COMMON_INTERCEPT_FUNCTION(prctl) +#else +#define INIT_PRCTL +#endif // SANITIZER_INTERCEPT_PRCTL + +#if SANITIZER_INTERCEPT_TIME +INTERCEPTOR(unsigned long, time, unsigned long *t) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, time, t); + unsigned long local_t; + unsigned long res = REAL(time)(&local_t); + if (t && res != (unsigned long)-1) { + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, t, sizeof(*t)); + *t = local_t; + } + return res; +} +#define INIT_TIME COMMON_INTERCEPT_FUNCTION(time); +#else +#define INIT_TIME +#endif // SANITIZER_INTERCEPT_TIME + +#if SANITIZER_INTERCEPT_LOCALTIME_AND_FRIENDS +static void unpoison_tm(void *ctx, __sanitizer_tm *tm) { + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, tm, sizeof(*tm)); +#if !SANITIZER_SOLARIS + if (tm->tm_zone) { + // Can not use COMMON_INTERCEPTOR_WRITE_RANGE here, because tm->tm_zone + // can point to shared memory and tsan would report a data race. + COMMON_INTERCEPTOR_INITIALIZE_RANGE(tm->tm_zone, + internal_strlen(tm->tm_zone) + 1); + } +#endif +} +INTERCEPTOR(__sanitizer_tm *, localtime, unsigned long *timep) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, localtime, timep); + __sanitizer_tm *res = REAL(localtime)(timep); + if (res) { + COMMON_INTERCEPTOR_READ_RANGE(ctx, timep, sizeof(*timep)); + unpoison_tm(ctx, res); + } + return res; +} +INTERCEPTOR(__sanitizer_tm *, localtime_r, unsigned long *timep, void *result) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, localtime_r, timep, result); + __sanitizer_tm *res = REAL(localtime_r)(timep, result); + if (res) { + COMMON_INTERCEPTOR_READ_RANGE(ctx, timep, sizeof(*timep)); + unpoison_tm(ctx, res); + } + return res; +} +INTERCEPTOR(__sanitizer_tm *, gmtime, unsigned long *timep) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, gmtime, timep); + __sanitizer_tm *res = REAL(gmtime)(timep); + if (res) { + COMMON_INTERCEPTOR_READ_RANGE(ctx, timep, sizeof(*timep)); + unpoison_tm(ctx, res); + } + return res; +} +INTERCEPTOR(__sanitizer_tm *, gmtime_r, unsigned long *timep, void *result) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, gmtime_r, timep, result); + __sanitizer_tm *res = REAL(gmtime_r)(timep, result); + if (res) { + COMMON_INTERCEPTOR_READ_RANGE(ctx, timep, sizeof(*timep)); + unpoison_tm(ctx, res); + } + return res; +} +INTERCEPTOR(char *, ctime, unsigned long *timep) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, ctime, timep); + // FIXME: under ASan the call below may write to freed memory and corrupt + // its metadata. See + // https://github.com/google/sanitizers/issues/321. + char *res = REAL(ctime)(timep); + if (res) { + COMMON_INTERCEPTOR_READ_RANGE(ctx, timep, sizeof(*timep)); + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, internal_strlen(res) + 1); + } + return res; +} +INTERCEPTOR(char *, ctime_r, unsigned long *timep, char *result) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, ctime_r, timep, result); + // FIXME: under ASan the call below may write to freed memory and corrupt + // its metadata. See + // https://github.com/google/sanitizers/issues/321. + char *res = REAL(ctime_r)(timep, result); + if (res) { + COMMON_INTERCEPTOR_READ_RANGE(ctx, timep, sizeof(*timep)); + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, internal_strlen(res) + 1); + } + return res; +} +INTERCEPTOR(char *, asctime, __sanitizer_tm *tm) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, asctime, tm); + // FIXME: under ASan the call below may write to freed memory and corrupt + // its metadata. See + // https://github.com/google/sanitizers/issues/321. + char *res = REAL(asctime)(tm); + if (res) { + COMMON_INTERCEPTOR_READ_RANGE(ctx, tm, sizeof(*tm)); + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, internal_strlen(res) + 1); + } + return res; +} +INTERCEPTOR(char *, asctime_r, __sanitizer_tm *tm, char *result) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, asctime_r, tm, result); + // FIXME: under ASan the call below may write to freed memory and corrupt + // its metadata. See + // https://github.com/google/sanitizers/issues/321. + char *res = REAL(asctime_r)(tm, result); + if (res) { + COMMON_INTERCEPTOR_READ_RANGE(ctx, tm, sizeof(*tm)); + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, internal_strlen(res) + 1); + } + return res; +} +INTERCEPTOR(long, mktime, __sanitizer_tm *tm) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, mktime, tm); + COMMON_INTERCEPTOR_READ_RANGE(ctx, &tm->tm_sec, sizeof(tm->tm_sec)); + COMMON_INTERCEPTOR_READ_RANGE(ctx, &tm->tm_min, sizeof(tm->tm_min)); + COMMON_INTERCEPTOR_READ_RANGE(ctx, &tm->tm_hour, sizeof(tm->tm_hour)); + COMMON_INTERCEPTOR_READ_RANGE(ctx, &tm->tm_mday, sizeof(tm->tm_mday)); + COMMON_INTERCEPTOR_READ_RANGE(ctx, &tm->tm_mon, sizeof(tm->tm_mon)); + COMMON_INTERCEPTOR_READ_RANGE(ctx, &tm->tm_year, sizeof(tm->tm_year)); + COMMON_INTERCEPTOR_READ_RANGE(ctx, &tm->tm_isdst, sizeof(tm->tm_isdst)); + long res = REAL(mktime)(tm); + if (res != -1) unpoison_tm(ctx, tm); + return res; +} +#define INIT_LOCALTIME_AND_FRIENDS \ + COMMON_INTERCEPT_FUNCTION(localtime); \ + COMMON_INTERCEPT_FUNCTION(localtime_r); \ + COMMON_INTERCEPT_FUNCTION(gmtime); \ + COMMON_INTERCEPT_FUNCTION(gmtime_r); \ + COMMON_INTERCEPT_FUNCTION(ctime); \ + COMMON_INTERCEPT_FUNCTION(ctime_r); \ + COMMON_INTERCEPT_FUNCTION(asctime); \ + COMMON_INTERCEPT_FUNCTION(asctime_r); \ + COMMON_INTERCEPT_FUNCTION(mktime); +#else +#define INIT_LOCALTIME_AND_FRIENDS +#endif // SANITIZER_INTERCEPT_LOCALTIME_AND_FRIENDS + +#if SANITIZER_INTERCEPT_STRPTIME +INTERCEPTOR(char *, strptime, char *s, char *format, __sanitizer_tm *tm) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, strptime, s, format, tm); + if (format) + COMMON_INTERCEPTOR_READ_RANGE(ctx, format, internal_strlen(format) + 1); + // FIXME: under ASan the call below may write to freed memory and corrupt + // its metadata. See + // https://github.com/google/sanitizers/issues/321. + char *res = REAL(strptime)(s, format, tm); + COMMON_INTERCEPTOR_READ_STRING(ctx, s, res ? res - s : 0); + if (res && tm) { + // Do not call unpoison_tm here, because strptime does not, in fact, + // initialize the entire struct tm. For example, tm_zone pointer is left + // uninitialized. + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, tm, sizeof(*tm)); + } + return res; +} +#define INIT_STRPTIME COMMON_INTERCEPT_FUNCTION(strptime); +#else +#define INIT_STRPTIME +#endif + +#if SANITIZER_INTERCEPT_SCANF || SANITIZER_INTERCEPT_PRINTF +#include "sanitizer_common_interceptors_format.inc" + +#define FORMAT_INTERCEPTOR_IMPL(name, vname, ...) \ + { \ + void *ctx; \ + va_list ap; \ + va_start(ap, format); \ + COMMON_INTERCEPTOR_ENTER(ctx, vname, __VA_ARGS__, ap); \ + int res = WRAP(vname)(__VA_ARGS__, ap); \ + va_end(ap); \ + return res; \ + } + +#endif + +#if SANITIZER_INTERCEPT_SCANF + +#define VSCANF_INTERCEPTOR_IMPL(vname, allowGnuMalloc, ...) \ + { \ + void *ctx; \ + COMMON_INTERCEPTOR_ENTER(ctx, vname, __VA_ARGS__); \ + va_list aq; \ + va_copy(aq, ap); \ + int res = REAL(vname)(__VA_ARGS__); \ + if (res > 0) \ + scanf_common(ctx, res, allowGnuMalloc, format, aq); \ + va_end(aq); \ + return res; \ + } + +INTERCEPTOR(int, vscanf, const char *format, va_list ap) +VSCANF_INTERCEPTOR_IMPL(vscanf, true, format, ap) + +INTERCEPTOR(int, vsscanf, const char *str, const char *format, va_list ap) +VSCANF_INTERCEPTOR_IMPL(vsscanf, true, str, format, ap) + +INTERCEPTOR(int, vfscanf, void *stream, const char *format, va_list ap) +VSCANF_INTERCEPTOR_IMPL(vfscanf, true, stream, format, ap) + +#if SANITIZER_INTERCEPT_ISOC99_SCANF +INTERCEPTOR(int, __isoc99_vscanf, const char *format, va_list ap) +VSCANF_INTERCEPTOR_IMPL(__isoc99_vscanf, false, format, ap) + +INTERCEPTOR(int, __isoc99_vsscanf, const char *str, const char *format, + va_list ap) +VSCANF_INTERCEPTOR_IMPL(__isoc99_vsscanf, false, str, format, ap) + +INTERCEPTOR(int, __isoc99_vfscanf, void *stream, const char *format, va_list ap) +VSCANF_INTERCEPTOR_IMPL(__isoc99_vfscanf, false, stream, format, ap) +#endif // SANITIZER_INTERCEPT_ISOC99_SCANF + +INTERCEPTOR(int, scanf, const char *format, ...) +FORMAT_INTERCEPTOR_IMPL(scanf, vscanf, format) + +INTERCEPTOR(int, fscanf, void *stream, const char *format, ...) +FORMAT_INTERCEPTOR_IMPL(fscanf, vfscanf, stream, format) + +INTERCEPTOR(int, sscanf, const char *str, const char *format, ...) +FORMAT_INTERCEPTOR_IMPL(sscanf, vsscanf, str, format) + +#if SANITIZER_INTERCEPT_ISOC99_SCANF +INTERCEPTOR(int, __isoc99_scanf, const char *format, ...) +FORMAT_INTERCEPTOR_IMPL(__isoc99_scanf, __isoc99_vscanf, format) + +INTERCEPTOR(int, __isoc99_fscanf, void *stream, const char *format, ...) +FORMAT_INTERCEPTOR_IMPL(__isoc99_fscanf, __isoc99_vfscanf, stream, format) + +INTERCEPTOR(int, __isoc99_sscanf, const char *str, const char *format, ...) +FORMAT_INTERCEPTOR_IMPL(__isoc99_sscanf, __isoc99_vsscanf, str, format) +#endif + +#endif + +#if SANITIZER_INTERCEPT_SCANF +#define INIT_SCANF \ + COMMON_INTERCEPT_FUNCTION_LDBL(scanf); \ + COMMON_INTERCEPT_FUNCTION_LDBL(sscanf); \ + COMMON_INTERCEPT_FUNCTION_LDBL(fscanf); \ + COMMON_INTERCEPT_FUNCTION_LDBL(vscanf); \ + COMMON_INTERCEPT_FUNCTION_LDBL(vsscanf); \ + COMMON_INTERCEPT_FUNCTION_LDBL(vfscanf); +#else +#define INIT_SCANF +#endif + +#if SANITIZER_INTERCEPT_ISOC99_SCANF +#define INIT_ISOC99_SCANF \ + COMMON_INTERCEPT_FUNCTION(__isoc99_scanf); \ + COMMON_INTERCEPT_FUNCTION(__isoc99_sscanf); \ + COMMON_INTERCEPT_FUNCTION(__isoc99_fscanf); \ + COMMON_INTERCEPT_FUNCTION(__isoc99_vscanf); \ + COMMON_INTERCEPT_FUNCTION(__isoc99_vsscanf); \ + COMMON_INTERCEPT_FUNCTION(__isoc99_vfscanf); +#else +#define INIT_ISOC99_SCANF +#endif + +#if SANITIZER_INTERCEPT_PRINTF + +#define VPRINTF_INTERCEPTOR_ENTER(vname, ...) \ + void *ctx; \ + COMMON_INTERCEPTOR_ENTER(ctx, vname, __VA_ARGS__); \ + va_list aq; \ + va_copy(aq, ap); + +#define VPRINTF_INTERCEPTOR_RETURN() \ + va_end(aq); + +#define VPRINTF_INTERCEPTOR_IMPL(vname, ...) \ + { \ + VPRINTF_INTERCEPTOR_ENTER(vname, __VA_ARGS__); \ + if (common_flags()->check_printf) \ + printf_common(ctx, format, aq); \ + int res = REAL(vname)(__VA_ARGS__); \ + VPRINTF_INTERCEPTOR_RETURN(); \ + return res; \ + } + +// FIXME: under ASan the REAL() call below may write to freed memory and +// corrupt its metadata. See +// https://github.com/google/sanitizers/issues/321. +#define VSPRINTF_INTERCEPTOR_IMPL(vname, str, ...) \ + { \ + VPRINTF_INTERCEPTOR_ENTER(vname, str, __VA_ARGS__) \ + if (common_flags()->check_printf) { \ + printf_common(ctx, format, aq); \ + } \ + int res = REAL(vname)(str, __VA_ARGS__); \ + if (res >= 0) { \ + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, str, res + 1); \ + } \ + VPRINTF_INTERCEPTOR_RETURN(); \ + return res; \ + } + +// FIXME: under ASan the REAL() call below may write to freed memory and +// corrupt its metadata. See +// https://github.com/google/sanitizers/issues/321. +#define VSNPRINTF_INTERCEPTOR_IMPL(vname, str, size, ...) \ + { \ + VPRINTF_INTERCEPTOR_ENTER(vname, str, size, __VA_ARGS__) \ + if (common_flags()->check_printf) { \ + printf_common(ctx, format, aq); \ + } \ + int res = REAL(vname)(str, size, __VA_ARGS__); \ + if (res >= 0) { \ + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, str, Min(size, (SIZE_T)(res + 1))); \ + } \ + VPRINTF_INTERCEPTOR_RETURN(); \ + return res; \ + } + +// FIXME: under ASan the REAL() call below may write to freed memory and +// corrupt its metadata. See +// https://github.com/google/sanitizers/issues/321. +#define VASPRINTF_INTERCEPTOR_IMPL(vname, strp, ...) \ + { \ + VPRINTF_INTERCEPTOR_ENTER(vname, strp, __VA_ARGS__) \ + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, strp, sizeof(char *)); \ + if (common_flags()->check_printf) { \ + printf_common(ctx, format, aq); \ + } \ + int res = REAL(vname)(strp, __VA_ARGS__); \ + if (res >= 0) { \ + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, *strp, res + 1); \ + } \ + VPRINTF_INTERCEPTOR_RETURN(); \ + return res; \ + } + +INTERCEPTOR(int, vprintf, const char *format, va_list ap) +VPRINTF_INTERCEPTOR_IMPL(vprintf, format, ap) + +INTERCEPTOR(int, vfprintf, __sanitizer_FILE *stream, const char *format, + va_list ap) +VPRINTF_INTERCEPTOR_IMPL(vfprintf, stream, format, ap) + +INTERCEPTOR(int, vsnprintf, char *str, SIZE_T size, const char *format, + va_list ap) +VSNPRINTF_INTERCEPTOR_IMPL(vsnprintf, str, size, format, ap) + +#if SANITIZER_INTERCEPT___PRINTF_CHK +INTERCEPTOR(int, __vsnprintf_chk, char *str, SIZE_T size, int flag, + SIZE_T size_to, const char *format, va_list ap) +VSNPRINTF_INTERCEPTOR_IMPL(vsnprintf, str, size, format, ap) +#endif + +#if SANITIZER_INTERCEPT_PRINTF_L +INTERCEPTOR(int, vsnprintf_l, char *str, SIZE_T size, void *loc, + const char *format, va_list ap) +VSNPRINTF_INTERCEPTOR_IMPL(vsnprintf_l, str, size, loc, format, ap) + +INTERCEPTOR(int, snprintf_l, char *str, SIZE_T size, void *loc, + const char *format, ...) +FORMAT_INTERCEPTOR_IMPL(snprintf_l, vsnprintf_l, str, size, loc, format) +#endif // SANITIZER_INTERCEPT_PRINTF_L + +INTERCEPTOR(int, vsprintf, char *str, const char *format, va_list ap) +VSPRINTF_INTERCEPTOR_IMPL(vsprintf, str, format, ap) + +#if SANITIZER_INTERCEPT___PRINTF_CHK +INTERCEPTOR(int, __vsprintf_chk, char *str, int flag, SIZE_T size_to, + const char *format, va_list ap) +VSPRINTF_INTERCEPTOR_IMPL(vsprintf, str, format, ap) +#endif + +INTERCEPTOR(int, vasprintf, char **strp, const char *format, va_list ap) +VASPRINTF_INTERCEPTOR_IMPL(vasprintf, strp, format, ap) + +#if SANITIZER_INTERCEPT_ISOC99_PRINTF +INTERCEPTOR(int, __isoc99_vprintf, const char *format, va_list ap) +VPRINTF_INTERCEPTOR_IMPL(__isoc99_vprintf, format, ap) + +INTERCEPTOR(int, __isoc99_vfprintf, __sanitizer_FILE *stream, + const char *format, va_list ap) +VPRINTF_INTERCEPTOR_IMPL(__isoc99_vfprintf, stream, format, ap) + +INTERCEPTOR(int, __isoc99_vsnprintf, char *str, SIZE_T size, const char *format, + va_list ap) +VSNPRINTF_INTERCEPTOR_IMPL(__isoc99_vsnprintf, str, size, format, ap) + +INTERCEPTOR(int, __isoc99_vsprintf, char *str, const char *format, + va_list ap) +VSPRINTF_INTERCEPTOR_IMPL(__isoc99_vsprintf, str, format, + ap) + +#endif // SANITIZER_INTERCEPT_ISOC99_PRINTF + +INTERCEPTOR(int, printf, const char *format, ...) +FORMAT_INTERCEPTOR_IMPL(printf, vprintf, format) + +INTERCEPTOR(int, fprintf, __sanitizer_FILE *stream, const char *format, ...) +FORMAT_INTERCEPTOR_IMPL(fprintf, vfprintf, stream, format) + +#if SANITIZER_INTERCEPT___PRINTF_CHK +INTERCEPTOR(int, __fprintf_chk, __sanitizer_FILE *stream, SIZE_T size, + const char *format, ...) +FORMAT_INTERCEPTOR_IMPL(__fprintf_chk, vfprintf, stream, format) +#endif + +INTERCEPTOR(int, sprintf, char *str, const char *format, ...) +FORMAT_INTERCEPTOR_IMPL(sprintf, vsprintf, str, format) + +#if SANITIZER_INTERCEPT___PRINTF_CHK +INTERCEPTOR(int, __sprintf_chk, char *str, int flag, SIZE_T size_to, + const char *format, ...) +FORMAT_INTERCEPTOR_IMPL(__sprintf_chk, vsprintf, str, format) +#endif + +INTERCEPTOR(int, snprintf, char *str, SIZE_T size, const char *format, ...) +FORMAT_INTERCEPTOR_IMPL(snprintf, vsnprintf, str, size, format) + +#if SANITIZER_INTERCEPT___PRINTF_CHK +INTERCEPTOR(int, __snprintf_chk, char *str, SIZE_T size, int flag, + SIZE_T size_to, const char *format, ...) +FORMAT_INTERCEPTOR_IMPL(__snprintf_chk, vsnprintf, str, size, format) +#endif + +INTERCEPTOR(int, asprintf, char **strp, const char *format, ...) +FORMAT_INTERCEPTOR_IMPL(asprintf, vasprintf, strp, format) + +#if SANITIZER_INTERCEPT_ISOC99_PRINTF +INTERCEPTOR(int, __isoc99_printf, const char *format, ...) +FORMAT_INTERCEPTOR_IMPL(__isoc99_printf, __isoc99_vprintf, format) + +INTERCEPTOR(int, __isoc99_fprintf, __sanitizer_FILE *stream, const char *format, + ...) +FORMAT_INTERCEPTOR_IMPL(__isoc99_fprintf, __isoc99_vfprintf, stream, format) + +INTERCEPTOR(int, __isoc99_sprintf, char *str, const char *format, ...) +FORMAT_INTERCEPTOR_IMPL(__isoc99_sprintf, __isoc99_vsprintf, str, format) + +INTERCEPTOR(int, __isoc99_snprintf, char *str, SIZE_T size, + const char *format, ...) +FORMAT_INTERCEPTOR_IMPL(__isoc99_snprintf, __isoc99_vsnprintf, str, size, + format) + +#endif // SANITIZER_INTERCEPT_ISOC99_PRINTF + +#endif // SANITIZER_INTERCEPT_PRINTF + +#if SANITIZER_INTERCEPT_PRINTF +#define INIT_PRINTF \ + COMMON_INTERCEPT_FUNCTION_LDBL(printf); \ + COMMON_INTERCEPT_FUNCTION_LDBL(sprintf); \ + COMMON_INTERCEPT_FUNCTION_LDBL(snprintf); \ + COMMON_INTERCEPT_FUNCTION_LDBL(asprintf); \ + COMMON_INTERCEPT_FUNCTION_LDBL(fprintf); \ + COMMON_INTERCEPT_FUNCTION_LDBL(vprintf); \ + COMMON_INTERCEPT_FUNCTION_LDBL(vsprintf); \ + COMMON_INTERCEPT_FUNCTION_LDBL(vsnprintf); \ + COMMON_INTERCEPT_FUNCTION_LDBL(vasprintf); \ + COMMON_INTERCEPT_FUNCTION_LDBL(vfprintf); +#else +#define INIT_PRINTF +#endif + +#if SANITIZER_INTERCEPT___PRINTF_CHK +#define INIT___PRINTF_CHK \ + COMMON_INTERCEPT_FUNCTION(__sprintf_chk); \ + COMMON_INTERCEPT_FUNCTION(__snprintf_chk); \ + COMMON_INTERCEPT_FUNCTION(__vsprintf_chk); \ + COMMON_INTERCEPT_FUNCTION(__vsnprintf_chk); \ + COMMON_INTERCEPT_FUNCTION(__fprintf_chk); +#else +#define INIT___PRINTF_CHK +#endif + +#if SANITIZER_INTERCEPT_PRINTF_L +#define INIT_PRINTF_L \ + COMMON_INTERCEPT_FUNCTION(snprintf_l); \ + COMMON_INTERCEPT_FUNCTION(vsnprintf_l); +#else +#define INIT_PRINTF_L +#endif + +#if SANITIZER_INTERCEPT_ISOC99_PRINTF +#define INIT_ISOC99_PRINTF \ + COMMON_INTERCEPT_FUNCTION(__isoc99_printf); \ + COMMON_INTERCEPT_FUNCTION(__isoc99_sprintf); \ + COMMON_INTERCEPT_FUNCTION(__isoc99_snprintf); \ + COMMON_INTERCEPT_FUNCTION(__isoc99_fprintf); \ + COMMON_INTERCEPT_FUNCTION(__isoc99_vprintf); \ + COMMON_INTERCEPT_FUNCTION(__isoc99_vsprintf); \ + COMMON_INTERCEPT_FUNCTION(__isoc99_vsnprintf); \ + COMMON_INTERCEPT_FUNCTION(__isoc99_vfprintf); +#else +#define INIT_ISOC99_PRINTF +#endif + +#if SANITIZER_INTERCEPT_IOCTL +#include "sanitizer_common_interceptors_ioctl.inc" +#include "sanitizer_interceptors_ioctl_netbsd.inc" +INTERCEPTOR(int, ioctl, int d, unsigned long request, ...) { + // We need a frame pointer, because we call into ioctl_common_[pre|post] which + // can trigger a report and we need to be able to unwind through this + // function. On Mac in debug mode we might not have a frame pointer, because + // ioctl_common_[pre|post] doesn't get inlined here. + ENABLE_FRAME_POINTER; + + void *ctx; + va_list ap; + va_start(ap, request); + void *arg = va_arg(ap, void *); + va_end(ap); + COMMON_INTERCEPTOR_ENTER(ctx, ioctl, d, request, arg); + + CHECK(ioctl_initialized); + + // Note: TSan does not use common flags, and they are zero-initialized. + // This effectively disables ioctl handling in TSan. + if (!common_flags()->handle_ioctl) return REAL(ioctl)(d, request, arg); + + // Although request is unsigned long, the rest of the interceptor uses it + // as just "unsigned" to save space, because we know that all values fit in + // "unsigned" - they are compile-time constants. + + const ioctl_desc *desc = ioctl_lookup(request); + ioctl_desc decoded_desc; + if (!desc) { + VPrintf(2, "Decoding unknown ioctl 0x%lx\n", request); + if (!ioctl_decode(request, &decoded_desc)) + Printf("WARNING: failed decoding unknown ioctl 0x%lx\n", request); + else + desc = &decoded_desc; + } + + if (desc) ioctl_common_pre(ctx, desc, d, request, arg); + int res = REAL(ioctl)(d, request, arg); + // FIXME: some ioctls have different return values for success and failure. + if (desc && res != -1) ioctl_common_post(ctx, desc, res, d, request, arg); + return res; +} +#define INIT_IOCTL \ + ioctl_init(); \ + COMMON_INTERCEPT_FUNCTION(ioctl); +#else +#define INIT_IOCTL +#endif + +#if SANITIZER_POSIX +UNUSED static void unpoison_passwd(void *ctx, __sanitizer_passwd *pwd) { + if (pwd) { + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, pwd, sizeof(*pwd)); + if (pwd->pw_name) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, pwd->pw_name, + internal_strlen(pwd->pw_name) + 1); + if (pwd->pw_passwd) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, pwd->pw_passwd, + internal_strlen(pwd->pw_passwd) + 1); +#if !SANITIZER_ANDROID + if (pwd->pw_gecos) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, pwd->pw_gecos, + internal_strlen(pwd->pw_gecos) + 1); +#endif +#if SANITIZER_MAC || SANITIZER_FREEBSD || SANITIZER_NETBSD + if (pwd->pw_class) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, pwd->pw_class, + internal_strlen(pwd->pw_class) + 1); +#endif + if (pwd->pw_dir) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, pwd->pw_dir, + internal_strlen(pwd->pw_dir) + 1); + if (pwd->pw_shell) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, pwd->pw_shell, + internal_strlen(pwd->pw_shell) + 1); + } +} + +UNUSED static void unpoison_group(void *ctx, __sanitizer_group *grp) { + if (grp) { + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, grp, sizeof(*grp)); + if (grp->gr_name) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, grp->gr_name, + internal_strlen(grp->gr_name) + 1); + if (grp->gr_passwd) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, grp->gr_passwd, + internal_strlen(grp->gr_passwd) + 1); + char **p = grp->gr_mem; + for (; *p; ++p) { + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, *p, internal_strlen(*p) + 1); + } + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, grp->gr_mem, + (p - grp->gr_mem + 1) * sizeof(*p)); + } +} +#endif // SANITIZER_POSIX + +#if SANITIZER_INTERCEPT_GETPWNAM_AND_FRIENDS +INTERCEPTOR(__sanitizer_passwd *, getpwnam, const char *name) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, getpwnam, name); + if (name) + COMMON_INTERCEPTOR_READ_RANGE(ctx, name, internal_strlen(name) + 1); + __sanitizer_passwd *res = REAL(getpwnam)(name); + unpoison_passwd(ctx, res); + return res; +} +INTERCEPTOR(__sanitizer_passwd *, getpwuid, u32 uid) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, getpwuid, uid); + __sanitizer_passwd *res = REAL(getpwuid)(uid); + unpoison_passwd(ctx, res); + return res; +} +INTERCEPTOR(__sanitizer_group *, getgrnam, const char *name) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, getgrnam, name); + COMMON_INTERCEPTOR_READ_RANGE(ctx, name, internal_strlen(name) + 1); + __sanitizer_group *res = REAL(getgrnam)(name); + unpoison_group(ctx, res); + return res; +} +INTERCEPTOR(__sanitizer_group *, getgrgid, u32 gid) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, getgrgid, gid); + __sanitizer_group *res = REAL(getgrgid)(gid); + unpoison_group(ctx, res); + return res; +} +#define INIT_GETPWNAM_AND_FRIENDS \ + COMMON_INTERCEPT_FUNCTION(getpwnam); \ + COMMON_INTERCEPT_FUNCTION(getpwuid); \ + COMMON_INTERCEPT_FUNCTION(getgrnam); \ + COMMON_INTERCEPT_FUNCTION(getgrgid); +#else +#define INIT_GETPWNAM_AND_FRIENDS +#endif + +#if SANITIZER_INTERCEPT_GETPWNAM_R_AND_FRIENDS +INTERCEPTOR(int, getpwnam_r, const char *name, __sanitizer_passwd *pwd, + char *buf, SIZE_T buflen, __sanitizer_passwd **result) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, getpwnam_r, name, pwd, buf, buflen, result); + COMMON_INTERCEPTOR_READ_RANGE(ctx, name, internal_strlen(name) + 1); + // FIXME: under ASan the call below may write to freed memory and corrupt + // its metadata. See + // https://github.com/google/sanitizers/issues/321. + int res = REAL(getpwnam_r)(name, pwd, buf, buflen, result); + if (!res && result) + unpoison_passwd(ctx, *result); + if (result) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, result, sizeof(*result)); + return res; +} +INTERCEPTOR(int, getpwuid_r, u32 uid, __sanitizer_passwd *pwd, char *buf, + SIZE_T buflen, __sanitizer_passwd **result) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, getpwuid_r, uid, pwd, buf, buflen, result); + // FIXME: under ASan the call below may write to freed memory and corrupt + // its metadata. See + // https://github.com/google/sanitizers/issues/321. + int res = REAL(getpwuid_r)(uid, pwd, buf, buflen, result); + if (!res && result) + unpoison_passwd(ctx, *result); + if (result) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, result, sizeof(*result)); + return res; +} +INTERCEPTOR(int, getgrnam_r, const char *name, __sanitizer_group *grp, + char *buf, SIZE_T buflen, __sanitizer_group **result) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, getgrnam_r, name, grp, buf, buflen, result); + COMMON_INTERCEPTOR_READ_RANGE(ctx, name, internal_strlen(name) + 1); + // FIXME: under ASan the call below may write to freed memory and corrupt + // its metadata. See + // https://github.com/google/sanitizers/issues/321. + int res = REAL(getgrnam_r)(name, grp, buf, buflen, result); + if (!res && result) + unpoison_group(ctx, *result); + if (result) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, result, sizeof(*result)); + return res; +} +INTERCEPTOR(int, getgrgid_r, u32 gid, __sanitizer_group *grp, char *buf, + SIZE_T buflen, __sanitizer_group **result) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, getgrgid_r, gid, grp, buf, buflen, result); + // FIXME: under ASan the call below may write to freed memory and corrupt + // its metadata. See + // https://github.com/google/sanitizers/issues/321. + int res = REAL(getgrgid_r)(gid, grp, buf, buflen, result); + if (!res && result) + unpoison_group(ctx, *result); + if (result) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, result, sizeof(*result)); + return res; +} +#define INIT_GETPWNAM_R_AND_FRIENDS \ + COMMON_INTERCEPT_FUNCTION(getpwnam_r); \ + COMMON_INTERCEPT_FUNCTION(getpwuid_r); \ + COMMON_INTERCEPT_FUNCTION(getgrnam_r); \ + COMMON_INTERCEPT_FUNCTION(getgrgid_r); +#else +#define INIT_GETPWNAM_R_AND_FRIENDS +#endif + +#if SANITIZER_INTERCEPT_GETPWENT +INTERCEPTOR(__sanitizer_passwd *, getpwent, int dummy) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, getpwent, dummy); + __sanitizer_passwd *res = REAL(getpwent)(dummy); + unpoison_passwd(ctx, res); + return res; +} +INTERCEPTOR(__sanitizer_group *, getgrent, int dummy) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, getgrent, dummy); + __sanitizer_group *res = REAL(getgrent)(dummy); + unpoison_group(ctx, res); + return res; +} +#define INIT_GETPWENT \ + COMMON_INTERCEPT_FUNCTION(getpwent); \ + COMMON_INTERCEPT_FUNCTION(getgrent); +#else +#define INIT_GETPWENT +#endif + +#if SANITIZER_INTERCEPT_FGETPWENT +INTERCEPTOR(__sanitizer_passwd *, fgetpwent, void *fp) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, fgetpwent, fp); + __sanitizer_passwd *res = REAL(fgetpwent)(fp); + unpoison_passwd(ctx, res); + return res; +} +INTERCEPTOR(__sanitizer_group *, fgetgrent, void *fp) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, fgetgrent, fp); + __sanitizer_group *res = REAL(fgetgrent)(fp); + unpoison_group(ctx, res); + return res; +} +#define INIT_FGETPWENT \ + COMMON_INTERCEPT_FUNCTION(fgetpwent); \ + COMMON_INTERCEPT_FUNCTION(fgetgrent); +#else +#define INIT_FGETPWENT +#endif + +#if SANITIZER_INTERCEPT_GETPWENT_R +INTERCEPTOR(int, getpwent_r, __sanitizer_passwd *pwbuf, char *buf, + SIZE_T buflen, __sanitizer_passwd **pwbufp) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, getpwent_r, pwbuf, buf, buflen, pwbufp); + // FIXME: under ASan the call below may write to freed memory and corrupt + // its metadata. See + // https://github.com/google/sanitizers/issues/321. + int res = REAL(getpwent_r)(pwbuf, buf, buflen, pwbufp); + if (!res && pwbufp) + unpoison_passwd(ctx, *pwbufp); + if (pwbufp) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, pwbufp, sizeof(*pwbufp)); + return res; +} +INTERCEPTOR(int, getgrent_r, __sanitizer_group *pwbuf, char *buf, SIZE_T buflen, + __sanitizer_group **pwbufp) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, getgrent_r, pwbuf, buf, buflen, pwbufp); + // FIXME: under ASan the call below may write to freed memory and corrupt + // its metadata. See + // https://github.com/google/sanitizers/issues/321. + int res = REAL(getgrent_r)(pwbuf, buf, buflen, pwbufp); + if (!res && pwbufp) + unpoison_group(ctx, *pwbufp); + if (pwbufp) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, pwbufp, sizeof(*pwbufp)); + return res; +} +#define INIT_GETPWENT_R \ + COMMON_INTERCEPT_FUNCTION(getpwent_r); \ + COMMON_INTERCEPT_FUNCTION(getgrent_r); +#else +#define INIT_GETPWENT_R +#endif + +#if SANITIZER_INTERCEPT_FGETPWENT_R +INTERCEPTOR(int, fgetpwent_r, void *fp, __sanitizer_passwd *pwbuf, char *buf, + SIZE_T buflen, __sanitizer_passwd **pwbufp) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, fgetpwent_r, fp, pwbuf, buf, buflen, pwbufp); + // FIXME: under ASan the call below may write to freed memory and corrupt + // its metadata. See + // https://github.com/google/sanitizers/issues/321. + int res = REAL(fgetpwent_r)(fp, pwbuf, buf, buflen, pwbufp); + if (!res && pwbufp) + unpoison_passwd(ctx, *pwbufp); + if (pwbufp) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, pwbufp, sizeof(*pwbufp)); + return res; +} +#define INIT_FGETPWENT_R \ + COMMON_INTERCEPT_FUNCTION(fgetpwent_r); +#else +#define INIT_FGETPWENT_R +#endif + +#if SANITIZER_INTERCEPT_FGETGRENT_R +INTERCEPTOR(int, fgetgrent_r, void *fp, __sanitizer_group *pwbuf, char *buf, + SIZE_T buflen, __sanitizer_group **pwbufp) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, fgetgrent_r, fp, pwbuf, buf, buflen, pwbufp); + // FIXME: under ASan the call below may write to freed memory and corrupt + // its metadata. See + // https://github.com/google/sanitizers/issues/321. + int res = REAL(fgetgrent_r)(fp, pwbuf, buf, buflen, pwbufp); + if (!res && pwbufp) + unpoison_group(ctx, *pwbufp); + if (pwbufp) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, pwbufp, sizeof(*pwbufp)); + return res; +} +#define INIT_FGETGRENT_R \ + COMMON_INTERCEPT_FUNCTION(fgetgrent_r); +#else +#define INIT_FGETGRENT_R +#endif + +#if SANITIZER_INTERCEPT_SETPWENT +// The only thing these interceptors do is disable any nested interceptors. +// These functions may open nss modules and call uninstrumented functions from +// them, and we don't want things like strlen() to trigger. +INTERCEPTOR(void, setpwent, int dummy) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, setpwent, dummy); + REAL(setpwent)(dummy); +} +INTERCEPTOR(void, endpwent, int dummy) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, endpwent, dummy); + REAL(endpwent)(dummy); +} +INTERCEPTOR(void, setgrent, int dummy) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, setgrent, dummy); + REAL(setgrent)(dummy); +} +INTERCEPTOR(void, endgrent, int dummy) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, endgrent, dummy); + REAL(endgrent)(dummy); +} +#define INIT_SETPWENT \ + COMMON_INTERCEPT_FUNCTION(setpwent); \ + COMMON_INTERCEPT_FUNCTION(endpwent); \ + COMMON_INTERCEPT_FUNCTION(setgrent); \ + COMMON_INTERCEPT_FUNCTION(endgrent); +#else +#define INIT_SETPWENT +#endif + +#if SANITIZER_INTERCEPT_CLOCK_GETTIME +INTERCEPTOR(int, clock_getres, u32 clk_id, void *tp) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, clock_getres, clk_id, tp); + // FIXME: under ASan the call below may write to freed memory and corrupt + // its metadata. See + // https://github.com/google/sanitizers/issues/321. + int res = REAL(clock_getres)(clk_id, tp); + if (!res && tp) { + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, tp, struct_timespec_sz); + } + return res; +} +INTERCEPTOR(int, clock_gettime, u32 clk_id, void *tp) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, clock_gettime, clk_id, tp); + // FIXME: under ASan the call below may write to freed memory and corrupt + // its metadata. See + // https://github.com/google/sanitizers/issues/321. + int res = REAL(clock_gettime)(clk_id, tp); + if (!res) { + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, tp, struct_timespec_sz); + } + return res; +} +#if SANITIZER_GLIBC +namespace __sanitizer { +extern "C" { +int real_clock_gettime(u32 clk_id, void *tp) { + if (COMMON_INTERCEPTOR_NOTHING_IS_INITIALIZED) + return internal_clock_gettime(clk_id, tp); + return REAL(clock_gettime)(clk_id, tp); +} +} // extern "C" +} // namespace __sanitizer +#endif +INTERCEPTOR(int, clock_settime, u32 clk_id, const void *tp) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, clock_settime, clk_id, tp); + COMMON_INTERCEPTOR_READ_RANGE(ctx, tp, struct_timespec_sz); + return REAL(clock_settime)(clk_id, tp); +} +#define INIT_CLOCK_GETTIME \ + COMMON_INTERCEPT_FUNCTION(clock_getres); \ + COMMON_INTERCEPT_FUNCTION(clock_gettime); \ + COMMON_INTERCEPT_FUNCTION(clock_settime); +#else +#define INIT_CLOCK_GETTIME +#endif + +#if SANITIZER_INTERCEPT_CLOCK_GETCPUCLOCKID +INTERCEPTOR(int, clock_getcpuclockid, pid_t pid, + __sanitizer_clockid_t *clockid) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, clock_getcpuclockid, pid, clockid); + int res = REAL(clock_getcpuclockid)(pid, clockid); + if (!res && clockid) { + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, clockid, sizeof *clockid); + } + return res; +} + +INTERCEPTOR(int, pthread_getcpuclockid, uptr thread, + __sanitizer_clockid_t *clockid) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, pthread_getcpuclockid, thread, clockid); + int res = REAL(pthread_getcpuclockid)(thread, clockid); + if (!res && clockid) { + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, clockid, sizeof *clockid); + } + return res; +} + +#define INIT_CLOCK_GETCPUCLOCKID \ + COMMON_INTERCEPT_FUNCTION(clock_getcpuclockid); \ + COMMON_INTERCEPT_FUNCTION(pthread_getcpuclockid); +#else +#define INIT_CLOCK_GETCPUCLOCKID +#endif + +#if SANITIZER_INTERCEPT_GETITIMER +INTERCEPTOR(int, getitimer, int which, void *curr_value) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, getitimer, which, curr_value); + // FIXME: under ASan the call below may write to freed memory and corrupt + // its metadata. See + // https://github.com/google/sanitizers/issues/321. + int res = REAL(getitimer)(which, curr_value); + if (!res && curr_value) { + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, curr_value, struct_itimerval_sz); + } + return res; +} +INTERCEPTOR(int, setitimer, int which, const void *new_value, void *old_value) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, setitimer, which, new_value, old_value); + if (new_value) { + // itimerval can contain padding that may be legitimately uninitialized + const struct __sanitizer_itimerval *nv = + (const struct __sanitizer_itimerval *)new_value; + COMMON_INTERCEPTOR_READ_RANGE(ctx, &nv->it_interval.tv_sec, + sizeof(__sanitizer_time_t)); + COMMON_INTERCEPTOR_READ_RANGE(ctx, &nv->it_interval.tv_usec, + sizeof(__sanitizer_suseconds_t)); + COMMON_INTERCEPTOR_READ_RANGE(ctx, &nv->it_value.tv_sec, + sizeof(__sanitizer_time_t)); + COMMON_INTERCEPTOR_READ_RANGE(ctx, &nv->it_value.tv_usec, + sizeof(__sanitizer_suseconds_t)); + } + // FIXME: under ASan the call below may write to freed memory and corrupt + // its metadata. See + // https://github.com/google/sanitizers/issues/321. + int res = REAL(setitimer)(which, new_value, old_value); + if (!res && old_value) { + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, old_value, struct_itimerval_sz); + } + return res; +} +#define INIT_GETITIMER \ + COMMON_INTERCEPT_FUNCTION(getitimer); \ + COMMON_INTERCEPT_FUNCTION(setitimer); +#else +#define INIT_GETITIMER +#endif + +#if SANITIZER_INTERCEPT_GLOB +static void unpoison_glob_t(void *ctx, __sanitizer_glob_t *pglob) { + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, pglob, sizeof(*pglob)); + // +1 for NULL pointer at the end. + if (pglob->gl_pathv) + COMMON_INTERCEPTOR_WRITE_RANGE( + ctx, pglob->gl_pathv, (pglob->gl_pathc + 1) * sizeof(*pglob->gl_pathv)); + for (SIZE_T i = 0; i < pglob->gl_pathc; ++i) { + char *p = pglob->gl_pathv[i]; + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, p, internal_strlen(p) + 1); + } +} + +#if SANITIZER_SOLARIS +INTERCEPTOR(int, glob, const char *pattern, int flags, + int (*errfunc)(const char *epath, int eerrno), + __sanitizer_glob_t *pglob) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, glob, pattern, flags, errfunc, pglob); + COMMON_INTERCEPTOR_READ_STRING(ctx, pattern, 0); + int res = REAL(glob)(pattern, flags, errfunc, pglob); + if ((!res || res == glob_nomatch) && pglob) unpoison_glob_t(ctx, pglob); + return res; +} +#else +static THREADLOCAL __sanitizer_glob_t *pglob_copy; + +static void wrapped_gl_closedir(void *dir) { + COMMON_INTERCEPTOR_UNPOISON_PARAM(1); + pglob_copy->gl_closedir(dir); +} + +static void *wrapped_gl_readdir(void *dir) { + COMMON_INTERCEPTOR_UNPOISON_PARAM(1); + return pglob_copy->gl_readdir(dir); +} + +static void *wrapped_gl_opendir(const char *s) { + COMMON_INTERCEPTOR_UNPOISON_PARAM(1); + COMMON_INTERCEPTOR_INITIALIZE_RANGE(s, internal_strlen(s) + 1); + return pglob_copy->gl_opendir(s); +} + +static int wrapped_gl_lstat(const char *s, void *st) { + COMMON_INTERCEPTOR_UNPOISON_PARAM(2); + COMMON_INTERCEPTOR_INITIALIZE_RANGE(s, internal_strlen(s) + 1); + return pglob_copy->gl_lstat(s, st); +} + +static int wrapped_gl_stat(const char *s, void *st) { + COMMON_INTERCEPTOR_UNPOISON_PARAM(2); + COMMON_INTERCEPTOR_INITIALIZE_RANGE(s, internal_strlen(s) + 1); + return pglob_copy->gl_stat(s, st); +} + +static const __sanitizer_glob_t kGlobCopy = { + 0, 0, 0, + 0, wrapped_gl_closedir, wrapped_gl_readdir, + wrapped_gl_opendir, wrapped_gl_lstat, wrapped_gl_stat}; + +INTERCEPTOR(int, glob, const char *pattern, int flags, + int (*errfunc)(const char *epath, int eerrno), + __sanitizer_glob_t *pglob) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, glob, pattern, flags, errfunc, pglob); + COMMON_INTERCEPTOR_READ_STRING(ctx, pattern, 0); + __sanitizer_glob_t glob_copy; + internal_memcpy(&glob_copy, &kGlobCopy, sizeof(glob_copy)); + if (flags & glob_altdirfunc) { + Swap(pglob->gl_closedir, glob_copy.gl_closedir); + Swap(pglob->gl_readdir, glob_copy.gl_readdir); + Swap(pglob->gl_opendir, glob_copy.gl_opendir); + Swap(pglob->gl_lstat, glob_copy.gl_lstat); + Swap(pglob->gl_stat, glob_copy.gl_stat); + pglob_copy = &glob_copy; + } + int res = REAL(glob)(pattern, flags, errfunc, pglob); + if (flags & glob_altdirfunc) { + Swap(pglob->gl_closedir, glob_copy.gl_closedir); + Swap(pglob->gl_readdir, glob_copy.gl_readdir); + Swap(pglob->gl_opendir, glob_copy.gl_opendir); + Swap(pglob->gl_lstat, glob_copy.gl_lstat); + Swap(pglob->gl_stat, glob_copy.gl_stat); + } + pglob_copy = 0; + if ((!res || res == glob_nomatch) && pglob) unpoison_glob_t(ctx, pglob); + return res; +} +#endif // SANITIZER_SOLARIS +#define INIT_GLOB \ + COMMON_INTERCEPT_FUNCTION(glob); +#else // SANITIZER_INTERCEPT_GLOB +#define INIT_GLOB +#endif // SANITIZER_INTERCEPT_GLOB + +#if SANITIZER_INTERCEPT_GLOB64 +INTERCEPTOR(int, glob64, const char *pattern, int flags, + int (*errfunc)(const char *epath, int eerrno), + __sanitizer_glob_t *pglob) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, glob64, pattern, flags, errfunc, pglob); + COMMON_INTERCEPTOR_READ_STRING(ctx, pattern, 0); + __sanitizer_glob_t glob_copy; + internal_memcpy(&glob_copy, &kGlobCopy, sizeof(glob_copy)); + if (flags & glob_altdirfunc) { + Swap(pglob->gl_closedir, glob_copy.gl_closedir); + Swap(pglob->gl_readdir, glob_copy.gl_readdir); + Swap(pglob->gl_opendir, glob_copy.gl_opendir); + Swap(pglob->gl_lstat, glob_copy.gl_lstat); + Swap(pglob->gl_stat, glob_copy.gl_stat); + pglob_copy = &glob_copy; + } + int res = REAL(glob64)(pattern, flags, errfunc, pglob); + if (flags & glob_altdirfunc) { + Swap(pglob->gl_closedir, glob_copy.gl_closedir); + Swap(pglob->gl_readdir, glob_copy.gl_readdir); + Swap(pglob->gl_opendir, glob_copy.gl_opendir); + Swap(pglob->gl_lstat, glob_copy.gl_lstat); + Swap(pglob->gl_stat, glob_copy.gl_stat); + } + pglob_copy = 0; + if ((!res || res == glob_nomatch) && pglob) unpoison_glob_t(ctx, pglob); + return res; +} +#define INIT_GLOB64 \ + COMMON_INTERCEPT_FUNCTION(glob64); +#else // SANITIZER_INTERCEPT_GLOB64 +#define INIT_GLOB64 +#endif // SANITIZER_INTERCEPT_GLOB64 + +#if SANITIZER_INTERCEPT_POSIX_SPAWN + +template <class RealSpawnPtr> +static int PosixSpawnImpl(void *ctx, RealSpawnPtr *real_posix_spawn, pid_t *pid, + const char *file_or_path, const void *file_actions, + const void *attrp, char *const argv[], + char *const envp[]) { + COMMON_INTERCEPTOR_READ_RANGE(ctx, file_or_path, + internal_strlen(file_or_path) + 1); + if (argv) { + for (char *const *s = argv; ; ++s) { + COMMON_INTERCEPTOR_READ_RANGE(ctx, s, sizeof(*s)); + if (!*s) break; + COMMON_INTERCEPTOR_READ_RANGE(ctx, *s, internal_strlen(*s) + 1); + } + } + if (envp) { + for (char *const *s = envp; ; ++s) { + COMMON_INTERCEPTOR_READ_RANGE(ctx, s, sizeof(*s)); + if (!*s) break; + COMMON_INTERCEPTOR_READ_RANGE(ctx, *s, internal_strlen(*s) + 1); + } + } + int res = + real_posix_spawn(pid, file_or_path, file_actions, attrp, argv, envp); + if (res == 0) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, pid, sizeof(*pid)); + return res; +} +INTERCEPTOR(int, posix_spawn, pid_t *pid, const char *path, + const void *file_actions, const void *attrp, char *const argv[], + char *const envp[]) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, posix_spawn, pid, path, file_actions, attrp, + argv, envp); + return PosixSpawnImpl(ctx, REAL(posix_spawn), pid, path, file_actions, attrp, + argv, envp); +} +INTERCEPTOR(int, posix_spawnp, pid_t *pid, const char *file, + const void *file_actions, const void *attrp, char *const argv[], + char *const envp[]) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, posix_spawnp, pid, file, file_actions, attrp, + argv, envp); + return PosixSpawnImpl(ctx, REAL(posix_spawnp), pid, file, file_actions, attrp, + argv, envp); +} +# define INIT_POSIX_SPAWN \ + COMMON_INTERCEPT_FUNCTION(posix_spawn); \ + COMMON_INTERCEPT_FUNCTION(posix_spawnp); +#else // SANITIZER_INTERCEPT_POSIX_SPAWN +# define INIT_POSIX_SPAWN +#endif // SANITIZER_INTERCEPT_POSIX_SPAWN + +#if SANITIZER_INTERCEPT_WAIT +// According to sys/wait.h, wait(), waitid(), waitpid() may have symbol version +// suffixes on Darwin. See the declaration of INTERCEPTOR_WITH_SUFFIX for +// details. +INTERCEPTOR_WITH_SUFFIX(int, wait, int *status) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, wait, status); + // FIXME: under ASan the call below may write to freed memory and corrupt + // its metadata. See + // https://github.com/google/sanitizers/issues/321. + int res = REAL(wait)(status); + if (res != -1 && status) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, status, sizeof(*status)); + return res; +} +// On FreeBSD id_t is always 64-bit wide. +#if SANITIZER_FREEBSD && (SANITIZER_WORDSIZE == 32) +INTERCEPTOR_WITH_SUFFIX(int, waitid, int idtype, long long id, void *infop, + int options) { +#else +INTERCEPTOR_WITH_SUFFIX(int, waitid, int idtype, int id, void *infop, + int options) { +#endif + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, waitid, idtype, id, infop, options); + // FIXME: under ASan the call below may write to freed memory and corrupt + // its metadata. See + // https://github.com/google/sanitizers/issues/321. + int res = REAL(waitid)(idtype, id, infop, options); + if (res != -1 && infop) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, infop, siginfo_t_sz); + return res; +} +INTERCEPTOR_WITH_SUFFIX(int, waitpid, int pid, int *status, int options) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, waitpid, pid, status, options); + // FIXME: under ASan the call below may write to freed memory and corrupt + // its metadata. See + // https://github.com/google/sanitizers/issues/321. + int res = REAL(waitpid)(pid, status, options); + if (res != -1 && status) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, status, sizeof(*status)); + return res; +} +INTERCEPTOR(int, wait3, int *status, int options, void *rusage) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, wait3, status, options, rusage); + // FIXME: under ASan the call below may write to freed memory and corrupt + // its metadata. See + // https://github.com/google/sanitizers/issues/321. + int res = REAL(wait3)(status, options, rusage); + if (res != -1) { + if (status) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, status, sizeof(*status)); + if (rusage) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, rusage, struct_rusage_sz); + } + return res; +} +#if SANITIZER_ANDROID +INTERCEPTOR(int, __wait4, int pid, int *status, int options, void *rusage) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, __wait4, pid, status, options, rusage); + // FIXME: under ASan the call below may write to freed memory and corrupt + // its metadata. See + // https://github.com/google/sanitizers/issues/321. + int res = REAL(__wait4)(pid, status, options, rusage); + if (res != -1) { + if (status) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, status, sizeof(*status)); + if (rusage) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, rusage, struct_rusage_sz); + } + return res; +} +#define INIT_WAIT4 COMMON_INTERCEPT_FUNCTION(__wait4); +#else +INTERCEPTOR(int, wait4, int pid, int *status, int options, void *rusage) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, wait4, pid, status, options, rusage); + // FIXME: under ASan the call below may write to freed memory and corrupt + // its metadata. See + // https://github.com/google/sanitizers/issues/321. + int res = REAL(wait4)(pid, status, options, rusage); + if (res != -1) { + if (status) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, status, sizeof(*status)); + if (rusage) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, rusage, struct_rusage_sz); + } + return res; +} +#define INIT_WAIT4 COMMON_INTERCEPT_FUNCTION(wait4); +#endif // SANITIZER_ANDROID +#define INIT_WAIT \ + COMMON_INTERCEPT_FUNCTION(wait); \ + COMMON_INTERCEPT_FUNCTION(waitid); \ + COMMON_INTERCEPT_FUNCTION(waitpid); \ + COMMON_INTERCEPT_FUNCTION(wait3); +#else +#define INIT_WAIT +#define INIT_WAIT4 +#endif + +#if SANITIZER_INTERCEPT_INET +INTERCEPTOR(char *, inet_ntop, int af, const void *src, char *dst, u32 size) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, inet_ntop, af, src, dst, size); + uptr sz = __sanitizer_in_addr_sz(af); + if (sz) COMMON_INTERCEPTOR_READ_RANGE(ctx, src, sz); + // FIXME: figure out read size based on the address family. + // FIXME: under ASan the call below may write to freed memory and corrupt + // its metadata. See + // https://github.com/google/sanitizers/issues/321. + char *res = REAL(inet_ntop)(af, src, dst, size); + if (res) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, internal_strlen(res) + 1); + return res; +} +INTERCEPTOR(int, inet_pton, int af, const char *src, void *dst) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, inet_pton, af, src, dst); + COMMON_INTERCEPTOR_READ_STRING(ctx, src, 0); + // FIXME: figure out read size based on the address family. + // FIXME: under ASan the call below may write to freed memory and corrupt + // its metadata. See + // https://github.com/google/sanitizers/issues/321. + int res = REAL(inet_pton)(af, src, dst); + if (res == 1) { + uptr sz = __sanitizer_in_addr_sz(af); + if (sz) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, dst, sz); + } + return res; +} +#define INIT_INET \ + COMMON_INTERCEPT_FUNCTION(inet_ntop); \ + COMMON_INTERCEPT_FUNCTION(inet_pton); +#else +#define INIT_INET +#endif + +#if SANITIZER_INTERCEPT_INET +INTERCEPTOR(int, inet_aton, const char *cp, void *dst) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, inet_aton, cp, dst); + if (cp) COMMON_INTERCEPTOR_READ_RANGE(ctx, cp, internal_strlen(cp) + 1); + // FIXME: under ASan the call below may write to freed memory and corrupt + // its metadata. See + // https://github.com/google/sanitizers/issues/321. + int res = REAL(inet_aton)(cp, dst); + if (res != 0) { + uptr sz = __sanitizer_in_addr_sz(af_inet); + if (sz) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, dst, sz); + } + return res; +} +#define INIT_INET_ATON COMMON_INTERCEPT_FUNCTION(inet_aton); +#else +#define INIT_INET_ATON +#endif + +#if SANITIZER_INTERCEPT_PTHREAD_GETSCHEDPARAM +INTERCEPTOR(int, pthread_getschedparam, uptr thread, int *policy, int *param) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, pthread_getschedparam, thread, policy, param); + // FIXME: under ASan the call below may write to freed memory and corrupt + // its metadata. See + // https://github.com/google/sanitizers/issues/321. + int res = REAL(pthread_getschedparam)(thread, policy, param); + if (res == 0) { + if (policy) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, policy, sizeof(*policy)); + if (param) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, param, sizeof(*param)); + } + return res; +} +#define INIT_PTHREAD_GETSCHEDPARAM \ + COMMON_INTERCEPT_FUNCTION(pthread_getschedparam); +#else +#define INIT_PTHREAD_GETSCHEDPARAM +#endif + +#if SANITIZER_INTERCEPT_GETADDRINFO +INTERCEPTOR(int, getaddrinfo, char *node, char *service, + struct __sanitizer_addrinfo *hints, + struct __sanitizer_addrinfo **out) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, getaddrinfo, node, service, hints, out); + if (node) COMMON_INTERCEPTOR_READ_RANGE(ctx, node, internal_strlen(node) + 1); + if (service) + COMMON_INTERCEPTOR_READ_RANGE(ctx, service, internal_strlen(service) + 1); + if (hints) + COMMON_INTERCEPTOR_READ_RANGE(ctx, hints, sizeof(__sanitizer_addrinfo)); + // FIXME: under ASan the call below may write to freed memory and corrupt + // its metadata. See + // https://github.com/google/sanitizers/issues/321. + int res = REAL(getaddrinfo)(node, service, hints, out); + if (res == 0 && out) { + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, out, sizeof(*out)); + struct __sanitizer_addrinfo *p = *out; + while (p) { + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, p, sizeof(*p)); + if (p->ai_addr) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, p->ai_addr, p->ai_addrlen); + if (p->ai_canonname) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, p->ai_canonname, + internal_strlen(p->ai_canonname) + 1); + p = p->ai_next; + } + } + return res; +} +#define INIT_GETADDRINFO COMMON_INTERCEPT_FUNCTION(getaddrinfo); +#else +#define INIT_GETADDRINFO +#endif + +#if SANITIZER_INTERCEPT_GETNAMEINFO +INTERCEPTOR(int, getnameinfo, void *sockaddr, unsigned salen, char *host, + unsigned hostlen, char *serv, unsigned servlen, int flags) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, getnameinfo, sockaddr, salen, host, hostlen, + serv, servlen, flags); + // FIXME: consider adding READ_RANGE(sockaddr, salen) + // There is padding in in_addr that may make this too noisy + // FIXME: under ASan the call below may write to freed memory and corrupt + // its metadata. See + // https://github.com/google/sanitizers/issues/321. + int res = + REAL(getnameinfo)(sockaddr, salen, host, hostlen, serv, servlen, flags); + if (res == 0) { + if (host && hostlen) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, host, internal_strlen(host) + 1); + if (serv && servlen) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, serv, internal_strlen(serv) + 1); + } + return res; +} +#define INIT_GETNAMEINFO COMMON_INTERCEPT_FUNCTION(getnameinfo); +#else +#define INIT_GETNAMEINFO +#endif + +#if SANITIZER_INTERCEPT_GETSOCKNAME +INTERCEPTOR(int, getsockname, int sock_fd, void *addr, unsigned *addrlen) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, getsockname, sock_fd, addr, addrlen); + unsigned addr_sz; + if (addrlen) { + COMMON_INTERCEPTOR_READ_RANGE(ctx, addrlen, sizeof(*addrlen)); + addr_sz = *addrlen; + } + // FIXME: under ASan the call below may write to freed memory and corrupt + // its metadata. See + // https://github.com/google/sanitizers/issues/321. + int res = REAL(getsockname)(sock_fd, addr, addrlen); + if (!res && addr && addrlen) { + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, addr, Min(addr_sz, *addrlen)); + } + return res; +} +#define INIT_GETSOCKNAME COMMON_INTERCEPT_FUNCTION(getsockname); +#else +#define INIT_GETSOCKNAME +#endif + +#if SANITIZER_INTERCEPT_GETHOSTBYNAME || SANITIZER_INTERCEPT_GETHOSTBYNAME_R +static void write_hostent(void *ctx, struct __sanitizer_hostent *h) { + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, h, sizeof(__sanitizer_hostent)); + if (h->h_name) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, h->h_name, internal_strlen(h->h_name) + 1); + char **p = h->h_aliases; + while (*p) { + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, *p, internal_strlen(*p) + 1); + ++p; + } + COMMON_INTERCEPTOR_WRITE_RANGE( + ctx, h->h_aliases, (p - h->h_aliases + 1) * sizeof(*h->h_aliases)); + p = h->h_addr_list; + while (*p) { + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, *p, h->h_length); + ++p; + } + COMMON_INTERCEPTOR_WRITE_RANGE( + ctx, h->h_addr_list, (p - h->h_addr_list + 1) * sizeof(*h->h_addr_list)); +} +#endif + +#if SANITIZER_INTERCEPT_GETHOSTBYNAME +INTERCEPTOR(struct __sanitizer_hostent *, gethostbyname, char *name) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, gethostbyname, name); + struct __sanitizer_hostent *res = REAL(gethostbyname)(name); + if (res) write_hostent(ctx, res); + return res; +} + +INTERCEPTOR(struct __sanitizer_hostent *, gethostbyaddr, void *addr, int len, + int type) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, gethostbyaddr, addr, len, type); + COMMON_INTERCEPTOR_READ_RANGE(ctx, addr, len); + struct __sanitizer_hostent *res = REAL(gethostbyaddr)(addr, len, type); + if (res) write_hostent(ctx, res); + return res; +} + +INTERCEPTOR(struct __sanitizer_hostent *, gethostent, int fake) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, gethostent, fake); + struct __sanitizer_hostent *res = REAL(gethostent)(fake); + if (res) write_hostent(ctx, res); + return res; +} +#define INIT_GETHOSTBYNAME \ + COMMON_INTERCEPT_FUNCTION(gethostent); \ + COMMON_INTERCEPT_FUNCTION(gethostbyaddr); \ + COMMON_INTERCEPT_FUNCTION(gethostbyname); +#else +#define INIT_GETHOSTBYNAME +#endif // SANITIZER_INTERCEPT_GETHOSTBYNAME + +#if SANITIZER_INTERCEPT_GETHOSTBYNAME2 +INTERCEPTOR(struct __sanitizer_hostent *, gethostbyname2, char *name, int af) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, gethostbyname2, name, af); + struct __sanitizer_hostent *res = REAL(gethostbyname2)(name, af); + if (res) write_hostent(ctx, res); + return res; +} +#define INIT_GETHOSTBYNAME2 COMMON_INTERCEPT_FUNCTION(gethostbyname2); +#else +#define INIT_GETHOSTBYNAME2 +#endif // SANITIZER_INTERCEPT_GETHOSTBYNAME2 + +#if SANITIZER_INTERCEPT_GETHOSTBYNAME_R +INTERCEPTOR(int, gethostbyname_r, char *name, struct __sanitizer_hostent *ret, + char *buf, SIZE_T buflen, __sanitizer_hostent **result, + int *h_errnop) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, gethostbyname_r, name, ret, buf, buflen, result, + h_errnop); + // FIXME: under ASan the call below may write to freed memory and corrupt + // its metadata. See + // https://github.com/google/sanitizers/issues/321. + int res = REAL(gethostbyname_r)(name, ret, buf, buflen, result, h_errnop); + if (result) { + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, result, sizeof(*result)); + if (res == 0 && *result) write_hostent(ctx, *result); + } + if (h_errnop) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, h_errnop, sizeof(*h_errnop)); + return res; +} +#define INIT_GETHOSTBYNAME_R COMMON_INTERCEPT_FUNCTION(gethostbyname_r); +#else +#define INIT_GETHOSTBYNAME_R +#endif + +#if SANITIZER_INTERCEPT_GETHOSTENT_R +INTERCEPTOR(int, gethostent_r, struct __sanitizer_hostent *ret, char *buf, + SIZE_T buflen, __sanitizer_hostent **result, int *h_errnop) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, gethostent_r, ret, buf, buflen, result, + h_errnop); + // FIXME: under ASan the call below may write to freed memory and corrupt + // its metadata. See + // https://github.com/google/sanitizers/issues/321. + int res = REAL(gethostent_r)(ret, buf, buflen, result, h_errnop); + if (result) { + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, result, sizeof(*result)); + if (res == 0 && *result) write_hostent(ctx, *result); + } + if (h_errnop) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, h_errnop, sizeof(*h_errnop)); + return res; +} +#define INIT_GETHOSTENT_R \ + COMMON_INTERCEPT_FUNCTION(gethostent_r); +#else +#define INIT_GETHOSTENT_R +#endif + +#if SANITIZER_INTERCEPT_GETHOSTBYADDR_R +INTERCEPTOR(int, gethostbyaddr_r, void *addr, int len, int type, + struct __sanitizer_hostent *ret, char *buf, SIZE_T buflen, + __sanitizer_hostent **result, int *h_errnop) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, gethostbyaddr_r, addr, len, type, ret, buf, + buflen, result, h_errnop); + COMMON_INTERCEPTOR_READ_RANGE(ctx, addr, len); + // FIXME: under ASan the call below may write to freed memory and corrupt + // its metadata. See + // https://github.com/google/sanitizers/issues/321. + int res = REAL(gethostbyaddr_r)(addr, len, type, ret, buf, buflen, result, + h_errnop); + if (result) { + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, result, sizeof(*result)); + if (res == 0 && *result) write_hostent(ctx, *result); + } + if (h_errnop) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, h_errnop, sizeof(*h_errnop)); + return res; +} +#define INIT_GETHOSTBYADDR_R \ + COMMON_INTERCEPT_FUNCTION(gethostbyaddr_r); +#else +#define INIT_GETHOSTBYADDR_R +#endif + +#if SANITIZER_INTERCEPT_GETHOSTBYNAME2_R +INTERCEPTOR(int, gethostbyname2_r, char *name, int af, + struct __sanitizer_hostent *ret, char *buf, SIZE_T buflen, + __sanitizer_hostent **result, int *h_errnop) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, gethostbyname2_r, name, af, ret, buf, buflen, + result, h_errnop); + // FIXME: under ASan the call below may write to freed memory and corrupt + // its metadata. See + // https://github.com/google/sanitizers/issues/321. + int res = + REAL(gethostbyname2_r)(name, af, ret, buf, buflen, result, h_errnop); + if (result) { + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, result, sizeof(*result)); + if (res == 0 && *result) write_hostent(ctx, *result); + } + if (h_errnop) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, h_errnop, sizeof(*h_errnop)); + return res; +} +#define INIT_GETHOSTBYNAME2_R \ + COMMON_INTERCEPT_FUNCTION(gethostbyname2_r); +#else +#define INIT_GETHOSTBYNAME2_R +#endif + +#if SANITIZER_INTERCEPT_GETSOCKOPT +INTERCEPTOR(int, getsockopt, int sockfd, int level, int optname, void *optval, + int *optlen) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, getsockopt, sockfd, level, optname, optval, + optlen); + if (optlen) COMMON_INTERCEPTOR_READ_RANGE(ctx, optlen, sizeof(*optlen)); + // FIXME: under ASan the call below may write to freed memory and corrupt + // its metadata. See + // https://github.com/google/sanitizers/issues/321. + int res = REAL(getsockopt)(sockfd, level, optname, optval, optlen); + if (res == 0) + if (optval && optlen) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, optval, *optlen); + return res; +} +#define INIT_GETSOCKOPT COMMON_INTERCEPT_FUNCTION(getsockopt); +#else +#define INIT_GETSOCKOPT +#endif + +#if SANITIZER_INTERCEPT_ACCEPT +INTERCEPTOR(int, accept, int fd, void *addr, unsigned *addrlen) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, accept, fd, addr, addrlen); + unsigned addrlen0 = 0; + if (addrlen) { + COMMON_INTERCEPTOR_READ_RANGE(ctx, addrlen, sizeof(*addrlen)); + addrlen0 = *addrlen; + } + int fd2 = REAL(accept)(fd, addr, addrlen); + if (fd2 >= 0) { + if (fd >= 0) COMMON_INTERCEPTOR_FD_SOCKET_ACCEPT(ctx, fd, fd2); + if (addr && addrlen) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, addr, Min(*addrlen, addrlen0)); + } + return fd2; +} +#define INIT_ACCEPT COMMON_INTERCEPT_FUNCTION(accept); +#else +#define INIT_ACCEPT +#endif + +#if SANITIZER_INTERCEPT_ACCEPT4 +INTERCEPTOR(int, accept4, int fd, void *addr, unsigned *addrlen, int f) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, accept4, fd, addr, addrlen, f); + unsigned addrlen0 = 0; + if (addrlen) { + COMMON_INTERCEPTOR_READ_RANGE(ctx, addrlen, sizeof(*addrlen)); + addrlen0 = *addrlen; + } + // FIXME: under ASan the call below may write to freed memory and corrupt + // its metadata. See + // https://github.com/google/sanitizers/issues/321. + int fd2 = REAL(accept4)(fd, addr, addrlen, f); + if (fd2 >= 0) { + if (fd >= 0) COMMON_INTERCEPTOR_FD_SOCKET_ACCEPT(ctx, fd, fd2); + if (addr && addrlen) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, addr, Min(*addrlen, addrlen0)); + } + return fd2; +} +#define INIT_ACCEPT4 COMMON_INTERCEPT_FUNCTION(accept4); +#else +#define INIT_ACCEPT4 +#endif + +#if SANITIZER_INTERCEPT_PACCEPT +INTERCEPTOR(int, paccept, int fd, void *addr, unsigned *addrlen, + __sanitizer_sigset_t *set, int f) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, paccept, fd, addr, addrlen, set, f); + unsigned addrlen0 = 0; + if (addrlen) { + COMMON_INTERCEPTOR_READ_RANGE(ctx, addrlen, sizeof(*addrlen)); + addrlen0 = *addrlen; + } + if (set) COMMON_INTERCEPTOR_READ_RANGE(ctx, set, sizeof(*set)); + int fd2 = REAL(paccept)(fd, addr, addrlen, set, f); + if (fd2 >= 0) { + if (fd >= 0) COMMON_INTERCEPTOR_FD_SOCKET_ACCEPT(ctx, fd, fd2); + if (addr && addrlen) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, addr, Min(*addrlen, addrlen0)); + } + return fd2; +} +#define INIT_PACCEPT COMMON_INTERCEPT_FUNCTION(paccept); +#else +#define INIT_PACCEPT +#endif + +#if SANITIZER_INTERCEPT_MODF +INTERCEPTOR(double, modf, double x, double *iptr) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, modf, x, iptr); + // FIXME: under ASan the call below may write to freed memory and corrupt + // its metadata. See + // https://github.com/google/sanitizers/issues/321. + double res = REAL(modf)(x, iptr); + if (iptr) { + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, iptr, sizeof(*iptr)); + } + return res; +} +INTERCEPTOR(float, modff, float x, float *iptr) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, modff, x, iptr); + // FIXME: under ASan the call below may write to freed memory and corrupt + // its metadata. See + // https://github.com/google/sanitizers/issues/321. + float res = REAL(modff)(x, iptr); + if (iptr) { + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, iptr, sizeof(*iptr)); + } + return res; +} +INTERCEPTOR(long double, modfl, long double x, long double *iptr) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, modfl, x, iptr); + // FIXME: under ASan the call below may write to freed memory and corrupt + // its metadata. See + // https://github.com/google/sanitizers/issues/321. + long double res = REAL(modfl)(x, iptr); + if (iptr) { + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, iptr, sizeof(*iptr)); + } + return res; +} +#define INIT_MODF \ + COMMON_INTERCEPT_FUNCTION(modf); \ + COMMON_INTERCEPT_FUNCTION(modff); \ + COMMON_INTERCEPT_FUNCTION_LDBL(modfl); +#else +#define INIT_MODF +#endif + +#if SANITIZER_INTERCEPT_RECVMSG || SANITIZER_INTERCEPT_RECVMMSG +static void write_msghdr(void *ctx, struct __sanitizer_msghdr *msg, + SSIZE_T maxlen) { + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, msg, sizeof(*msg)); + if (msg->msg_name && msg->msg_namelen) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, msg->msg_name, msg->msg_namelen); + if (msg->msg_iov && msg->msg_iovlen) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, msg->msg_iov, + sizeof(*msg->msg_iov) * msg->msg_iovlen); + write_iovec(ctx, msg->msg_iov, msg->msg_iovlen, maxlen); + if (msg->msg_control && msg->msg_controllen) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, msg->msg_control, msg->msg_controllen); +} +#endif + +#if SANITIZER_INTERCEPT_RECVMSG +INTERCEPTOR(SSIZE_T, recvmsg, int fd, struct __sanitizer_msghdr *msg, + int flags) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, recvmsg, fd, msg, flags); + // FIXME: under ASan the call below may write to freed memory and corrupt + // its metadata. See + // https://github.com/google/sanitizers/issues/321. + SSIZE_T res = REAL(recvmsg)(fd, msg, flags); + if (res >= 0) { + if (fd >= 0) COMMON_INTERCEPTOR_FD_ACQUIRE(ctx, fd); + if (msg) { + write_msghdr(ctx, msg, res); + COMMON_INTERCEPTOR_HANDLE_RECVMSG(ctx, msg); + } + } + return res; +} +#define INIT_RECVMSG COMMON_INTERCEPT_FUNCTION(recvmsg); +#else +#define INIT_RECVMSG +#endif + +#if SANITIZER_INTERCEPT_RECVMMSG +INTERCEPTOR(int, recvmmsg, int fd, struct __sanitizer_mmsghdr *msgvec, + unsigned int vlen, int flags, void *timeout) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, recvmmsg, fd, msgvec, vlen, flags, timeout); + if (timeout) COMMON_INTERCEPTOR_READ_RANGE(ctx, timeout, struct_timespec_sz); + int res = REAL(recvmmsg)(fd, msgvec, vlen, flags, timeout); + if (res >= 0) { + if (fd >= 0) COMMON_INTERCEPTOR_FD_ACQUIRE(ctx, fd); + for (int i = 0; i < res; ++i) { + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, &msgvec[i].msg_len, + sizeof(msgvec[i].msg_len)); + write_msghdr(ctx, &msgvec[i].msg_hdr, msgvec[i].msg_len); + COMMON_INTERCEPTOR_HANDLE_RECVMSG(ctx, &msgvec[i].msg_hdr); + } + } + return res; +} +#define INIT_RECVMMSG COMMON_INTERCEPT_FUNCTION(recvmmsg); +#else +#define INIT_RECVMMSG +#endif + +#if SANITIZER_INTERCEPT_SENDMSG || SANITIZER_INTERCEPT_SENDMMSG +static void read_msghdr_control(void *ctx, void *control, uptr controllen) { + const unsigned kCmsgDataOffset = + RoundUpTo(sizeof(__sanitizer_cmsghdr), sizeof(uptr)); + + char *p = (char *)control; + char *const control_end = p + controllen; + while (true) { + if (p + sizeof(__sanitizer_cmsghdr) > control_end) break; + __sanitizer_cmsghdr *cmsg = (__sanitizer_cmsghdr *)p; + COMMON_INTERCEPTOR_READ_RANGE(ctx, &cmsg->cmsg_len, sizeof(cmsg->cmsg_len)); + + if (p + RoundUpTo(cmsg->cmsg_len, sizeof(uptr)) > control_end) break; + + COMMON_INTERCEPTOR_READ_RANGE(ctx, &cmsg->cmsg_level, + sizeof(cmsg->cmsg_level)); + COMMON_INTERCEPTOR_READ_RANGE(ctx, &cmsg->cmsg_type, + sizeof(cmsg->cmsg_type)); + + if (cmsg->cmsg_len > kCmsgDataOffset) { + char *data = p + kCmsgDataOffset; + unsigned data_len = cmsg->cmsg_len - kCmsgDataOffset; + if (data_len > 0) COMMON_INTERCEPTOR_READ_RANGE(ctx, data, data_len); + } + + p += RoundUpTo(cmsg->cmsg_len, sizeof(uptr)); + } +} + +static void read_msghdr(void *ctx, struct __sanitizer_msghdr *msg, + SSIZE_T maxlen) { +#define R(f) \ + COMMON_INTERCEPTOR_READ_RANGE(ctx, &msg->msg_##f, sizeof(msg->msg_##f)) + R(name); + R(namelen); + R(iov); + R(iovlen); + R(control); + R(controllen); + R(flags); +#undef R + if (msg->msg_name && msg->msg_namelen) + COMMON_INTERCEPTOR_READ_RANGE(ctx, msg->msg_name, msg->msg_namelen); + if (msg->msg_iov && msg->msg_iovlen) + COMMON_INTERCEPTOR_READ_RANGE(ctx, msg->msg_iov, + sizeof(*msg->msg_iov) * msg->msg_iovlen); + read_iovec(ctx, msg->msg_iov, msg->msg_iovlen, maxlen); + if (msg->msg_control && msg->msg_controllen) + read_msghdr_control(ctx, msg->msg_control, msg->msg_controllen); +} +#endif + +#if SANITIZER_INTERCEPT_SENDMSG +INTERCEPTOR(SSIZE_T, sendmsg, int fd, struct __sanitizer_msghdr *msg, + int flags) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, sendmsg, fd, msg, flags); + if (fd >= 0) { + COMMON_INTERCEPTOR_FD_ACCESS(ctx, fd); + COMMON_INTERCEPTOR_FD_RELEASE(ctx, fd); + } + SSIZE_T res = REAL(sendmsg)(fd, msg, flags); + if (common_flags()->intercept_send && res >= 0 && msg) + read_msghdr(ctx, msg, res); + return res; +} +#define INIT_SENDMSG COMMON_INTERCEPT_FUNCTION(sendmsg); +#else +#define INIT_SENDMSG +#endif + +#if SANITIZER_INTERCEPT_SENDMMSG +INTERCEPTOR(int, sendmmsg, int fd, struct __sanitizer_mmsghdr *msgvec, + unsigned vlen, int flags) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, sendmmsg, fd, msgvec, vlen, flags); + if (fd >= 0) { + COMMON_INTERCEPTOR_FD_ACCESS(ctx, fd); + COMMON_INTERCEPTOR_FD_RELEASE(ctx, fd); + } + int res = REAL(sendmmsg)(fd, msgvec, vlen, flags); + if (res >= 0 && msgvec) { + for (int i = 0; i < res; ++i) { + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, &msgvec[i].msg_len, + sizeof(msgvec[i].msg_len)); + if (common_flags()->intercept_send) + read_msghdr(ctx, &msgvec[i].msg_hdr, msgvec[i].msg_len); + } + } + return res; +} +#define INIT_SENDMMSG COMMON_INTERCEPT_FUNCTION(sendmmsg); +#else +#define INIT_SENDMMSG +#endif + +#if SANITIZER_INTERCEPT_SYSMSG +INTERCEPTOR(int, msgsnd, int msqid, const void *msgp, SIZE_T msgsz, + int msgflg) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, msgsnd, msqid, msgp, msgsz, msgflg); + if (msgp) + COMMON_INTERCEPTOR_READ_RANGE(ctx, msgp, sizeof(long) + msgsz); + int res = REAL(msgsnd)(msqid, msgp, msgsz, msgflg); + return res; +} + +INTERCEPTOR(SSIZE_T, msgrcv, int msqid, void *msgp, SIZE_T msgsz, + long msgtyp, int msgflg) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, msgrcv, msqid, msgp, msgsz, msgtyp, msgflg); + SSIZE_T len = REAL(msgrcv)(msqid, msgp, msgsz, msgtyp, msgflg); + if (len != -1) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, msgp, sizeof(long) + len); + return len; +} + +#define INIT_SYSMSG \ + COMMON_INTERCEPT_FUNCTION(msgsnd); \ + COMMON_INTERCEPT_FUNCTION(msgrcv); +#else +#define INIT_SYSMSG +#endif + +#if SANITIZER_INTERCEPT_GETPEERNAME +INTERCEPTOR(int, getpeername, int sockfd, void *addr, unsigned *addrlen) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, getpeername, sockfd, addr, addrlen); + unsigned addr_sz; + if (addrlen) { + COMMON_INTERCEPTOR_READ_RANGE(ctx, addrlen, sizeof(*addrlen)); + addr_sz = *addrlen; + } + // FIXME: under ASan the call below may write to freed memory and corrupt + // its metadata. See + // https://github.com/google/sanitizers/issues/321. + int res = REAL(getpeername)(sockfd, addr, addrlen); + if (!res && addr && addrlen) { + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, addr, Min(addr_sz, *addrlen)); + } + return res; +} +#define INIT_GETPEERNAME COMMON_INTERCEPT_FUNCTION(getpeername); +#else +#define INIT_GETPEERNAME +#endif + +#if SANITIZER_INTERCEPT_SYSINFO +INTERCEPTOR(int, sysinfo, void *info) { + void *ctx; + // FIXME: under ASan the call below may write to freed memory and corrupt + // its metadata. See + // https://github.com/google/sanitizers/issues/321. + COMMON_INTERCEPTOR_ENTER(ctx, sysinfo, info); + int res = REAL(sysinfo)(info); + if (!res && info) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, info, struct_sysinfo_sz); + return res; +} +#define INIT_SYSINFO COMMON_INTERCEPT_FUNCTION(sysinfo); +#else +#define INIT_SYSINFO +#endif + +#if SANITIZER_INTERCEPT_READDIR +INTERCEPTOR(__sanitizer_dirent *, opendir, const char *path) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, opendir, path); + COMMON_INTERCEPTOR_READ_RANGE(ctx, path, internal_strlen(path) + 1); + __sanitizer_dirent *res = REAL(opendir)(path); + if (res) + COMMON_INTERCEPTOR_DIR_ACQUIRE(ctx, path); + return res; +} + +INTERCEPTOR(__sanitizer_dirent *, readdir, void *dirp) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, readdir, dirp); + // FIXME: under ASan the call below may write to freed memory and corrupt + // its metadata. See + // https://github.com/google/sanitizers/issues/321. + __sanitizer_dirent *res = REAL(readdir)(dirp); + if (res) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, res->d_reclen); + return res; +} + +INTERCEPTOR(int, readdir_r, void *dirp, __sanitizer_dirent *entry, + __sanitizer_dirent **result) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, readdir_r, dirp, entry, result); + // FIXME: under ASan the call below may write to freed memory and corrupt + // its metadata. See + // https://github.com/google/sanitizers/issues/321. + int res = REAL(readdir_r)(dirp, entry, result); + if (!res) { + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, result, sizeof(*result)); + if (*result) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, *result, (*result)->d_reclen); + } + return res; +} + +#define INIT_READDIR \ + COMMON_INTERCEPT_FUNCTION(opendir); \ + COMMON_INTERCEPT_FUNCTION(readdir); \ + COMMON_INTERCEPT_FUNCTION(readdir_r); +#else +#define INIT_READDIR +#endif + +#if SANITIZER_INTERCEPT_READDIR64 +INTERCEPTOR(__sanitizer_dirent64 *, readdir64, void *dirp) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, readdir64, dirp); + // FIXME: under ASan the call below may write to freed memory and corrupt + // its metadata. See + // https://github.com/google/sanitizers/issues/321. + __sanitizer_dirent64 *res = REAL(readdir64)(dirp); + if (res) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, res->d_reclen); + return res; +} + +INTERCEPTOR(int, readdir64_r, void *dirp, __sanitizer_dirent64 *entry, + __sanitizer_dirent64 **result) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, readdir64_r, dirp, entry, result); + // FIXME: under ASan the call below may write to freed memory and corrupt + // its metadata. See + // https://github.com/google/sanitizers/issues/321. + int res = REAL(readdir64_r)(dirp, entry, result); + if (!res) { + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, result, sizeof(*result)); + if (*result) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, *result, (*result)->d_reclen); + } + return res; +} +#define INIT_READDIR64 \ + COMMON_INTERCEPT_FUNCTION(readdir64); \ + COMMON_INTERCEPT_FUNCTION(readdir64_r); +#else +#define INIT_READDIR64 +#endif + +#if SANITIZER_INTERCEPT_PTRACE +INTERCEPTOR(uptr, ptrace, int request, int pid, void *addr, void *data) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, ptrace, request, pid, addr, data); + __sanitizer_iovec local_iovec; + + if (data) { + if (request == ptrace_setregs) { + COMMON_INTERCEPTOR_READ_RANGE(ctx, data, struct_user_regs_struct_sz); + } else if (request == ptrace_setfpregs) { + COMMON_INTERCEPTOR_READ_RANGE(ctx, data, struct_user_fpregs_struct_sz); + } else if (request == ptrace_setfpxregs) { + COMMON_INTERCEPTOR_READ_RANGE(ctx, data, struct_user_fpxregs_struct_sz); + } else if (request == ptrace_setvfpregs) { + COMMON_INTERCEPTOR_READ_RANGE(ctx, data, struct_user_vfpregs_struct_sz); + } else if (request == ptrace_setsiginfo) { + COMMON_INTERCEPTOR_READ_RANGE(ctx, data, siginfo_t_sz); + + // Some kernel might zero the iovec::iov_base in case of invalid + // write access. In this case copy the invalid address for further + // inspection. + } else if (request == ptrace_setregset || request == ptrace_getregset) { + __sanitizer_iovec *iovec = (__sanitizer_iovec*)data; + COMMON_INTERCEPTOR_READ_RANGE(ctx, iovec, sizeof(*iovec)); + local_iovec = *iovec; + if (request == ptrace_setregset) + COMMON_INTERCEPTOR_READ_RANGE(ctx, iovec->iov_base, iovec->iov_len); + } + } + + // FIXME: under ASan the call below may write to freed memory and corrupt + // its metadata. See + // https://github.com/google/sanitizers/issues/321. + uptr res = REAL(ptrace)(request, pid, addr, data); + + if (!res && data) { + // Note that PEEK* requests assign different meaning to the return value. + // This function does not handle them (nor does it need to). + if (request == ptrace_getregs) { + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, data, struct_user_regs_struct_sz); + } else if (request == ptrace_getfpregs) { + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, data, struct_user_fpregs_struct_sz); + } else if (request == ptrace_getfpxregs) { + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, data, struct_user_fpxregs_struct_sz); + } else if (request == ptrace_getvfpregs) { + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, data, struct_user_vfpregs_struct_sz); + } else if (request == ptrace_getsiginfo) { + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, data, siginfo_t_sz); + } else if (request == ptrace_geteventmsg) { + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, data, sizeof(unsigned long)); + } else if (request == ptrace_getregset) { + __sanitizer_iovec *iovec = (__sanitizer_iovec*)data; + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, iovec, sizeof(*iovec)); + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, local_iovec.iov_base, + local_iovec.iov_len); + } + } + return res; +} + +#define INIT_PTRACE COMMON_INTERCEPT_FUNCTION(ptrace); +#else +#define INIT_PTRACE +#endif + +#if SANITIZER_INTERCEPT_SETLOCALE +static void unpoison_ctype_arrays(void *ctx) { +#if SANITIZER_NETBSD + // These arrays contain 256 regular elements in unsigned char range + 1 EOF + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, _ctype_tab_, 257 * sizeof(short)); + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, _toupper_tab_, 257 * sizeof(short)); + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, _tolower_tab_, 257 * sizeof(short)); +#endif +} + +INTERCEPTOR(char *, setlocale, int category, char *locale) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, setlocale, category, locale); + if (locale) + COMMON_INTERCEPTOR_READ_RANGE(ctx, locale, internal_strlen(locale) + 1); + char *res = REAL(setlocale)(category, locale); + if (res) { + COMMON_INTERCEPTOR_INITIALIZE_RANGE(res, internal_strlen(res) + 1); + unpoison_ctype_arrays(ctx); + } + return res; +} + +#define INIT_SETLOCALE COMMON_INTERCEPT_FUNCTION(setlocale); +#else +#define INIT_SETLOCALE +#endif + +#if SANITIZER_INTERCEPT_GETCWD +INTERCEPTOR(char *, getcwd, char *buf, SIZE_T size) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, getcwd, buf, size); + // FIXME: under ASan the call below may write to freed memory and corrupt + // its metadata. See + // https://github.com/google/sanitizers/issues/321. + char *res = REAL(getcwd)(buf, size); + if (res) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, internal_strlen(res) + 1); + return res; +} +#define INIT_GETCWD COMMON_INTERCEPT_FUNCTION(getcwd); +#else +#define INIT_GETCWD +#endif + +#if SANITIZER_INTERCEPT_GET_CURRENT_DIR_NAME +INTERCEPTOR(char *, get_current_dir_name, int fake) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, get_current_dir_name, fake); + // FIXME: under ASan the call below may write to freed memory and corrupt + // its metadata. See + // https://github.com/google/sanitizers/issues/321. + char *res = REAL(get_current_dir_name)(fake); + if (res) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, internal_strlen(res) + 1); + return res; +} + +#define INIT_GET_CURRENT_DIR_NAME \ + COMMON_INTERCEPT_FUNCTION(get_current_dir_name); +#else +#define INIT_GET_CURRENT_DIR_NAME +#endif + +UNUSED static inline void FixRealStrtolEndptr(const char *nptr, char **endptr) { + CHECK(endptr); + if (nptr == *endptr) { + // No digits were found at strtol call, we need to find out the last + // symbol accessed by strtoll on our own. + // We get this symbol by skipping leading blanks and optional +/- sign. + while (IsSpace(*nptr)) nptr++; + if (*nptr == '+' || *nptr == '-') nptr++; + *endptr = const_cast<char *>(nptr); + } + CHECK(*endptr >= nptr); +} + +UNUSED static inline void StrtolFixAndCheck(void *ctx, const char *nptr, + char **endptr, char *real_endptr, int base) { + if (endptr) { + *endptr = real_endptr; + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, endptr, sizeof(*endptr)); + } + // If base has unsupported value, strtol can exit with EINVAL + // without reading any characters. So do additional checks only + // if base is valid. + bool is_valid_base = (base == 0) || (2 <= base && base <= 36); + if (is_valid_base) { + FixRealStrtolEndptr(nptr, &real_endptr); + } + COMMON_INTERCEPTOR_READ_STRING(ctx, nptr, is_valid_base ? + (real_endptr - nptr) + 1 : 0); +} + + +#if SANITIZER_INTERCEPT_STRTOIMAX +INTERCEPTOR(INTMAX_T, strtoimax, const char *nptr, char **endptr, int base) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, strtoimax, nptr, endptr, base); + // FIXME: under ASan the call below may write to freed memory and corrupt + // its metadata. See + // https://github.com/google/sanitizers/issues/321. + char *real_endptr; + INTMAX_T res = REAL(strtoimax)(nptr, &real_endptr, base); + StrtolFixAndCheck(ctx, nptr, endptr, real_endptr, base); + return res; +} + +INTERCEPTOR(UINTMAX_T, strtoumax, const char *nptr, char **endptr, int base) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, strtoumax, nptr, endptr, base); + // FIXME: under ASan the call below may write to freed memory and corrupt + // its metadata. See + // https://github.com/google/sanitizers/issues/321. + char *real_endptr; + UINTMAX_T res = REAL(strtoumax)(nptr, &real_endptr, base); + StrtolFixAndCheck(ctx, nptr, endptr, real_endptr, base); + return res; +} + +#define INIT_STRTOIMAX \ + COMMON_INTERCEPT_FUNCTION(strtoimax); \ + COMMON_INTERCEPT_FUNCTION(strtoumax); +#else +#define INIT_STRTOIMAX +#endif + +#if SANITIZER_INTERCEPT_MBSTOWCS +INTERCEPTOR(SIZE_T, mbstowcs, wchar_t *dest, const char *src, SIZE_T len) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, mbstowcs, dest, src, len); + // FIXME: under ASan the call below may write to freed memory and corrupt + // its metadata. See + // https://github.com/google/sanitizers/issues/321. + SIZE_T res = REAL(mbstowcs)(dest, src, len); + if (res != (SIZE_T) - 1 && dest) { + SIZE_T write_cnt = res + (res < len); + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, dest, write_cnt * sizeof(wchar_t)); + } + return res; +} + +INTERCEPTOR(SIZE_T, mbsrtowcs, wchar_t *dest, const char **src, SIZE_T len, + void *ps) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, mbsrtowcs, dest, src, len, ps); + if (src) COMMON_INTERCEPTOR_READ_RANGE(ctx, src, sizeof(*src)); + if (ps) COMMON_INTERCEPTOR_READ_RANGE(ctx, ps, mbstate_t_sz); + // FIXME: under ASan the call below may write to freed memory and corrupt + // its metadata. See + // https://github.com/google/sanitizers/issues/321. + SIZE_T res = REAL(mbsrtowcs)(dest, src, len, ps); + if (res != (SIZE_T)(-1) && dest && src) { + // This function, and several others, may or may not write the terminating + // \0 character. They write it iff they clear *src. + SIZE_T write_cnt = res + !*src; + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, dest, write_cnt * sizeof(wchar_t)); + } + return res; +} + +#define INIT_MBSTOWCS \ + COMMON_INTERCEPT_FUNCTION(mbstowcs); \ + COMMON_INTERCEPT_FUNCTION(mbsrtowcs); +#else +#define INIT_MBSTOWCS +#endif + +#if SANITIZER_INTERCEPT_MBSNRTOWCS +INTERCEPTOR(SIZE_T, mbsnrtowcs, wchar_t *dest, const char **src, SIZE_T nms, + SIZE_T len, void *ps) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, mbsnrtowcs, dest, src, nms, len, ps); + if (src) { + COMMON_INTERCEPTOR_READ_RANGE(ctx, src, sizeof(*src)); + if (nms) COMMON_INTERCEPTOR_READ_RANGE(ctx, *src, nms); + } + if (ps) COMMON_INTERCEPTOR_READ_RANGE(ctx, ps, mbstate_t_sz); + // FIXME: under ASan the call below may write to freed memory and corrupt + // its metadata. See + // https://github.com/google/sanitizers/issues/321. + SIZE_T res = REAL(mbsnrtowcs)(dest, src, nms, len, ps); + if (res != (SIZE_T)(-1) && dest && src) { + SIZE_T write_cnt = res + !*src; + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, dest, write_cnt * sizeof(wchar_t)); + } + return res; +} + +#define INIT_MBSNRTOWCS COMMON_INTERCEPT_FUNCTION(mbsnrtowcs); +#else +#define INIT_MBSNRTOWCS +#endif + +#if SANITIZER_INTERCEPT_WCSTOMBS +INTERCEPTOR(SIZE_T, wcstombs, char *dest, const wchar_t *src, SIZE_T len) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, wcstombs, dest, src, len); + // FIXME: under ASan the call below may write to freed memory and corrupt + // its metadata. See + // https://github.com/google/sanitizers/issues/321. + SIZE_T res = REAL(wcstombs)(dest, src, len); + if (res != (SIZE_T) - 1 && dest) { + SIZE_T write_cnt = res + (res < len); + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, dest, write_cnt); + } + return res; +} + +INTERCEPTOR(SIZE_T, wcsrtombs, char *dest, const wchar_t **src, SIZE_T len, + void *ps) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, wcsrtombs, dest, src, len, ps); + if (src) COMMON_INTERCEPTOR_READ_RANGE(ctx, src, sizeof(*src)); + if (ps) COMMON_INTERCEPTOR_READ_RANGE(ctx, ps, mbstate_t_sz); + // FIXME: under ASan the call below may write to freed memory and corrupt + // its metadata. See + // https://github.com/google/sanitizers/issues/321. + SIZE_T res = REAL(wcsrtombs)(dest, src, len, ps); + if (res != (SIZE_T) - 1 && dest && src) { + SIZE_T write_cnt = res + !*src; + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, dest, write_cnt); + } + return res; +} + +#define INIT_WCSTOMBS \ + COMMON_INTERCEPT_FUNCTION(wcstombs); \ + COMMON_INTERCEPT_FUNCTION(wcsrtombs); +#else +#define INIT_WCSTOMBS +#endif + +#if SANITIZER_INTERCEPT_WCSNRTOMBS +INTERCEPTOR(SIZE_T, wcsnrtombs, char *dest, const wchar_t **src, SIZE_T nms, + SIZE_T len, void *ps) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, wcsnrtombs, dest, src, nms, len, ps); + if (src) { + COMMON_INTERCEPTOR_READ_RANGE(ctx, src, sizeof(*src)); + if (nms) COMMON_INTERCEPTOR_READ_RANGE(ctx, *src, nms); + } + if (ps) COMMON_INTERCEPTOR_READ_RANGE(ctx, ps, mbstate_t_sz); + // FIXME: under ASan the call below may write to freed memory and corrupt + // its metadata. See + // https://github.com/google/sanitizers/issues/321. + SIZE_T res = REAL(wcsnrtombs)(dest, src, nms, len, ps); + if (res != ((SIZE_T)-1) && dest && src) { + SIZE_T write_cnt = res + !*src; + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, dest, write_cnt); + } + return res; +} + +#define INIT_WCSNRTOMBS COMMON_INTERCEPT_FUNCTION(wcsnrtombs); +#else +#define INIT_WCSNRTOMBS +#endif + + +#if SANITIZER_INTERCEPT_WCRTOMB +INTERCEPTOR(SIZE_T, wcrtomb, char *dest, wchar_t src, void *ps) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, wcrtomb, dest, src, ps); + if (ps) COMMON_INTERCEPTOR_READ_RANGE(ctx, ps, mbstate_t_sz); + + if (!dest) + return REAL(wcrtomb)(dest, src, ps); + + char local_dest[32]; + SIZE_T res = REAL(wcrtomb)(local_dest, src, ps); + if (res != ((SIZE_T)-1)) { + CHECK_LE(res, sizeof(local_dest)); + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, dest, res); + REAL(memcpy)(dest, local_dest, res); + } + return res; +} + +#define INIT_WCRTOMB COMMON_INTERCEPT_FUNCTION(wcrtomb); +#else +#define INIT_WCRTOMB +#endif + +#if SANITIZER_INTERCEPT_WCTOMB +INTERCEPTOR(int, wctomb, char *dest, wchar_t src) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, wctomb, dest, src); + if (!dest) + return REAL(wctomb)(dest, src); + + char local_dest[32]; + int res = REAL(wctomb)(local_dest, src); + if (res != -1) { + CHECK_LE(res, sizeof(local_dest)); + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, dest, res); + REAL(memcpy)(dest, local_dest, res); + } + return res; +} + +#define INIT_WCTOMB COMMON_INTERCEPT_FUNCTION(wctomb); +#else +#define INIT_WCTOMB +#endif + +#if SANITIZER_INTERCEPT_TCGETATTR +INTERCEPTOR(int, tcgetattr, int fd, void *termios_p) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, tcgetattr, fd, termios_p); + // FIXME: under ASan the call below may write to freed memory and corrupt + // its metadata. See + // https://github.com/google/sanitizers/issues/321. + int res = REAL(tcgetattr)(fd, termios_p); + if (!res && termios_p) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, termios_p, struct_termios_sz); + return res; +} + +#define INIT_TCGETATTR COMMON_INTERCEPT_FUNCTION(tcgetattr); +#else +#define INIT_TCGETATTR +#endif + +#if SANITIZER_INTERCEPT_REALPATH +INTERCEPTOR(char *, realpath, const char *path, char *resolved_path) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, realpath, path, resolved_path); + if (path) COMMON_INTERCEPTOR_READ_RANGE(ctx, path, internal_strlen(path) + 1); + + // Workaround a bug in glibc where dlsym(RTLD_NEXT, ...) returns the oldest + // version of a versioned symbol. For realpath(), this gives us something + // (called __old_realpath) that does not handle NULL in the second argument. + // Handle it as part of the interceptor. + char *allocated_path = nullptr; + if (!resolved_path) + allocated_path = resolved_path = (char *)WRAP(malloc)(path_max + 1); + + char *res = REAL(realpath)(path, resolved_path); + if (allocated_path && !res) + WRAP(free)(allocated_path); + if (res) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, internal_strlen(res) + 1); + return res; +} +# define INIT_REALPATH COMMON_INTERCEPT_FUNCTION(realpath); +#else +#define INIT_REALPATH +#endif + +#if SANITIZER_INTERCEPT_CANONICALIZE_FILE_NAME +INTERCEPTOR(char *, canonicalize_file_name, const char *path) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, canonicalize_file_name, path); + if (path) COMMON_INTERCEPTOR_READ_RANGE(ctx, path, internal_strlen(path) + 1); + char *res = REAL(canonicalize_file_name)(path); + if (res) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, internal_strlen(res) + 1); + return res; +} +#define INIT_CANONICALIZE_FILE_NAME \ + COMMON_INTERCEPT_FUNCTION(canonicalize_file_name); +#else +#define INIT_CANONICALIZE_FILE_NAME +#endif + +#if SANITIZER_INTERCEPT_CONFSTR +INTERCEPTOR(SIZE_T, confstr, int name, char *buf, SIZE_T len) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, confstr, name, buf, len); + // FIXME: under ASan the call below may write to freed memory and corrupt + // its metadata. See + // https://github.com/google/sanitizers/issues/321. + SIZE_T res = REAL(confstr)(name, buf, len); + if (buf && res) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, res < len ? res : len); + return res; +} +#define INIT_CONFSTR COMMON_INTERCEPT_FUNCTION(confstr); +#else +#define INIT_CONFSTR +#endif + +#if SANITIZER_INTERCEPT_SCHED_GETAFFINITY +INTERCEPTOR(int, sched_getaffinity, int pid, SIZE_T cpusetsize, void *mask) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, sched_getaffinity, pid, cpusetsize, mask); + // FIXME: under ASan the call below may write to freed memory and corrupt + // its metadata. See + // https://github.com/google/sanitizers/issues/321. + int res = REAL(sched_getaffinity)(pid, cpusetsize, mask); + if (mask && !res) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, mask, cpusetsize); + return res; +} +#define INIT_SCHED_GETAFFINITY COMMON_INTERCEPT_FUNCTION(sched_getaffinity); +#else +#define INIT_SCHED_GETAFFINITY +#endif + +#if SANITIZER_INTERCEPT_SCHED_GETPARAM +INTERCEPTOR(int, sched_getparam, int pid, void *param) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, sched_getparam, pid, param); + int res = REAL(sched_getparam)(pid, param); + if (!res) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, param, struct_sched_param_sz); + return res; +} +#define INIT_SCHED_GETPARAM COMMON_INTERCEPT_FUNCTION(sched_getparam); +#else +#define INIT_SCHED_GETPARAM +#endif + +#if SANITIZER_INTERCEPT_STRERROR +INTERCEPTOR(char *, strerror, int errnum) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, strerror, errnum); + COMMON_INTERCEPTOR_STRERROR(); + char *res = REAL(strerror)(errnum); + if (res) COMMON_INTERCEPTOR_INITIALIZE_RANGE(res, internal_strlen(res) + 1); + return res; +} +#define INIT_STRERROR COMMON_INTERCEPT_FUNCTION(strerror); +#else +#define INIT_STRERROR +#endif + +#if SANITIZER_INTERCEPT_STRERROR_R +// There are 2 versions of strerror_r: +// * POSIX version returns 0 on success, negative error code on failure, +// writes message to buf. +// * GNU version returns message pointer, which points to either buf or some +// static storage. +#if ((_POSIX_C_SOURCE >= 200112L || _XOPEN_SOURCE >= 600) && !_GNU_SOURCE) || \ + SANITIZER_MAC || SANITIZER_ANDROID || SANITIZER_NETBSD || \ + SANITIZER_FREEBSD +// POSIX version. Spec is not clear on whether buf is NULL-terminated. +// At least on OSX, buf contents are valid even when the call fails. +INTERCEPTOR(int, strerror_r, int errnum, char *buf, SIZE_T buflen) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, strerror_r, errnum, buf, buflen); + // FIXME: under ASan the call below may write to freed memory and corrupt + // its metadata. See + // https://github.com/google/sanitizers/issues/321. + int res = REAL(strerror_r)(errnum, buf, buflen); + + SIZE_T sz = internal_strnlen(buf, buflen); + if (sz < buflen) ++sz; + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, sz); + return res; +} +#else +// GNU version. +INTERCEPTOR(char *, strerror_r, int errnum, char *buf, SIZE_T buflen) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, strerror_r, errnum, buf, buflen); + // FIXME: under ASan the call below may write to freed memory and corrupt + // its metadata. See + // https://github.com/google/sanitizers/issues/321. + char *res = REAL(strerror_r)(errnum, buf, buflen); + if (res == buf) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, internal_strlen(res) + 1); + else + COMMON_INTERCEPTOR_INITIALIZE_RANGE(res, internal_strlen(res) + 1); + return res; +} +#endif //(_POSIX_C_SOURCE >= 200112L || _XOPEN_SOURCE >= 600) && !_GNU_SOURCE || + //SANITIZER_MAC +#define INIT_STRERROR_R COMMON_INTERCEPT_FUNCTION(strerror_r); +#else +#define INIT_STRERROR_R +#endif + +#if SANITIZER_INTERCEPT_XPG_STRERROR_R +INTERCEPTOR(int, __xpg_strerror_r, int errnum, char *buf, SIZE_T buflen) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, __xpg_strerror_r, errnum, buf, buflen); + // FIXME: under ASan the call below may write to freed memory and corrupt + // its metadata. See + // https://github.com/google/sanitizers/issues/321. + int res = REAL(__xpg_strerror_r)(errnum, buf, buflen); + // This version always returns a null-terminated string. + if (buf && buflen) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, internal_strlen(buf) + 1); + return res; +} +#define INIT_XPG_STRERROR_R COMMON_INTERCEPT_FUNCTION(__xpg_strerror_r); +#else +#define INIT_XPG_STRERROR_R +#endif + +#if SANITIZER_INTERCEPT_SCANDIR +typedef int (*scandir_filter_f)(const struct __sanitizer_dirent *); +typedef int (*scandir_compar_f)(const struct __sanitizer_dirent **, + const struct __sanitizer_dirent **); + +static THREADLOCAL scandir_filter_f scandir_filter; +static THREADLOCAL scandir_compar_f scandir_compar; + +static int wrapped_scandir_filter(const struct __sanitizer_dirent *dir) { + COMMON_INTERCEPTOR_UNPOISON_PARAM(1); + COMMON_INTERCEPTOR_INITIALIZE_RANGE(dir, dir->d_reclen); + return scandir_filter(dir); +} + +static int wrapped_scandir_compar(const struct __sanitizer_dirent **a, + const struct __sanitizer_dirent **b) { + COMMON_INTERCEPTOR_UNPOISON_PARAM(2); + COMMON_INTERCEPTOR_INITIALIZE_RANGE(a, sizeof(*a)); + COMMON_INTERCEPTOR_INITIALIZE_RANGE(*a, (*a)->d_reclen); + COMMON_INTERCEPTOR_INITIALIZE_RANGE(b, sizeof(*b)); + COMMON_INTERCEPTOR_INITIALIZE_RANGE(*b, (*b)->d_reclen); + return scandir_compar(a, b); +} + +INTERCEPTOR(int, scandir, char *dirp, __sanitizer_dirent ***namelist, + scandir_filter_f filter, scandir_compar_f compar) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, scandir, dirp, namelist, filter, compar); + if (dirp) COMMON_INTERCEPTOR_READ_RANGE(ctx, dirp, internal_strlen(dirp) + 1); + scandir_filter = filter; + scandir_compar = compar; + // FIXME: under ASan the call below may write to freed memory and corrupt + // its metadata. See + // https://github.com/google/sanitizers/issues/321. + int res = REAL(scandir)(dirp, namelist, + filter ? wrapped_scandir_filter : nullptr, + compar ? wrapped_scandir_compar : nullptr); + scandir_filter = nullptr; + scandir_compar = nullptr; + if (namelist && res > 0) { + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, namelist, sizeof(*namelist)); + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, *namelist, sizeof(**namelist) * res); + for (int i = 0; i < res; ++i) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, (*namelist)[i], + (*namelist)[i]->d_reclen); + } + return res; +} +#define INIT_SCANDIR COMMON_INTERCEPT_FUNCTION(scandir); +#else +#define INIT_SCANDIR +#endif + +#if SANITIZER_INTERCEPT_SCANDIR64 +typedef int (*scandir64_filter_f)(const struct __sanitizer_dirent64 *); +typedef int (*scandir64_compar_f)(const struct __sanitizer_dirent64 **, + const struct __sanitizer_dirent64 **); + +static THREADLOCAL scandir64_filter_f scandir64_filter; +static THREADLOCAL scandir64_compar_f scandir64_compar; + +static int wrapped_scandir64_filter(const struct __sanitizer_dirent64 *dir) { + COMMON_INTERCEPTOR_UNPOISON_PARAM(1); + COMMON_INTERCEPTOR_INITIALIZE_RANGE(dir, dir->d_reclen); + return scandir64_filter(dir); +} + +static int wrapped_scandir64_compar(const struct __sanitizer_dirent64 **a, + const struct __sanitizer_dirent64 **b) { + COMMON_INTERCEPTOR_UNPOISON_PARAM(2); + COMMON_INTERCEPTOR_INITIALIZE_RANGE(a, sizeof(*a)); + COMMON_INTERCEPTOR_INITIALIZE_RANGE(*a, (*a)->d_reclen); + COMMON_INTERCEPTOR_INITIALIZE_RANGE(b, sizeof(*b)); + COMMON_INTERCEPTOR_INITIALIZE_RANGE(*b, (*b)->d_reclen); + return scandir64_compar(a, b); +} + +INTERCEPTOR(int, scandir64, char *dirp, __sanitizer_dirent64 ***namelist, + scandir64_filter_f filter, scandir64_compar_f compar) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, scandir64, dirp, namelist, filter, compar); + if (dirp) COMMON_INTERCEPTOR_READ_RANGE(ctx, dirp, internal_strlen(dirp) + 1); + scandir64_filter = filter; + scandir64_compar = compar; + // FIXME: under ASan the call below may write to freed memory and corrupt + // its metadata. See + // https://github.com/google/sanitizers/issues/321. + int res = + REAL(scandir64)(dirp, namelist, + filter ? wrapped_scandir64_filter : nullptr, + compar ? wrapped_scandir64_compar : nullptr); + scandir64_filter = nullptr; + scandir64_compar = nullptr; + if (namelist && res > 0) { + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, namelist, sizeof(*namelist)); + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, *namelist, sizeof(**namelist) * res); + for (int i = 0; i < res; ++i) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, (*namelist)[i], + (*namelist)[i]->d_reclen); + } + return res; +} +#define INIT_SCANDIR64 COMMON_INTERCEPT_FUNCTION(scandir64); +#else +#define INIT_SCANDIR64 +#endif + +#if SANITIZER_INTERCEPT_GETGROUPS +INTERCEPTOR(int, getgroups, int size, u32 *lst) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, getgroups, size, lst); + // FIXME: under ASan the call below may write to freed memory and corrupt + // its metadata. See + // https://github.com/google/sanitizers/issues/321. + int res = REAL(getgroups)(size, lst); + if (res >= 0 && lst && size > 0) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, lst, res * sizeof(*lst)); + return res; +} +#define INIT_GETGROUPS COMMON_INTERCEPT_FUNCTION(getgroups); +#else +#define INIT_GETGROUPS +#endif + +#if SANITIZER_INTERCEPT_POLL +static void read_pollfd(void *ctx, __sanitizer_pollfd *fds, + __sanitizer_nfds_t nfds) { + for (unsigned i = 0; i < nfds; ++i) { + COMMON_INTERCEPTOR_READ_RANGE(ctx, &fds[i].fd, sizeof(fds[i].fd)); + COMMON_INTERCEPTOR_READ_RANGE(ctx, &fds[i].events, sizeof(fds[i].events)); + } +} + +static void write_pollfd(void *ctx, __sanitizer_pollfd *fds, + __sanitizer_nfds_t nfds) { + for (unsigned i = 0; i < nfds; ++i) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, &fds[i].revents, + sizeof(fds[i].revents)); +} + +INTERCEPTOR(int, poll, __sanitizer_pollfd *fds, __sanitizer_nfds_t nfds, + int timeout) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, poll, fds, nfds, timeout); + if (fds && nfds) read_pollfd(ctx, fds, nfds); + int res = COMMON_INTERCEPTOR_BLOCK_REAL(poll)(fds, nfds, timeout); + if (fds && nfds) write_pollfd(ctx, fds, nfds); + return res; +} +#define INIT_POLL COMMON_INTERCEPT_FUNCTION(poll); +#else +#define INIT_POLL +#endif + +#if SANITIZER_INTERCEPT_PPOLL +INTERCEPTOR(int, ppoll, __sanitizer_pollfd *fds, __sanitizer_nfds_t nfds, + void *timeout_ts, __sanitizer_sigset_t *sigmask) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, ppoll, fds, nfds, timeout_ts, sigmask); + if (fds && nfds) read_pollfd(ctx, fds, nfds); + if (timeout_ts) + COMMON_INTERCEPTOR_READ_RANGE(ctx, timeout_ts, struct_timespec_sz); + if (sigmask) COMMON_INTERCEPTOR_READ_RANGE(ctx, sigmask, sizeof(*sigmask)); + int res = + COMMON_INTERCEPTOR_BLOCK_REAL(ppoll)(fds, nfds, timeout_ts, sigmask); + if (fds && nfds) write_pollfd(ctx, fds, nfds); + return res; +} +#define INIT_PPOLL COMMON_INTERCEPT_FUNCTION(ppoll); +#else +#define INIT_PPOLL +#endif + +#if SANITIZER_INTERCEPT_WORDEXP +INTERCEPTOR(int, wordexp, char *s, __sanitizer_wordexp_t *p, int flags) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, wordexp, s, p, flags); + if (s) COMMON_INTERCEPTOR_READ_RANGE(ctx, s, internal_strlen(s) + 1); + // FIXME: under ASan the call below may write to freed memory and corrupt + // its metadata. See + // https://github.com/google/sanitizers/issues/321. + int res = REAL(wordexp)(s, p, flags); + if (!res && p) { + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, p, sizeof(*p)); + uptr we_wordc = + ((flags & wordexp_wrde_dooffs) ? p->we_offs : 0) + p->we_wordc; + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, p->we_wordv, + sizeof(*p->we_wordv) * (we_wordc + 1)); + for (uptr i = 0; i < we_wordc; ++i) { + char *w = p->we_wordv[i]; + if (w) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, w, internal_strlen(w) + 1); + } + } + return res; +} +#define INIT_WORDEXP COMMON_INTERCEPT_FUNCTION(wordexp); +#else +#define INIT_WORDEXP +#endif + +#if SANITIZER_INTERCEPT_SIGWAIT +INTERCEPTOR(int, sigwait, __sanitizer_sigset_t *set, int *sig) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, sigwait, set, sig); + if (set) COMMON_INTERCEPTOR_READ_RANGE(ctx, set, sizeof(*set)); + // FIXME: under ASan the call below may write to freed memory and corrupt + // its metadata. See + // https://github.com/google/sanitizers/issues/321. + int res = COMMON_INTERCEPTOR_BLOCK_REAL(sigwait)(set, sig); + if (!res && sig) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, sig, sizeof(*sig)); + return res; +} +#define INIT_SIGWAIT COMMON_INTERCEPT_FUNCTION(sigwait); +#else +#define INIT_SIGWAIT +#endif + +#if SANITIZER_INTERCEPT_SIGWAITINFO +INTERCEPTOR(int, sigwaitinfo, __sanitizer_sigset_t *set, void *info) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, sigwaitinfo, set, info); + if (set) COMMON_INTERCEPTOR_READ_RANGE(ctx, set, sizeof(*set)); + // FIXME: under ASan the call below may write to freed memory and corrupt + // its metadata. See + // https://github.com/google/sanitizers/issues/321. + int res = COMMON_INTERCEPTOR_BLOCK_REAL(sigwaitinfo)(set, info); + if (res > 0 && info) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, info, siginfo_t_sz); + return res; +} +#define INIT_SIGWAITINFO COMMON_INTERCEPT_FUNCTION(sigwaitinfo); +#else +#define INIT_SIGWAITINFO +#endif + +#if SANITIZER_INTERCEPT_SIGTIMEDWAIT +INTERCEPTOR(int, sigtimedwait, __sanitizer_sigset_t *set, void *info, + void *timeout) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, sigtimedwait, set, info, timeout); + if (timeout) COMMON_INTERCEPTOR_READ_RANGE(ctx, timeout, struct_timespec_sz); + if (set) COMMON_INTERCEPTOR_READ_RANGE(ctx, set, sizeof(*set)); + // FIXME: under ASan the call below may write to freed memory and corrupt + // its metadata. See + // https://github.com/google/sanitizers/issues/321. + int res = COMMON_INTERCEPTOR_BLOCK_REAL(sigtimedwait)(set, info, timeout); + if (res > 0 && info) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, info, siginfo_t_sz); + return res; +} +#define INIT_SIGTIMEDWAIT COMMON_INTERCEPT_FUNCTION(sigtimedwait); +#else +#define INIT_SIGTIMEDWAIT +#endif + +#if SANITIZER_INTERCEPT_SIGSETOPS +INTERCEPTOR(int, sigemptyset, __sanitizer_sigset_t *set) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, sigemptyset, set); + // FIXME: under ASan the call below may write to freed memory and corrupt + // its metadata. See + // https://github.com/google/sanitizers/issues/321. + int res = REAL(sigemptyset)(set); + if (!res && set) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, set, sizeof(*set)); + return res; +} + +INTERCEPTOR(int, sigfillset, __sanitizer_sigset_t *set) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, sigfillset, set); + // FIXME: under ASan the call below may write to freed memory and corrupt + // its metadata. See + // https://github.com/google/sanitizers/issues/321. + int res = REAL(sigfillset)(set); + if (!res && set) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, set, sizeof(*set)); + return res; +} +#define INIT_SIGSETOPS \ + COMMON_INTERCEPT_FUNCTION(sigemptyset); \ + COMMON_INTERCEPT_FUNCTION(sigfillset); +#else +#define INIT_SIGSETOPS +#endif + +#if SANITIZER_INTERCEPT_SIGSET_LOGICOPS +INTERCEPTOR(int, sigandset, __sanitizer_sigset_t *dst, + __sanitizer_sigset_t *src1, __sanitizer_sigset_t *src2) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, sigandset, dst, src1, src2); + if (src1) + COMMON_INTERCEPTOR_READ_RANGE(ctx, src1, sizeof(*src1)); + if (src2) + COMMON_INTERCEPTOR_READ_RANGE(ctx, src2, sizeof(*src2)); + int res = REAL(sigandset)(dst, src1, src2); + if (!res && dst) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, dst, sizeof(*dst)); + return res; +} + +INTERCEPTOR(int, sigorset, __sanitizer_sigset_t *dst, + __sanitizer_sigset_t *src1, __sanitizer_sigset_t *src2) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, sigorset, dst, src1, src2); + if (src1) + COMMON_INTERCEPTOR_READ_RANGE(ctx, src1, sizeof(*src1)); + if (src2) + COMMON_INTERCEPTOR_READ_RANGE(ctx, src2, sizeof(*src2)); + int res = REAL(sigorset)(dst, src1, src2); + if (!res && dst) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, dst, sizeof(*dst)); + return res; +} +#define INIT_SIGSET_LOGICOPS \ + COMMON_INTERCEPT_FUNCTION(sigandset); \ + COMMON_INTERCEPT_FUNCTION(sigorset); +#else +#define INIT_SIGSET_LOGICOPS +#endif + +#if SANITIZER_INTERCEPT_SIGPENDING +INTERCEPTOR(int, sigpending, __sanitizer_sigset_t *set) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, sigpending, set); + // FIXME: under ASan the call below may write to freed memory and corrupt + // its metadata. See + // https://github.com/google/sanitizers/issues/321. + int res = REAL(sigpending)(set); + if (!res && set) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, set, sizeof(*set)); + return res; +} +#define INIT_SIGPENDING COMMON_INTERCEPT_FUNCTION(sigpending); +#else +#define INIT_SIGPENDING +#endif + +#if SANITIZER_INTERCEPT_SIGPROCMASK +INTERCEPTOR(int, sigprocmask, int how, __sanitizer_sigset_t *set, + __sanitizer_sigset_t *oldset) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, sigprocmask, how, set, oldset); + if (set) COMMON_INTERCEPTOR_READ_RANGE(ctx, set, sizeof(*set)); + // FIXME: under ASan the call below may write to freed memory and corrupt + // its metadata. See + // https://github.com/google/sanitizers/issues/321. + int res = REAL(sigprocmask)(how, set, oldset); + if (!res && oldset) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, oldset, sizeof(*oldset)); + return res; +} +#define INIT_SIGPROCMASK COMMON_INTERCEPT_FUNCTION(sigprocmask); +#else +#define INIT_SIGPROCMASK +#endif + +#if SANITIZER_INTERCEPT_PTHREAD_SIGMASK +INTERCEPTOR(int, pthread_sigmask, int how, __sanitizer_sigset_t *set, + __sanitizer_sigset_t *oldset) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, pthread_sigmask, how, set, oldset); + if (set) COMMON_INTERCEPTOR_READ_RANGE(ctx, set, sizeof(*set)); + // FIXME: under ASan the call below may write to freed memory and corrupt + // its metadata. See + // https://github.com/google/sanitizers/issues/321. + int res = REAL(pthread_sigmask)(how, set, oldset); + if (!res && oldset) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, oldset, sizeof(*oldset)); + return res; +} +#define INIT_PTHREAD_SIGMASK COMMON_INTERCEPT_FUNCTION(pthread_sigmask); +#else +#define INIT_PTHREAD_SIGMASK +#endif + +#if SANITIZER_INTERCEPT_BACKTRACE +INTERCEPTOR(int, backtrace, void **buffer, int size) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, backtrace, buffer, size); + // FIXME: under ASan the call below may write to freed memory and corrupt + // its metadata. See + // https://github.com/google/sanitizers/issues/321. + int res = REAL(backtrace)(buffer, size); + if (res && buffer) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buffer, res * sizeof(*buffer)); + return res; +} + +INTERCEPTOR(char **, backtrace_symbols, void **buffer, int size) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, backtrace_symbols, buffer, size); + if (buffer && size) + COMMON_INTERCEPTOR_READ_RANGE(ctx, buffer, size * sizeof(*buffer)); + // FIXME: under ASan the call below may write to freed memory and corrupt + // its metadata. See + // https://github.com/google/sanitizers/issues/321. + char **res = REAL(backtrace_symbols)(buffer, size); + if (res && size) { + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, size * sizeof(*res)); + for (int i = 0; i < size; ++i) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res[i], internal_strlen(res[i]) + 1); + } + return res; +} +#define INIT_BACKTRACE \ + COMMON_INTERCEPT_FUNCTION(backtrace); \ + COMMON_INTERCEPT_FUNCTION(backtrace_symbols); +#else +#define INIT_BACKTRACE +#endif + +#if SANITIZER_INTERCEPT__EXIT +INTERCEPTOR(void, _exit, int status) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, _exit, status); + COMMON_INTERCEPTOR_USER_CALLBACK_START(); + int status1 = COMMON_INTERCEPTOR_ON_EXIT(ctx); + COMMON_INTERCEPTOR_USER_CALLBACK_END(); + if (status == 0) status = status1; + REAL(_exit)(status); +} +#define INIT__EXIT COMMON_INTERCEPT_FUNCTION(_exit); +#else +#define INIT__EXIT +#endif + +#if SANITIZER_INTERCEPT_PTHREAD_MUTEX +INTERCEPTOR(int, pthread_mutex_lock, void *m) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, pthread_mutex_lock, m); + COMMON_INTERCEPTOR_MUTEX_PRE_LOCK(ctx, m); + int res = REAL(pthread_mutex_lock)(m); + if (res == errno_EOWNERDEAD) + COMMON_INTERCEPTOR_MUTEX_REPAIR(ctx, m); + if (res == 0 || res == errno_EOWNERDEAD) + COMMON_INTERCEPTOR_MUTEX_POST_LOCK(ctx, m); + if (res == errno_EINVAL) + COMMON_INTERCEPTOR_MUTEX_INVALID(ctx, m); + return res; +} + +INTERCEPTOR(int, pthread_mutex_unlock, void *m) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, pthread_mutex_unlock, m); + COMMON_INTERCEPTOR_MUTEX_UNLOCK(ctx, m); + int res = REAL(pthread_mutex_unlock)(m); + if (res == errno_EINVAL) + COMMON_INTERCEPTOR_MUTEX_INVALID(ctx, m); + return res; +} + +#define INIT_PTHREAD_MUTEX_LOCK COMMON_INTERCEPT_FUNCTION(pthread_mutex_lock) +#define INIT_PTHREAD_MUTEX_UNLOCK \ + COMMON_INTERCEPT_FUNCTION(pthread_mutex_unlock) +#else +#define INIT_PTHREAD_MUTEX_LOCK +#define INIT_PTHREAD_MUTEX_UNLOCK +#endif + +#if SANITIZER_INTERCEPT___PTHREAD_MUTEX +INTERCEPTOR(int, __pthread_mutex_lock, void *m) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, __pthread_mutex_lock, m); + COMMON_INTERCEPTOR_MUTEX_PRE_LOCK(ctx, m); + int res = REAL(__pthread_mutex_lock)(m); + if (res == errno_EOWNERDEAD) + COMMON_INTERCEPTOR_MUTEX_REPAIR(ctx, m); + if (res == 0 || res == errno_EOWNERDEAD) + COMMON_INTERCEPTOR_MUTEX_POST_LOCK(ctx, m); + if (res == errno_EINVAL) + COMMON_INTERCEPTOR_MUTEX_INVALID(ctx, m); + return res; +} + +INTERCEPTOR(int, __pthread_mutex_unlock, void *m) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, __pthread_mutex_unlock, m); + COMMON_INTERCEPTOR_MUTEX_UNLOCK(ctx, m); + int res = REAL(__pthread_mutex_unlock)(m); + if (res == errno_EINVAL) + COMMON_INTERCEPTOR_MUTEX_INVALID(ctx, m); + return res; +} + +#define INIT___PTHREAD_MUTEX_LOCK \ + COMMON_INTERCEPT_FUNCTION(__pthread_mutex_lock) +#define INIT___PTHREAD_MUTEX_UNLOCK \ + COMMON_INTERCEPT_FUNCTION(__pthread_mutex_unlock) +#else +#define INIT___PTHREAD_MUTEX_LOCK +#define INIT___PTHREAD_MUTEX_UNLOCK +#endif + +#if SANITIZER_INTERCEPT___LIBC_MUTEX +INTERCEPTOR(int, __libc_mutex_lock, void *m) +ALIAS(WRAPPER_NAME(pthread_mutex_lock)); + +INTERCEPTOR(int, __libc_mutex_unlock, void *m) +ALIAS(WRAPPER_NAME(pthread_mutex_unlock)); + +INTERCEPTOR(int, __libc_thr_setcancelstate, int state, int *oldstate) +ALIAS(WRAPPER_NAME(pthread_setcancelstate)); + +#define INIT___LIBC_MUTEX_LOCK COMMON_INTERCEPT_FUNCTION(__libc_mutex_lock) +#define INIT___LIBC_MUTEX_UNLOCK COMMON_INTERCEPT_FUNCTION(__libc_mutex_unlock) +#define INIT___LIBC_THR_SETCANCELSTATE \ + COMMON_INTERCEPT_FUNCTION(__libc_thr_setcancelstate) +#else +#define INIT___LIBC_MUTEX_LOCK +#define INIT___LIBC_MUTEX_UNLOCK +#define INIT___LIBC_THR_SETCANCELSTATE +#endif + +#if SANITIZER_INTERCEPT_GETMNTENT || SANITIZER_INTERCEPT_GETMNTENT_R +static void write_mntent(void *ctx, __sanitizer_mntent *mnt) { + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, mnt, sizeof(*mnt)); + if (mnt->mnt_fsname) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, mnt->mnt_fsname, + internal_strlen(mnt->mnt_fsname) + 1); + if (mnt->mnt_dir) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, mnt->mnt_dir, + internal_strlen(mnt->mnt_dir) + 1); + if (mnt->mnt_type) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, mnt->mnt_type, + internal_strlen(mnt->mnt_type) + 1); + if (mnt->mnt_opts) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, mnt->mnt_opts, + internal_strlen(mnt->mnt_opts) + 1); +} +#endif + +#if SANITIZER_INTERCEPT_GETMNTENT +INTERCEPTOR(__sanitizer_mntent *, getmntent, void *fp) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, getmntent, fp); + __sanitizer_mntent *res = REAL(getmntent)(fp); + if (res) write_mntent(ctx, res); + return res; +} +#define INIT_GETMNTENT COMMON_INTERCEPT_FUNCTION(getmntent); +#else +#define INIT_GETMNTENT +#endif + +#if SANITIZER_INTERCEPT_GETMNTENT_R +INTERCEPTOR(__sanitizer_mntent *, getmntent_r, void *fp, + __sanitizer_mntent *mntbuf, char *buf, int buflen) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, getmntent_r, fp, mntbuf, buf, buflen); + __sanitizer_mntent *res = REAL(getmntent_r)(fp, mntbuf, buf, buflen); + if (res) write_mntent(ctx, res); + return res; +} +#define INIT_GETMNTENT_R COMMON_INTERCEPT_FUNCTION(getmntent_r); +#else +#define INIT_GETMNTENT_R +#endif + +#if SANITIZER_INTERCEPT_STATFS +INTERCEPTOR(int, statfs, char *path, void *buf) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, statfs, path, buf); + if (path) COMMON_INTERCEPTOR_READ_RANGE(ctx, path, internal_strlen(path) + 1); + // FIXME: under ASan the call below may write to freed memory and corrupt + // its metadata. See + // https://github.com/google/sanitizers/issues/321. + int res = REAL(statfs)(path, buf); + if (!res) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, struct_statfs_sz); + return res; +} +INTERCEPTOR(int, fstatfs, int fd, void *buf) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, fstatfs, fd, buf); + // FIXME: under ASan the call below may write to freed memory and corrupt + // its metadata. See + // https://github.com/google/sanitizers/issues/321. + int res = REAL(fstatfs)(fd, buf); + if (!res) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, struct_statfs_sz); + return res; +} +#define INIT_STATFS \ + COMMON_INTERCEPT_FUNCTION(statfs); \ + COMMON_INTERCEPT_FUNCTION(fstatfs); +#else +#define INIT_STATFS +#endif + +#if SANITIZER_INTERCEPT_STATFS64 +INTERCEPTOR(int, statfs64, char *path, void *buf) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, statfs64, path, buf); + if (path) COMMON_INTERCEPTOR_READ_RANGE(ctx, path, internal_strlen(path) + 1); + // FIXME: under ASan the call below may write to freed memory and corrupt + // its metadata. See + // https://github.com/google/sanitizers/issues/321. + int res = REAL(statfs64)(path, buf); + if (!res) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, struct_statfs64_sz); + return res; +} +INTERCEPTOR(int, fstatfs64, int fd, void *buf) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, fstatfs64, fd, buf); + // FIXME: under ASan the call below may write to freed memory and corrupt + // its metadata. See + // https://github.com/google/sanitizers/issues/321. + int res = REAL(fstatfs64)(fd, buf); + if (!res) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, struct_statfs64_sz); + return res; +} +#define INIT_STATFS64 \ + COMMON_INTERCEPT_FUNCTION(statfs64); \ + COMMON_INTERCEPT_FUNCTION(fstatfs64); +#else +#define INIT_STATFS64 +#endif + +#if SANITIZER_INTERCEPT_STATVFS +INTERCEPTOR(int, statvfs, char *path, void *buf) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, statvfs, path, buf); + if (path) COMMON_INTERCEPTOR_READ_RANGE(ctx, path, internal_strlen(path) + 1); + // FIXME: under ASan the call below may write to freed memory and corrupt + // its metadata. See + // https://github.com/google/sanitizers/issues/321. + int res = REAL(statvfs)(path, buf); + if (!res) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, struct_statvfs_sz); + return res; +} +INTERCEPTOR(int, fstatvfs, int fd, void *buf) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, fstatvfs, fd, buf); + COMMON_INTERCEPTOR_FD_ACCESS(ctx, fd); + // FIXME: under ASan the call below may write to freed memory and corrupt + // its metadata. See + // https://github.com/google/sanitizers/issues/321. + int res = REAL(fstatvfs)(fd, buf); + if (!res) { + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, struct_statvfs_sz); + if (fd >= 0) + COMMON_INTERCEPTOR_FD_ACQUIRE(ctx, fd); + } + return res; +} +#define INIT_STATVFS \ + COMMON_INTERCEPT_FUNCTION(statvfs); \ + COMMON_INTERCEPT_FUNCTION(fstatvfs); +#else +#define INIT_STATVFS +#endif + +#if SANITIZER_INTERCEPT_STATVFS64 +INTERCEPTOR(int, statvfs64, char *path, void *buf) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, statvfs64, path, buf); + if (path) COMMON_INTERCEPTOR_READ_RANGE(ctx, path, internal_strlen(path) + 1); + // FIXME: under ASan the call below may write to freed memory and corrupt + // its metadata. See + // https://github.com/google/sanitizers/issues/321. + int res = REAL(statvfs64)(path, buf); + if (!res) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, struct_statvfs64_sz); + return res; +} +INTERCEPTOR(int, fstatvfs64, int fd, void *buf) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, fstatvfs64, fd, buf); + // FIXME: under ASan the call below may write to freed memory and corrupt + // its metadata. See + // https://github.com/google/sanitizers/issues/321. + int res = REAL(fstatvfs64)(fd, buf); + if (!res) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, struct_statvfs64_sz); + return res; +} +#define INIT_STATVFS64 \ + COMMON_INTERCEPT_FUNCTION(statvfs64); \ + COMMON_INTERCEPT_FUNCTION(fstatvfs64); +#else +#define INIT_STATVFS64 +#endif + +#if SANITIZER_INTERCEPT_INITGROUPS +INTERCEPTOR(int, initgroups, char *user, u32 group) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, initgroups, user, group); + if (user) COMMON_INTERCEPTOR_READ_RANGE(ctx, user, internal_strlen(user) + 1); + int res = REAL(initgroups)(user, group); + return res; +} +#define INIT_INITGROUPS COMMON_INTERCEPT_FUNCTION(initgroups); +#else +#define INIT_INITGROUPS +#endif + +#if SANITIZER_INTERCEPT_ETHER_NTOA_ATON +INTERCEPTOR(char *, ether_ntoa, __sanitizer_ether_addr *addr) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, ether_ntoa, addr); + if (addr) COMMON_INTERCEPTOR_READ_RANGE(ctx, addr, sizeof(*addr)); + char *res = REAL(ether_ntoa)(addr); + if (res) COMMON_INTERCEPTOR_INITIALIZE_RANGE(res, internal_strlen(res) + 1); + return res; +} +INTERCEPTOR(__sanitizer_ether_addr *, ether_aton, char *buf) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, ether_aton, buf); + if (buf) COMMON_INTERCEPTOR_READ_RANGE(ctx, buf, internal_strlen(buf) + 1); + __sanitizer_ether_addr *res = REAL(ether_aton)(buf); + if (res) COMMON_INTERCEPTOR_INITIALIZE_RANGE(res, sizeof(*res)); + return res; +} +#define INIT_ETHER_NTOA_ATON \ + COMMON_INTERCEPT_FUNCTION(ether_ntoa); \ + COMMON_INTERCEPT_FUNCTION(ether_aton); +#else +#define INIT_ETHER_NTOA_ATON +#endif + +#if SANITIZER_INTERCEPT_ETHER_HOST +INTERCEPTOR(int, ether_ntohost, char *hostname, __sanitizer_ether_addr *addr) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, ether_ntohost, hostname, addr); + if (addr) COMMON_INTERCEPTOR_READ_RANGE(ctx, addr, sizeof(*addr)); + // FIXME: under ASan the call below may write to freed memory and corrupt + // its metadata. See + // https://github.com/google/sanitizers/issues/321. + int res = REAL(ether_ntohost)(hostname, addr); + if (!res && hostname) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, hostname, internal_strlen(hostname) + 1); + return res; +} +INTERCEPTOR(int, ether_hostton, char *hostname, __sanitizer_ether_addr *addr) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, ether_hostton, hostname, addr); + if (hostname) + COMMON_INTERCEPTOR_READ_RANGE(ctx, hostname, internal_strlen(hostname) + 1); + // FIXME: under ASan the call below may write to freed memory and corrupt + // its metadata. See + // https://github.com/google/sanitizers/issues/321. + int res = REAL(ether_hostton)(hostname, addr); + if (!res && addr) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, addr, sizeof(*addr)); + return res; +} +INTERCEPTOR(int, ether_line, char *line, __sanitizer_ether_addr *addr, + char *hostname) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, ether_line, line, addr, hostname); + if (line) COMMON_INTERCEPTOR_READ_RANGE(ctx, line, internal_strlen(line) + 1); + // FIXME: under ASan the call below may write to freed memory and corrupt + // its metadata. See + // https://github.com/google/sanitizers/issues/321. + int res = REAL(ether_line)(line, addr, hostname); + if (!res) { + if (addr) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, addr, sizeof(*addr)); + if (hostname) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, hostname, internal_strlen(hostname) + 1); + } + return res; +} +#define INIT_ETHER_HOST \ + COMMON_INTERCEPT_FUNCTION(ether_ntohost); \ + COMMON_INTERCEPT_FUNCTION(ether_hostton); \ + COMMON_INTERCEPT_FUNCTION(ether_line); +#else +#define INIT_ETHER_HOST +#endif + +#if SANITIZER_INTERCEPT_ETHER_R +INTERCEPTOR(char *, ether_ntoa_r, __sanitizer_ether_addr *addr, char *buf) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, ether_ntoa_r, addr, buf); + if (addr) COMMON_INTERCEPTOR_READ_RANGE(ctx, addr, sizeof(*addr)); + // FIXME: under ASan the call below may write to freed memory and corrupt + // its metadata. See + // https://github.com/google/sanitizers/issues/321. + char *res = REAL(ether_ntoa_r)(addr, buf); + if (res) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, internal_strlen(res) + 1); + return res; +} +INTERCEPTOR(__sanitizer_ether_addr *, ether_aton_r, char *buf, + __sanitizer_ether_addr *addr) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, ether_aton_r, buf, addr); + if (buf) COMMON_INTERCEPTOR_READ_RANGE(ctx, buf, internal_strlen(buf) + 1); + // FIXME: under ASan the call below may write to freed memory and corrupt + // its metadata. See + // https://github.com/google/sanitizers/issues/321. + __sanitizer_ether_addr *res = REAL(ether_aton_r)(buf, addr); + if (res) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, sizeof(*res)); + return res; +} +#define INIT_ETHER_R \ + COMMON_INTERCEPT_FUNCTION(ether_ntoa_r); \ + COMMON_INTERCEPT_FUNCTION(ether_aton_r); +#else +#define INIT_ETHER_R +#endif + +#if SANITIZER_INTERCEPT_SHMCTL +INTERCEPTOR(int, shmctl, int shmid, int cmd, void *buf) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, shmctl, shmid, cmd, buf); + // FIXME: under ASan the call below may write to freed memory and corrupt + // its metadata. See + // https://github.com/google/sanitizers/issues/321. + int res = REAL(shmctl)(shmid, cmd, buf); + if (res >= 0) { + unsigned sz = 0; + if (cmd == shmctl_ipc_stat || cmd == shmctl_shm_stat) + sz = sizeof(__sanitizer_shmid_ds); + else if (cmd == shmctl_ipc_info) + sz = struct_shminfo_sz; + else if (cmd == shmctl_shm_info) + sz = struct_shm_info_sz; + if (sz) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, sz); + } + return res; +} +#define INIT_SHMCTL COMMON_INTERCEPT_FUNCTION(shmctl); +#else +#define INIT_SHMCTL +#endif + +#if SANITIZER_INTERCEPT_RANDOM_R +INTERCEPTOR(int, random_r, void *buf, u32 *result) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, random_r, buf, result); + // FIXME: under ASan the call below may write to freed memory and corrupt + // its metadata. See + // https://github.com/google/sanitizers/issues/321. + int res = REAL(random_r)(buf, result); + if (!res && result) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, result, sizeof(*result)); + return res; +} +#define INIT_RANDOM_R COMMON_INTERCEPT_FUNCTION(random_r); +#else +#define INIT_RANDOM_R +#endif + +// FIXME: under ASan the REAL() call below may write to freed memory and corrupt +// its metadata. See +// https://github.com/google/sanitizers/issues/321. +#if SANITIZER_INTERCEPT_PTHREAD_ATTR_GET || \ + SANITIZER_INTERCEPT_PTHREAD_ATTR_GET_SCHED || \ + SANITIZER_INTERCEPT_PTHREAD_ATTR_GETINHERITSSCHED || \ + SANITIZER_INTERCEPT_PTHREAD_MUTEXATTR_GET || \ + SANITIZER_INTERCEPT_PTHREAD_RWLOCKATTR_GET || \ + SANITIZER_INTERCEPT_PTHREAD_CONDATTR_GET || \ + SANITIZER_INTERCEPT_PTHREAD_BARRIERATTR_GET +#define INTERCEPTOR_PTHREAD_OBJECT_ATTR_GET(fn, sz) \ + INTERCEPTOR(int, fn, void *attr, void *r) { \ + void *ctx; \ + COMMON_INTERCEPTOR_ENTER(ctx, fn, attr, r); \ + int res = REAL(fn)(attr, r); \ + if (!res && r) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, r, sz); \ + return res; \ + } +#define INTERCEPTOR_PTHREAD_ATTR_GET(what, sz) \ + INTERCEPTOR_PTHREAD_OBJECT_ATTR_GET(pthread_attr_get##what, sz) +#define INTERCEPTOR_PTHREAD_MUTEXATTR_GET(what, sz) \ + INTERCEPTOR_PTHREAD_OBJECT_ATTR_GET(pthread_mutexattr_get##what, sz) +#define INTERCEPTOR_PTHREAD_RWLOCKATTR_GET(what, sz) \ + INTERCEPTOR_PTHREAD_OBJECT_ATTR_GET(pthread_rwlockattr_get##what, sz) +#define INTERCEPTOR_PTHREAD_CONDATTR_GET(what, sz) \ + INTERCEPTOR_PTHREAD_OBJECT_ATTR_GET(pthread_condattr_get##what, sz) +#define INTERCEPTOR_PTHREAD_BARRIERATTR_GET(what, sz) \ + INTERCEPTOR_PTHREAD_OBJECT_ATTR_GET(pthread_barrierattr_get##what, sz) +#endif + +#if SANITIZER_INTERCEPT_PTHREAD_ATTR_GET +INTERCEPTOR_PTHREAD_ATTR_GET(detachstate, sizeof(int)) +INTERCEPTOR_PTHREAD_ATTR_GET(guardsize, sizeof(SIZE_T)) +INTERCEPTOR_PTHREAD_ATTR_GET(scope, sizeof(int)) +INTERCEPTOR_PTHREAD_ATTR_GET(stacksize, sizeof(SIZE_T)) +INTERCEPTOR(int, pthread_attr_getstack, void *attr, void **addr, SIZE_T *size) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, pthread_attr_getstack, attr, addr, size); + // FIXME: under ASan the call below may write to freed memory and corrupt + // its metadata. See + // https://github.com/google/sanitizers/issues/321. + int res = REAL(pthread_attr_getstack)(attr, addr, size); + if (!res) { + if (addr) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, addr, sizeof(*addr)); + if (size) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, size, sizeof(*size)); + } + return res; +} + +// We may need to call the real pthread_attr_getstack from the run-time +// in sanitizer_common, but we don't want to include the interception headers +// there. So, just define this function here. +namespace __sanitizer { +extern "C" { +int real_pthread_attr_getstack(void *attr, void **addr, SIZE_T *size) { + return REAL(pthread_attr_getstack)(attr, addr, size); +} +} // extern "C" +} // namespace __sanitizer + +#define INIT_PTHREAD_ATTR_GET \ + COMMON_INTERCEPT_FUNCTION(pthread_attr_getdetachstate); \ + COMMON_INTERCEPT_FUNCTION(pthread_attr_getguardsize); \ + COMMON_INTERCEPT_FUNCTION(pthread_attr_getscope); \ + COMMON_INTERCEPT_FUNCTION(pthread_attr_getstacksize); \ + COMMON_INTERCEPT_FUNCTION(pthread_attr_getstack); +#else +#define INIT_PTHREAD_ATTR_GET +#endif + +#if SANITIZER_INTERCEPT_PTHREAD_ATTR_GET_SCHED +INTERCEPTOR_PTHREAD_ATTR_GET(schedparam, struct_sched_param_sz) +INTERCEPTOR_PTHREAD_ATTR_GET(schedpolicy, sizeof(int)) + +#define INIT_PTHREAD_ATTR_GET_SCHED \ + COMMON_INTERCEPT_FUNCTION(pthread_attr_getschedparam); \ + COMMON_INTERCEPT_FUNCTION(pthread_attr_getschedpolicy); +#else +#define INIT_PTHREAD_ATTR_GET_SCHED +#endif + +#if SANITIZER_INTERCEPT_PTHREAD_ATTR_GETINHERITSCHED +INTERCEPTOR_PTHREAD_ATTR_GET(inheritsched, sizeof(int)) + +#define INIT_PTHREAD_ATTR_GETINHERITSCHED \ + COMMON_INTERCEPT_FUNCTION(pthread_attr_getinheritsched); +#else +#define INIT_PTHREAD_ATTR_GETINHERITSCHED +#endif + +#if SANITIZER_INTERCEPT_PTHREAD_ATTR_GETAFFINITY_NP +INTERCEPTOR(int, pthread_attr_getaffinity_np, void *attr, SIZE_T cpusetsize, + void *cpuset) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, pthread_attr_getaffinity_np, attr, cpusetsize, + cpuset); + // FIXME: under ASan the call below may write to freed memory and corrupt + // its metadata. See + // https://github.com/google/sanitizers/issues/321. + int res = REAL(pthread_attr_getaffinity_np)(attr, cpusetsize, cpuset); + if (!res && cpusetsize && cpuset) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, cpuset, cpusetsize); + return res; +} + +#define INIT_PTHREAD_ATTR_GETAFFINITY_NP \ + COMMON_INTERCEPT_FUNCTION(pthread_attr_getaffinity_np); +#else +#define INIT_PTHREAD_ATTR_GETAFFINITY_NP +#endif + +#if SANITIZER_INTERCEPT_PTHREAD_MUTEXATTR_GETPSHARED +INTERCEPTOR_PTHREAD_MUTEXATTR_GET(pshared, sizeof(int)) +#define INIT_PTHREAD_MUTEXATTR_GETPSHARED \ + COMMON_INTERCEPT_FUNCTION(pthread_mutexattr_getpshared); +#else +#define INIT_PTHREAD_MUTEXATTR_GETPSHARED +#endif + +#if SANITIZER_INTERCEPT_PTHREAD_MUTEXATTR_GETTYPE +INTERCEPTOR_PTHREAD_MUTEXATTR_GET(type, sizeof(int)) +#define INIT_PTHREAD_MUTEXATTR_GETTYPE \ + COMMON_INTERCEPT_FUNCTION(pthread_mutexattr_gettype); +#else +#define INIT_PTHREAD_MUTEXATTR_GETTYPE +#endif + +#if SANITIZER_INTERCEPT_PTHREAD_MUTEXATTR_GETPROTOCOL +INTERCEPTOR_PTHREAD_MUTEXATTR_GET(protocol, sizeof(int)) +#define INIT_PTHREAD_MUTEXATTR_GETPROTOCOL \ + COMMON_INTERCEPT_FUNCTION(pthread_mutexattr_getprotocol); +#else +#define INIT_PTHREAD_MUTEXATTR_GETPROTOCOL +#endif + +#if SANITIZER_INTERCEPT_PTHREAD_MUTEXATTR_GETPRIOCEILING +INTERCEPTOR_PTHREAD_MUTEXATTR_GET(prioceiling, sizeof(int)) +#define INIT_PTHREAD_MUTEXATTR_GETPRIOCEILING \ + COMMON_INTERCEPT_FUNCTION(pthread_mutexattr_getprioceiling); +#else +#define INIT_PTHREAD_MUTEXATTR_GETPRIOCEILING +#endif + +#if SANITIZER_INTERCEPT_PTHREAD_MUTEXATTR_GETROBUST +INTERCEPTOR_PTHREAD_MUTEXATTR_GET(robust, sizeof(int)) +#define INIT_PTHREAD_MUTEXATTR_GETROBUST \ + COMMON_INTERCEPT_FUNCTION(pthread_mutexattr_getrobust); +#else +#define INIT_PTHREAD_MUTEXATTR_GETROBUST +#endif + +#if SANITIZER_INTERCEPT_PTHREAD_MUTEXATTR_GETROBUST_NP +INTERCEPTOR_PTHREAD_MUTEXATTR_GET(robust_np, sizeof(int)) +#define INIT_PTHREAD_MUTEXATTR_GETROBUST_NP \ + COMMON_INTERCEPT_FUNCTION(pthread_mutexattr_getrobust_np); +#else +#define INIT_PTHREAD_MUTEXATTR_GETROBUST_NP +#endif + +#if SANITIZER_INTERCEPT_PTHREAD_RWLOCKATTR_GETPSHARED +INTERCEPTOR_PTHREAD_RWLOCKATTR_GET(pshared, sizeof(int)) +#define INIT_PTHREAD_RWLOCKATTR_GETPSHARED \ + COMMON_INTERCEPT_FUNCTION(pthread_rwlockattr_getpshared); +#else +#define INIT_PTHREAD_RWLOCKATTR_GETPSHARED +#endif + +#if SANITIZER_INTERCEPT_PTHREAD_RWLOCKATTR_GETKIND_NP +INTERCEPTOR_PTHREAD_RWLOCKATTR_GET(kind_np, sizeof(int)) +#define INIT_PTHREAD_RWLOCKATTR_GETKIND_NP \ + COMMON_INTERCEPT_FUNCTION(pthread_rwlockattr_getkind_np); +#else +#define INIT_PTHREAD_RWLOCKATTR_GETKIND_NP +#endif + +#if SANITIZER_INTERCEPT_PTHREAD_CONDATTR_GETPSHARED +INTERCEPTOR_PTHREAD_CONDATTR_GET(pshared, sizeof(int)) +#define INIT_PTHREAD_CONDATTR_GETPSHARED \ + COMMON_INTERCEPT_FUNCTION(pthread_condattr_getpshared); +#else +#define INIT_PTHREAD_CONDATTR_GETPSHARED +#endif + +#if SANITIZER_INTERCEPT_PTHREAD_CONDATTR_GETCLOCK +INTERCEPTOR_PTHREAD_CONDATTR_GET(clock, sizeof(int)) +#define INIT_PTHREAD_CONDATTR_GETCLOCK \ + COMMON_INTERCEPT_FUNCTION(pthread_condattr_getclock); +#else +#define INIT_PTHREAD_CONDATTR_GETCLOCK +#endif + +#if SANITIZER_INTERCEPT_PTHREAD_BARRIERATTR_GETPSHARED +INTERCEPTOR_PTHREAD_BARRIERATTR_GET(pshared, sizeof(int)) // !mac !android +#define INIT_PTHREAD_BARRIERATTR_GETPSHARED \ + COMMON_INTERCEPT_FUNCTION(pthread_barrierattr_getpshared); +#else +#define INIT_PTHREAD_BARRIERATTR_GETPSHARED +#endif + +#if SANITIZER_INTERCEPT_TMPNAM +INTERCEPTOR(char *, tmpnam, char *s) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, tmpnam, s); + char *res = REAL(tmpnam)(s); + if (res) { + if (s) + // FIXME: under ASan the call below may write to freed memory and corrupt + // its metadata. See + // https://github.com/google/sanitizers/issues/321. + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, s, internal_strlen(s) + 1); + else + COMMON_INTERCEPTOR_INITIALIZE_RANGE(res, internal_strlen(res) + 1); + } + return res; +} +#define INIT_TMPNAM COMMON_INTERCEPT_FUNCTION(tmpnam); +#else +#define INIT_TMPNAM +#endif + +#if SANITIZER_INTERCEPT_TMPNAM_R +INTERCEPTOR(char *, tmpnam_r, char *s) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, tmpnam_r, s); + // FIXME: under ASan the call below may write to freed memory and corrupt + // its metadata. See + // https://github.com/google/sanitizers/issues/321. + char *res = REAL(tmpnam_r)(s); + if (res && s) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, s, internal_strlen(s) + 1); + return res; +} +#define INIT_TMPNAM_R COMMON_INTERCEPT_FUNCTION(tmpnam_r); +#else +#define INIT_TMPNAM_R +#endif + +#if SANITIZER_INTERCEPT_PTSNAME +INTERCEPTOR(char *, ptsname, int fd) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, ptsname, fd); + char *res = REAL(ptsname)(fd); + if (res != nullptr) + COMMON_INTERCEPTOR_INITIALIZE_RANGE(res, internal_strlen(res) + 1); + return res; +} +#define INIT_PTSNAME COMMON_INTERCEPT_FUNCTION(ptsname); +#else +#define INIT_PTSNAME +#endif + +#if SANITIZER_INTERCEPT_PTSNAME_R +INTERCEPTOR(int, ptsname_r, int fd, char *name, SIZE_T namesize) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, ptsname_r, fd, name, namesize); + int res = REAL(ptsname_r)(fd, name, namesize); + if (res == 0) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, name, internal_strlen(name) + 1); + return res; +} +#define INIT_PTSNAME_R COMMON_INTERCEPT_FUNCTION(ptsname_r); +#else +#define INIT_PTSNAME_R +#endif + +#if SANITIZER_INTERCEPT_TTYNAME +INTERCEPTOR(char *, ttyname, int fd) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, ttyname, fd); + char *res = REAL(ttyname)(fd); + if (res != nullptr) + COMMON_INTERCEPTOR_INITIALIZE_RANGE(res, internal_strlen(res) + 1); + return res; +} +#define INIT_TTYNAME COMMON_INTERCEPT_FUNCTION(ttyname); +#else +#define INIT_TTYNAME +#endif + +#if SANITIZER_INTERCEPT_TTYNAME_R +INTERCEPTOR(int, ttyname_r, int fd, char *name, SIZE_T namesize) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, ttyname_r, fd, name, namesize); + int res = REAL(ttyname_r)(fd, name, namesize); + if (res == 0) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, name, internal_strlen(name) + 1); + return res; +} +#define INIT_TTYNAME_R COMMON_INTERCEPT_FUNCTION(ttyname_r); +#else +#define INIT_TTYNAME_R +#endif + +#if SANITIZER_INTERCEPT_TEMPNAM +INTERCEPTOR(char *, tempnam, char *dir, char *pfx) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, tempnam, dir, pfx); + if (dir) COMMON_INTERCEPTOR_READ_RANGE(ctx, dir, internal_strlen(dir) + 1); + if (pfx) COMMON_INTERCEPTOR_READ_RANGE(ctx, pfx, internal_strlen(pfx) + 1); + char *res = REAL(tempnam)(dir, pfx); + if (res) COMMON_INTERCEPTOR_INITIALIZE_RANGE(res, internal_strlen(res) + 1); + return res; +} +#define INIT_TEMPNAM COMMON_INTERCEPT_FUNCTION(tempnam); +#else +#define INIT_TEMPNAM +#endif + +#if SANITIZER_INTERCEPT_PTHREAD_SETNAME_NP && !SANITIZER_NETBSD +INTERCEPTOR(int, pthread_setname_np, uptr thread, const char *name) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, pthread_setname_np, thread, name); + COMMON_INTERCEPTOR_READ_STRING(ctx, name, 0); + COMMON_INTERCEPTOR_SET_PTHREAD_NAME(ctx, thread, name); + return REAL(pthread_setname_np)(thread, name); +} +#define INIT_PTHREAD_SETNAME_NP COMMON_INTERCEPT_FUNCTION(pthread_setname_np); +#elif SANITIZER_INTERCEPT_PTHREAD_SETNAME_NP && SANITIZER_NETBSD +INTERCEPTOR(int, pthread_setname_np, uptr thread, const char *name, void *arg) { + void *ctx; + char newname[32]; // PTHREAD_MAX_NAMELEN_NP=32 + COMMON_INTERCEPTOR_ENTER(ctx, pthread_setname_np, thread, name, arg); + COMMON_INTERCEPTOR_READ_STRING(ctx, name, 0); + internal_snprintf(newname, sizeof(newname), name, arg); + COMMON_INTERCEPTOR_SET_PTHREAD_NAME(ctx, thread, newname); + return REAL(pthread_setname_np)(thread, name, arg); +} +#define INIT_PTHREAD_SETNAME_NP COMMON_INTERCEPT_FUNCTION(pthread_setname_np); +#else +#define INIT_PTHREAD_SETNAME_NP +#endif + +#if SANITIZER_INTERCEPT_PTHREAD_GETNAME_NP +INTERCEPTOR(int, pthread_getname_np, uptr thread, char *name, SIZE_T len) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, pthread_getname_np, thread, name, len); + int res = REAL(pthread_getname_np)(thread, name, len); + if (!res) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, name, internal_strnlen(name, len) + 1); + return res; +} +#define INIT_PTHREAD_GETNAME_NP COMMON_INTERCEPT_FUNCTION(pthread_getname_np); +#else +#define INIT_PTHREAD_GETNAME_NP +#endif + +#if SANITIZER_INTERCEPT_SINCOS +INTERCEPTOR(void, sincos, double x, double *sin, double *cos) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, sincos, x, sin, cos); + // FIXME: under ASan the call below may write to freed memory and corrupt + // its metadata. See + // https://github.com/google/sanitizers/issues/321. + REAL(sincos)(x, sin, cos); + if (sin) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, sin, sizeof(*sin)); + if (cos) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, cos, sizeof(*cos)); +} +INTERCEPTOR(void, sincosf, float x, float *sin, float *cos) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, sincosf, x, sin, cos); + // FIXME: under ASan the call below may write to freed memory and corrupt + // its metadata. See + // https://github.com/google/sanitizers/issues/321. + REAL(sincosf)(x, sin, cos); + if (sin) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, sin, sizeof(*sin)); + if (cos) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, cos, sizeof(*cos)); +} +INTERCEPTOR(void, sincosl, long double x, long double *sin, long double *cos) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, sincosl, x, sin, cos); + // FIXME: under ASan the call below may write to freed memory and corrupt + // its metadata. See + // https://github.com/google/sanitizers/issues/321. + REAL(sincosl)(x, sin, cos); + if (sin) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, sin, sizeof(*sin)); + if (cos) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, cos, sizeof(*cos)); +} +#define INIT_SINCOS \ + COMMON_INTERCEPT_FUNCTION(sincos); \ + COMMON_INTERCEPT_FUNCTION(sincosf); \ + COMMON_INTERCEPT_FUNCTION_LDBL(sincosl); +#else +#define INIT_SINCOS +#endif + +#if SANITIZER_INTERCEPT_REMQUO +INTERCEPTOR(double, remquo, double x, double y, int *quo) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, remquo, x, y, quo); + // FIXME: under ASan the call below may write to freed memory and corrupt + // its metadata. See + // https://github.com/google/sanitizers/issues/321. + double res = REAL(remquo)(x, y, quo); + if (quo) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, quo, sizeof(*quo)); + return res; +} +INTERCEPTOR(float, remquof, float x, float y, int *quo) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, remquof, x, y, quo); + // FIXME: under ASan the call below may write to freed memory and corrupt + // its metadata. See + // https://github.com/google/sanitizers/issues/321. + float res = REAL(remquof)(x, y, quo); + if (quo) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, quo, sizeof(*quo)); + return res; +} +#define INIT_REMQUO \ + COMMON_INTERCEPT_FUNCTION(remquo); \ + COMMON_INTERCEPT_FUNCTION(remquof); +#else +#define INIT_REMQUO +#endif + +#if SANITIZER_INTERCEPT_REMQUOL +INTERCEPTOR(long double, remquol, long double x, long double y, int *quo) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, remquol, x, y, quo); + // FIXME: under ASan the call below may write to freed memory and corrupt + // its metadata. See + // https://github.com/google/sanitizers/issues/321. + long double res = REAL(remquol)(x, y, quo); + if (quo) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, quo, sizeof(*quo)); + return res; +} +#define INIT_REMQUOL \ + COMMON_INTERCEPT_FUNCTION_LDBL(remquol); +#else +#define INIT_REMQUOL +#endif + +#if SANITIZER_INTERCEPT_LGAMMA +extern int signgam; +INTERCEPTOR(double, lgamma, double x) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, lgamma, x); + double res = REAL(lgamma)(x); + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, &signgam, sizeof(signgam)); + return res; +} +INTERCEPTOR(float, lgammaf, float x) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, lgammaf, x); + float res = REAL(lgammaf)(x); + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, &signgam, sizeof(signgam)); + return res; +} +#define INIT_LGAMMA \ + COMMON_INTERCEPT_FUNCTION(lgamma); \ + COMMON_INTERCEPT_FUNCTION(lgammaf); +#else +#define INIT_LGAMMA +#endif + +#if SANITIZER_INTERCEPT_LGAMMAL +INTERCEPTOR(long double, lgammal, long double x) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, lgammal, x); + long double res = REAL(lgammal)(x); + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, &signgam, sizeof(signgam)); + return res; +} +#define INIT_LGAMMAL \ + COMMON_INTERCEPT_FUNCTION_LDBL(lgammal); +#else +#define INIT_LGAMMAL +#endif + +#if SANITIZER_INTERCEPT_LGAMMA_R +INTERCEPTOR(double, lgamma_r, double x, int *signp) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, lgamma_r, x, signp); + // FIXME: under ASan the call below may write to freed memory and corrupt + // its metadata. See + // https://github.com/google/sanitizers/issues/321. + double res = REAL(lgamma_r)(x, signp); + if (signp) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, signp, sizeof(*signp)); + return res; +} +INTERCEPTOR(float, lgammaf_r, float x, int *signp) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, lgammaf_r, x, signp); + // FIXME: under ASan the call below may write to freed memory and corrupt + // its metadata. See + // https://github.com/google/sanitizers/issues/321. + float res = REAL(lgammaf_r)(x, signp); + if (signp) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, signp, sizeof(*signp)); + return res; +} +#define INIT_LGAMMA_R \ + COMMON_INTERCEPT_FUNCTION(lgamma_r); \ + COMMON_INTERCEPT_FUNCTION(lgammaf_r); +#else +#define INIT_LGAMMA_R +#endif + +#if SANITIZER_INTERCEPT_LGAMMAL_R +INTERCEPTOR(long double, lgammal_r, long double x, int *signp) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, lgammal_r, x, signp); + // FIXME: under ASan the call below may write to freed memory and corrupt + // its metadata. See + // https://github.com/google/sanitizers/issues/321. + long double res = REAL(lgammal_r)(x, signp); + if (signp) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, signp, sizeof(*signp)); + return res; +} +#define INIT_LGAMMAL_R COMMON_INTERCEPT_FUNCTION_LDBL(lgammal_r); +#else +#define INIT_LGAMMAL_R +#endif + +#if SANITIZER_INTERCEPT_DRAND48_R +INTERCEPTOR(int, drand48_r, void *buffer, double *result) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, drand48_r, buffer, result); + // FIXME: under ASan the call below may write to freed memory and corrupt + // its metadata. See + // https://github.com/google/sanitizers/issues/321. + int res = REAL(drand48_r)(buffer, result); + if (result) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, result, sizeof(*result)); + return res; +} +INTERCEPTOR(int, lrand48_r, void *buffer, long *result) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, lrand48_r, buffer, result); + // FIXME: under ASan the call below may write to freed memory and corrupt + // its metadata. See + // https://github.com/google/sanitizers/issues/321. + int res = REAL(lrand48_r)(buffer, result); + if (result) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, result, sizeof(*result)); + return res; +} +#define INIT_DRAND48_R \ + COMMON_INTERCEPT_FUNCTION(drand48_r); \ + COMMON_INTERCEPT_FUNCTION(lrand48_r); +#else +#define INIT_DRAND48_R +#endif + +#if SANITIZER_INTERCEPT_RAND_R +INTERCEPTOR(int, rand_r, unsigned *seedp) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, rand_r, seedp); + COMMON_INTERCEPTOR_READ_RANGE(ctx, seedp, sizeof(*seedp)); + return REAL(rand_r)(seedp); +} +#define INIT_RAND_R COMMON_INTERCEPT_FUNCTION(rand_r); +#else +#define INIT_RAND_R +#endif + +#if SANITIZER_INTERCEPT_GETLINE +INTERCEPTOR(SSIZE_T, getline, char **lineptr, SIZE_T *n, void *stream) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, getline, lineptr, n, stream); + // FIXME: under ASan the call below may write to freed memory and corrupt + // its metadata. See + // https://github.com/google/sanitizers/issues/321. + SSIZE_T res = REAL(getline)(lineptr, n, stream); + if (res > 0) { + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, lineptr, sizeof(*lineptr)); + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, n, sizeof(*n)); + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, *lineptr, res + 1); + } + return res; +} + +// FIXME: under ASan the call below may write to freed memory and corrupt its +// metadata. See +// https://github.com/google/sanitizers/issues/321. +#define GETDELIM_INTERCEPTOR_IMPL(vname) \ + { \ + void *ctx; \ + COMMON_INTERCEPTOR_ENTER(ctx, vname, lineptr, n, delim, stream); \ + SSIZE_T res = REAL(vname)(lineptr, n, delim, stream); \ + if (res > 0) { \ + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, lineptr, sizeof(*lineptr)); \ + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, n, sizeof(*n)); \ + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, *lineptr, res + 1); \ + } \ + return res; \ + } + +INTERCEPTOR(SSIZE_T, __getdelim, char **lineptr, SIZE_T *n, int delim, + void *stream) +GETDELIM_INTERCEPTOR_IMPL(__getdelim) + +// There's no __getdelim() on FreeBSD so we supply the getdelim() interceptor +// with its own body. +INTERCEPTOR(SSIZE_T, getdelim, char **lineptr, SIZE_T *n, int delim, + void *stream) +GETDELIM_INTERCEPTOR_IMPL(getdelim) + +#define INIT_GETLINE \ + COMMON_INTERCEPT_FUNCTION(getline); \ + COMMON_INTERCEPT_FUNCTION(__getdelim); \ + COMMON_INTERCEPT_FUNCTION(getdelim); +#else +#define INIT_GETLINE +#endif + +#if SANITIZER_INTERCEPT_ICONV +INTERCEPTOR(SIZE_T, iconv, void *cd, char **inbuf, SIZE_T *inbytesleft, + char **outbuf, SIZE_T *outbytesleft) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, iconv, cd, inbuf, inbytesleft, outbuf, + outbytesleft); + if (inbytesleft) + COMMON_INTERCEPTOR_READ_RANGE(ctx, inbytesleft, sizeof(*inbytesleft)); + if (inbuf && inbytesleft) + COMMON_INTERCEPTOR_READ_RANGE(ctx, *inbuf, *inbytesleft); + if (outbytesleft) + COMMON_INTERCEPTOR_READ_RANGE(ctx, outbytesleft, sizeof(*outbytesleft)); + void *outbuf_orig = outbuf ? *outbuf : nullptr; + // FIXME: under ASan the call below may write to freed memory and corrupt + // its metadata. See + // https://github.com/google/sanitizers/issues/321. + SIZE_T res = REAL(iconv)(cd, inbuf, inbytesleft, outbuf, outbytesleft); + if (outbuf && *outbuf > outbuf_orig) { + SIZE_T sz = (char *)*outbuf - (char *)outbuf_orig; + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, outbuf_orig, sz); + } + return res; +} +#define INIT_ICONV COMMON_INTERCEPT_FUNCTION(iconv); +#else +#define INIT_ICONV +#endif + +#if SANITIZER_INTERCEPT_TIMES +INTERCEPTOR(__sanitizer_clock_t, times, void *tms) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, times, tms); + // FIXME: under ASan the call below may write to freed memory and corrupt + // its metadata. See + // https://github.com/google/sanitizers/issues/321. + __sanitizer_clock_t res = REAL(times)(tms); + if (res != (__sanitizer_clock_t)-1 && tms) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, tms, struct_tms_sz); + return res; +} +#define INIT_TIMES COMMON_INTERCEPT_FUNCTION(times); +#else +#define INIT_TIMES +#endif + +#if SANITIZER_S390 && \ + (SANITIZER_INTERCEPT_TLS_GET_ADDR || SANITIZER_INTERCEPT_TLS_GET_OFFSET) +extern "C" uptr __tls_get_offset_wrapper(void *arg, uptr (*fn)(void *arg)); +DEFINE_REAL(uptr, __tls_get_offset, void *arg) +#endif + +#if SANITIZER_INTERCEPT_TLS_GET_ADDR +#if !SANITIZER_S390 +#define INIT_TLS_GET_ADDR COMMON_INTERCEPT_FUNCTION(__tls_get_addr) +// If you see any crashes around this functions, there are 2 known issues with +// it: 1. __tls_get_addr can be called with mis-aligned stack due to: +// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=58066 +// 2. It can be called recursively if sanitizer code uses __tls_get_addr +// to access thread local variables (it should not happen normally, +// because sanitizers use initial-exec tls model). +INTERCEPTOR(void *, __tls_get_addr, void *arg) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, __tls_get_addr, arg); + void *res = REAL(__tls_get_addr)(arg); + uptr tls_begin, tls_end; + COMMON_INTERCEPTOR_GET_TLS_RANGE(&tls_begin, &tls_end); + DTLS::DTV *dtv = DTLS_on_tls_get_addr(arg, res, tls_begin, tls_end); + if (dtv) { + // New DTLS block has been allocated. + COMMON_INTERCEPTOR_INITIALIZE_RANGE((void *)dtv->beg, dtv->size); + } + return res; +} +#if SANITIZER_PPC +// On PowerPC, we also need to intercept __tls_get_addr_opt, which has +// mostly the same semantics as __tls_get_addr, but its presence enables +// some optimizations in linker (which are safe to ignore here). +extern "C" __attribute__((alias("__interceptor___tls_get_addr"), + visibility("default"))) +void *__tls_get_addr_opt(void *arg); +#endif +#else // SANITIZER_S390 +// On s390, we have to intercept two functions here: +// - __tls_get_addr_internal, which is a glibc-internal function that is like +// the usual __tls_get_addr, but returns a TP-relative offset instead of +// a proper pointer. It is used by dlsym for TLS symbols. +// - __tls_get_offset, which is like the above, but also takes a GOT-relative +// descriptor offset as an argument instead of a pointer. GOT address +// is passed in r12, so it's necessary to write it in assembly. This is +// the function used by the compiler. +#define INIT_TLS_GET_ADDR COMMON_INTERCEPT_FUNCTION(__tls_get_offset) +INTERCEPTOR(uptr, __tls_get_addr_internal, void *arg) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, __tls_get_addr_internal, arg); + uptr res = __tls_get_offset_wrapper(arg, REAL(__tls_get_offset)); + uptr tp = reinterpret_cast<uptr>(__builtin_thread_pointer()); + void *ptr = reinterpret_cast<void *>(res + tp); + uptr tls_begin, tls_end; + COMMON_INTERCEPTOR_GET_TLS_RANGE(&tls_begin, &tls_end); + DTLS::DTV *dtv = DTLS_on_tls_get_addr(arg, ptr, tls_begin, tls_end); + if (dtv) { + // New DTLS block has been allocated. + COMMON_INTERCEPTOR_INITIALIZE_RANGE((void *)dtv->beg, dtv->size); + } + return res; +} +#endif // SANITIZER_S390 +#else +#define INIT_TLS_GET_ADDR +#endif + +#if SANITIZER_S390 && \ + (SANITIZER_INTERCEPT_TLS_GET_ADDR || SANITIZER_INTERCEPT_TLS_GET_OFFSET) +extern "C" uptr __tls_get_offset(void *arg); +extern "C" uptr __interceptor___tls_get_offset(void *arg); +// We need a hidden symbol aliasing the above, so that we can jump +// directly to it from the assembly below. +extern "C" __attribute__((alias("__interceptor___tls_get_addr_internal"), + visibility("hidden"))) +uptr __tls_get_addr_hidden(void *arg); +// Now carefully intercept __tls_get_offset. +asm( + ".text\n" +// The __intercept_ version has to exist, so that gen_dynamic_list.py +// exports our symbol. + ".weak __tls_get_offset\n" + ".type __tls_get_offset, @function\n" + "__tls_get_offset:\n" + ".global __interceptor___tls_get_offset\n" + ".type __interceptor___tls_get_offset, @function\n" + "__interceptor___tls_get_offset:\n" +#ifdef __s390x__ + "la %r2, 0(%r2,%r12)\n" + "jg __tls_get_addr_hidden\n" +#else + "basr %r3,0\n" + "0: la %r2,0(%r2,%r12)\n" + "l %r4,1f-0b(%r3)\n" + "b 0(%r4,%r3)\n" + "1: .long __tls_get_addr_hidden - 0b\n" +#endif + ".size __interceptor___tls_get_offset, .-__interceptor___tls_get_offset\n" +// Assembly wrapper to call REAL(__tls_get_offset)(arg) + ".type __tls_get_offset_wrapper, @function\n" + "__tls_get_offset_wrapper:\n" +#ifdef __s390x__ + "sgr %r2,%r12\n" +#else + "sr %r2,%r12\n" +#endif + "br %r3\n" + ".size __tls_get_offset_wrapper, .-__tls_get_offset_wrapper\n" +); +#endif + +#if SANITIZER_INTERCEPT_LISTXATTR +INTERCEPTOR(SSIZE_T, listxattr, const char *path, char *list, SIZE_T size) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, listxattr, path, list, size); + if (path) COMMON_INTERCEPTOR_READ_RANGE(ctx, path, internal_strlen(path) + 1); + // FIXME: under ASan the call below may write to freed memory and corrupt + // its metadata. See + // https://github.com/google/sanitizers/issues/321. + SSIZE_T res = REAL(listxattr)(path, list, size); + // Here and below, size == 0 is a special case where nothing is written to the + // buffer, and res contains the desired buffer size. + if (size && res > 0 && list) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, list, res); + return res; +} +INTERCEPTOR(SSIZE_T, llistxattr, const char *path, char *list, SIZE_T size) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, llistxattr, path, list, size); + if (path) COMMON_INTERCEPTOR_READ_RANGE(ctx, path, internal_strlen(path) + 1); + // FIXME: under ASan the call below may write to freed memory and corrupt + // its metadata. See + // https://github.com/google/sanitizers/issues/321. + SSIZE_T res = REAL(llistxattr)(path, list, size); + if (size && res > 0 && list) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, list, res); + return res; +} +INTERCEPTOR(SSIZE_T, flistxattr, int fd, char *list, SIZE_T size) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, flistxattr, fd, list, size); + // FIXME: under ASan the call below may write to freed memory and corrupt + // its metadata. See + // https://github.com/google/sanitizers/issues/321. + SSIZE_T res = REAL(flistxattr)(fd, list, size); + if (size && res > 0 && list) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, list, res); + return res; +} +#define INIT_LISTXATTR \ + COMMON_INTERCEPT_FUNCTION(listxattr); \ + COMMON_INTERCEPT_FUNCTION(llistxattr); \ + COMMON_INTERCEPT_FUNCTION(flistxattr); +#else +#define INIT_LISTXATTR +#endif + +#if SANITIZER_INTERCEPT_GETXATTR +INTERCEPTOR(SSIZE_T, getxattr, const char *path, const char *name, char *value, + SIZE_T size) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, getxattr, path, name, value, size); + if (path) COMMON_INTERCEPTOR_READ_RANGE(ctx, path, internal_strlen(path) + 1); + if (name) COMMON_INTERCEPTOR_READ_RANGE(ctx, name, internal_strlen(name) + 1); + // FIXME: under ASan the call below may write to freed memory and corrupt + // its metadata. See + // https://github.com/google/sanitizers/issues/321. + SSIZE_T res = REAL(getxattr)(path, name, value, size); + if (size && res > 0 && value) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, value, res); + return res; +} +INTERCEPTOR(SSIZE_T, lgetxattr, const char *path, const char *name, char *value, + SIZE_T size) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, lgetxattr, path, name, value, size); + if (path) COMMON_INTERCEPTOR_READ_RANGE(ctx, path, internal_strlen(path) + 1); + if (name) COMMON_INTERCEPTOR_READ_RANGE(ctx, name, internal_strlen(name) + 1); + // FIXME: under ASan the call below may write to freed memory and corrupt + // its metadata. See + // https://github.com/google/sanitizers/issues/321. + SSIZE_T res = REAL(lgetxattr)(path, name, value, size); + if (size && res > 0 && value) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, value, res); + return res; +} +INTERCEPTOR(SSIZE_T, fgetxattr, int fd, const char *name, char *value, + SIZE_T size) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, fgetxattr, fd, name, value, size); + if (name) COMMON_INTERCEPTOR_READ_RANGE(ctx, name, internal_strlen(name) + 1); + // FIXME: under ASan the call below may write to freed memory and corrupt + // its metadata. See + // https://github.com/google/sanitizers/issues/321. + SSIZE_T res = REAL(fgetxattr)(fd, name, value, size); + if (size && res > 0 && value) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, value, res); + return res; +} +#define INIT_GETXATTR \ + COMMON_INTERCEPT_FUNCTION(getxattr); \ + COMMON_INTERCEPT_FUNCTION(lgetxattr); \ + COMMON_INTERCEPT_FUNCTION(fgetxattr); +#else +#define INIT_GETXATTR +#endif + +#if SANITIZER_INTERCEPT_GETRESID +INTERCEPTOR(int, getresuid, void *ruid, void *euid, void *suid) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, getresuid, ruid, euid, suid); + // FIXME: under ASan the call below may write to freed memory and corrupt + // its metadata. See + // https://github.com/google/sanitizers/issues/321. + int res = REAL(getresuid)(ruid, euid, suid); + if (res >= 0) { + if (ruid) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ruid, uid_t_sz); + if (euid) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, euid, uid_t_sz); + if (suid) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, suid, uid_t_sz); + } + return res; +} +INTERCEPTOR(int, getresgid, void *rgid, void *egid, void *sgid) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, getresgid, rgid, egid, sgid); + // FIXME: under ASan the call below may write to freed memory and corrupt + // its metadata. See + // https://github.com/google/sanitizers/issues/321. + int res = REAL(getresgid)(rgid, egid, sgid); + if (res >= 0) { + if (rgid) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, rgid, gid_t_sz); + if (egid) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, egid, gid_t_sz); + if (sgid) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, sgid, gid_t_sz); + } + return res; +} +#define INIT_GETRESID \ + COMMON_INTERCEPT_FUNCTION(getresuid); \ + COMMON_INTERCEPT_FUNCTION(getresgid); +#else +#define INIT_GETRESID +#endif + +#if SANITIZER_INTERCEPT_GETIFADDRS +// As long as getifaddrs()/freeifaddrs() use calloc()/free(), we don't need to +// intercept freeifaddrs(). If that ceases to be the case, we might need to +// intercept it to poison the memory again. +INTERCEPTOR(int, getifaddrs, __sanitizer_ifaddrs **ifap) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, getifaddrs, ifap); + // FIXME: under ASan the call below may write to freed memory and corrupt + // its metadata. See + // https://github.com/google/sanitizers/issues/321. + int res = REAL(getifaddrs)(ifap); + if (res == 0 && ifap) { + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ifap, sizeof(void *)); + __sanitizer_ifaddrs *p = *ifap; + while (p) { + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, p, sizeof(__sanitizer_ifaddrs)); + if (p->ifa_name) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, p->ifa_name, + internal_strlen(p->ifa_name) + 1); + if (p->ifa_addr) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, p->ifa_addr, struct_sockaddr_sz); + if (p->ifa_netmask) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, p->ifa_netmask, struct_sockaddr_sz); + // On Linux this is a union, but the other member also points to a + // struct sockaddr, so the following is sufficient. + if (p->ifa_dstaddr) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, p->ifa_dstaddr, struct_sockaddr_sz); + // FIXME(smatveev): Unpoison p->ifa_data as well. + p = p->ifa_next; + } + } + return res; +} +#define INIT_GETIFADDRS \ + COMMON_INTERCEPT_FUNCTION(getifaddrs); +#else +#define INIT_GETIFADDRS +#endif + +#if SANITIZER_INTERCEPT_IF_INDEXTONAME +INTERCEPTOR(char *, if_indextoname, unsigned int ifindex, char* ifname) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, if_indextoname, ifindex, ifname); + // FIXME: under ASan the call below may write to freed memory and corrupt + // its metadata. See + // https://github.com/google/sanitizers/issues/321. + char *res = REAL(if_indextoname)(ifindex, ifname); + if (res && ifname) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ifname, internal_strlen(ifname) + 1); + return res; +} +INTERCEPTOR(unsigned int, if_nametoindex, const char* ifname) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, if_nametoindex, ifname); + if (ifname) + COMMON_INTERCEPTOR_READ_RANGE(ctx, ifname, internal_strlen(ifname) + 1); + return REAL(if_nametoindex)(ifname); +} +#define INIT_IF_INDEXTONAME \ + COMMON_INTERCEPT_FUNCTION(if_indextoname); \ + COMMON_INTERCEPT_FUNCTION(if_nametoindex); +#else +#define INIT_IF_INDEXTONAME +#endif + +#if SANITIZER_INTERCEPT_CAPGET +INTERCEPTOR(int, capget, void *hdrp, void *datap) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, capget, hdrp, datap); + if (hdrp) + COMMON_INTERCEPTOR_READ_RANGE(ctx, hdrp, __user_cap_header_struct_sz); + // FIXME: under ASan the call below may write to freed memory and corrupt + // its metadata. See + // https://github.com/google/sanitizers/issues/321. + int res = REAL(capget)(hdrp, datap); + if (res == 0 && datap) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, datap, __user_cap_data_struct_sz); + // We can also return -1 and write to hdrp->version if the version passed in + // hdrp->version is unsupported. But that's not a trivial condition to check, + // and anyway COMMON_INTERCEPTOR_READ_RANGE protects us to some extent. + return res; +} +INTERCEPTOR(int, capset, void *hdrp, const void *datap) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, capset, hdrp, datap); + if (hdrp) + COMMON_INTERCEPTOR_READ_RANGE(ctx, hdrp, __user_cap_header_struct_sz); + if (datap) + COMMON_INTERCEPTOR_READ_RANGE(ctx, datap, __user_cap_data_struct_sz); + return REAL(capset)(hdrp, datap); +} +#define INIT_CAPGET \ + COMMON_INTERCEPT_FUNCTION(capget); \ + COMMON_INTERCEPT_FUNCTION(capset); +#else +#define INIT_CAPGET +#endif + +#if SANITIZER_INTERCEPT_AEABI_MEM +INTERCEPTOR(void *, __aeabi_memmove, void *to, const void *from, uptr size) { + void *ctx; + COMMON_INTERCEPTOR_MEMMOVE_IMPL(ctx, to, from, size); +} + +INTERCEPTOR(void *, __aeabi_memmove4, void *to, const void *from, uptr size) { + void *ctx; + COMMON_INTERCEPTOR_MEMMOVE_IMPL(ctx, to, from, size); +} + +INTERCEPTOR(void *, __aeabi_memmove8, void *to, const void *from, uptr size) { + void *ctx; + COMMON_INTERCEPTOR_MEMMOVE_IMPL(ctx, to, from, size); +} + +INTERCEPTOR(void *, __aeabi_memcpy, void *to, const void *from, uptr size) { + void *ctx; + COMMON_INTERCEPTOR_MEMCPY_IMPL(ctx, to, from, size); +} + +INTERCEPTOR(void *, __aeabi_memcpy4, void *to, const void *from, uptr size) { + void *ctx; + COMMON_INTERCEPTOR_MEMCPY_IMPL(ctx, to, from, size); +} + +INTERCEPTOR(void *, __aeabi_memcpy8, void *to, const void *from, uptr size) { + void *ctx; + COMMON_INTERCEPTOR_MEMCPY_IMPL(ctx, to, from, size); +} + +// Note the argument order. +INTERCEPTOR(void *, __aeabi_memset, void *block, uptr size, int c) { + void *ctx; + COMMON_INTERCEPTOR_MEMSET_IMPL(ctx, block, c, size); +} + +INTERCEPTOR(void *, __aeabi_memset4, void *block, uptr size, int c) { + void *ctx; + COMMON_INTERCEPTOR_MEMSET_IMPL(ctx, block, c, size); +} + +INTERCEPTOR(void *, __aeabi_memset8, void *block, uptr size, int c) { + void *ctx; + COMMON_INTERCEPTOR_MEMSET_IMPL(ctx, block, c, size); +} + +INTERCEPTOR(void *, __aeabi_memclr, void *block, uptr size) { + void *ctx; + COMMON_INTERCEPTOR_MEMSET_IMPL(ctx, block, 0, size); +} + +INTERCEPTOR(void *, __aeabi_memclr4, void *block, uptr size) { + void *ctx; + COMMON_INTERCEPTOR_MEMSET_IMPL(ctx, block, 0, size); +} + +INTERCEPTOR(void *, __aeabi_memclr8, void *block, uptr size) { + void *ctx; + COMMON_INTERCEPTOR_MEMSET_IMPL(ctx, block, 0, size); +} + +#define INIT_AEABI_MEM \ + COMMON_INTERCEPT_FUNCTION(__aeabi_memmove); \ + COMMON_INTERCEPT_FUNCTION(__aeabi_memmove4); \ + COMMON_INTERCEPT_FUNCTION(__aeabi_memmove8); \ + COMMON_INTERCEPT_FUNCTION(__aeabi_memcpy); \ + COMMON_INTERCEPT_FUNCTION(__aeabi_memcpy4); \ + COMMON_INTERCEPT_FUNCTION(__aeabi_memcpy8); \ + COMMON_INTERCEPT_FUNCTION(__aeabi_memset); \ + COMMON_INTERCEPT_FUNCTION(__aeabi_memset4); \ + COMMON_INTERCEPT_FUNCTION(__aeabi_memset8); \ + COMMON_INTERCEPT_FUNCTION(__aeabi_memclr); \ + COMMON_INTERCEPT_FUNCTION(__aeabi_memclr4); \ + COMMON_INTERCEPT_FUNCTION(__aeabi_memclr8); +#else +#define INIT_AEABI_MEM +#endif // SANITIZER_INTERCEPT_AEABI_MEM + +#if SANITIZER_INTERCEPT___BZERO +INTERCEPTOR(void *, __bzero, void *block, uptr size) { + void *ctx; + COMMON_INTERCEPTOR_MEMSET_IMPL(ctx, block, 0, size); +} +#define INIT___BZERO COMMON_INTERCEPT_FUNCTION(__bzero); +#else +#define INIT___BZERO +#endif // SANITIZER_INTERCEPT___BZERO + +#if SANITIZER_INTERCEPT_BZERO +INTERCEPTOR(void *, bzero, void *block, uptr size) { + void *ctx; + COMMON_INTERCEPTOR_MEMSET_IMPL(ctx, block, 0, size); +} +#define INIT_BZERO COMMON_INTERCEPT_FUNCTION(bzero); +#else +#define INIT_BZERO +#endif // SANITIZER_INTERCEPT_BZERO + +#if SANITIZER_INTERCEPT_FTIME +INTERCEPTOR(int, ftime, __sanitizer_timeb *tp) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, ftime, tp); + // FIXME: under ASan the call below may write to freed memory and corrupt + // its metadata. See + // https://github.com/google/sanitizers/issues/321. + int res = REAL(ftime)(tp); + if (tp) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, tp, sizeof(*tp)); + return res; +} +#define INIT_FTIME COMMON_INTERCEPT_FUNCTION(ftime); +#else +#define INIT_FTIME +#endif // SANITIZER_INTERCEPT_FTIME + +#if SANITIZER_INTERCEPT_XDR +INTERCEPTOR(void, xdrmem_create, __sanitizer_XDR *xdrs, uptr addr, + unsigned size, int op) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, xdrmem_create, xdrs, addr, size, op); + // FIXME: under ASan the call below may write to freed memory and corrupt + // its metadata. See + // https://github.com/google/sanitizers/issues/321. + REAL(xdrmem_create)(xdrs, addr, size, op); + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, xdrs, sizeof(*xdrs)); + if (op == __sanitizer_XDR_ENCODE) { + // It's not obvious how much data individual xdr_ routines write. + // Simply unpoison the entire target buffer in advance. + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, (void *)addr, size); + } +} + +INTERCEPTOR(void, xdrstdio_create, __sanitizer_XDR *xdrs, void *file, int op) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, xdrstdio_create, xdrs, file, op); + // FIXME: under ASan the call below may write to freed memory and corrupt + // its metadata. See + // https://github.com/google/sanitizers/issues/321. + REAL(xdrstdio_create)(xdrs, file, op); + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, xdrs, sizeof(*xdrs)); +} + +// FIXME: under ASan the call below may write to freed memory and corrupt +// its metadata. See +// https://github.com/google/sanitizers/issues/321. +#define XDR_INTERCEPTOR(F, T) \ + INTERCEPTOR(int, F, __sanitizer_XDR *xdrs, T *p) { \ + void *ctx; \ + COMMON_INTERCEPTOR_ENTER(ctx, F, xdrs, p); \ + if (p && xdrs->x_op == __sanitizer_XDR_ENCODE) \ + COMMON_INTERCEPTOR_READ_RANGE(ctx, p, sizeof(*p)); \ + int res = REAL(F)(xdrs, p); \ + if (res && p && xdrs->x_op == __sanitizer_XDR_DECODE) \ + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, p, sizeof(*p)); \ + return res; \ + } + +XDR_INTERCEPTOR(xdr_short, short) +XDR_INTERCEPTOR(xdr_u_short, unsigned short) +XDR_INTERCEPTOR(xdr_int, int) +XDR_INTERCEPTOR(xdr_u_int, unsigned) +XDR_INTERCEPTOR(xdr_long, long) +XDR_INTERCEPTOR(xdr_u_long, unsigned long) +XDR_INTERCEPTOR(xdr_hyper, long long) +XDR_INTERCEPTOR(xdr_u_hyper, unsigned long long) +XDR_INTERCEPTOR(xdr_longlong_t, long long) +XDR_INTERCEPTOR(xdr_u_longlong_t, unsigned long long) +XDR_INTERCEPTOR(xdr_int8_t, u8) +XDR_INTERCEPTOR(xdr_uint8_t, u8) +XDR_INTERCEPTOR(xdr_int16_t, u16) +XDR_INTERCEPTOR(xdr_uint16_t, u16) +XDR_INTERCEPTOR(xdr_int32_t, u32) +XDR_INTERCEPTOR(xdr_uint32_t, u32) +XDR_INTERCEPTOR(xdr_int64_t, u64) +XDR_INTERCEPTOR(xdr_uint64_t, u64) +XDR_INTERCEPTOR(xdr_quad_t, long long) +XDR_INTERCEPTOR(xdr_u_quad_t, unsigned long long) +XDR_INTERCEPTOR(xdr_bool, bool) +XDR_INTERCEPTOR(xdr_enum, int) +XDR_INTERCEPTOR(xdr_char, char) +XDR_INTERCEPTOR(xdr_u_char, unsigned char) +XDR_INTERCEPTOR(xdr_float, float) +XDR_INTERCEPTOR(xdr_double, double) + +// FIXME: intercept xdr_array, opaque, union, vector, reference, pointer, +// wrapstring, sizeof + +INTERCEPTOR(int, xdr_bytes, __sanitizer_XDR *xdrs, char **p, unsigned *sizep, + unsigned maxsize) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, xdr_bytes, xdrs, p, sizep, maxsize); + if (p && sizep && xdrs->x_op == __sanitizer_XDR_ENCODE) { + COMMON_INTERCEPTOR_READ_RANGE(ctx, p, sizeof(*p)); + COMMON_INTERCEPTOR_READ_RANGE(ctx, sizep, sizeof(*sizep)); + COMMON_INTERCEPTOR_READ_RANGE(ctx, *p, *sizep); + } + // FIXME: under ASan the call below may write to freed memory and corrupt + // its metadata. See + // https://github.com/google/sanitizers/issues/321. + int res = REAL(xdr_bytes)(xdrs, p, sizep, maxsize); + if (p && sizep && xdrs->x_op == __sanitizer_XDR_DECODE) { + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, p, sizeof(*p)); + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, sizep, sizeof(*sizep)); + if (res && *p && *sizep) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, *p, *sizep); + } + return res; +} + +INTERCEPTOR(int, xdr_string, __sanitizer_XDR *xdrs, char **p, + unsigned maxsize) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, xdr_string, xdrs, p, maxsize); + if (p && xdrs->x_op == __sanitizer_XDR_ENCODE) { + COMMON_INTERCEPTOR_READ_RANGE(ctx, p, sizeof(*p)); + COMMON_INTERCEPTOR_READ_RANGE(ctx, *p, internal_strlen(*p) + 1); + } + // FIXME: under ASan the call below may write to freed memory and corrupt + // its metadata. See + // https://github.com/google/sanitizers/issues/321. + int res = REAL(xdr_string)(xdrs, p, maxsize); + if (p && xdrs->x_op == __sanitizer_XDR_DECODE) { + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, p, sizeof(*p)); + if (res && *p) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, *p, internal_strlen(*p) + 1); + } + return res; +} + +#define INIT_XDR \ + COMMON_INTERCEPT_FUNCTION(xdrmem_create); \ + COMMON_INTERCEPT_FUNCTION(xdrstdio_create); \ + COMMON_INTERCEPT_FUNCTION(xdr_short); \ + COMMON_INTERCEPT_FUNCTION(xdr_u_short); \ + COMMON_INTERCEPT_FUNCTION(xdr_int); \ + COMMON_INTERCEPT_FUNCTION(xdr_u_int); \ + COMMON_INTERCEPT_FUNCTION(xdr_long); \ + COMMON_INTERCEPT_FUNCTION(xdr_u_long); \ + COMMON_INTERCEPT_FUNCTION(xdr_hyper); \ + COMMON_INTERCEPT_FUNCTION(xdr_u_hyper); \ + COMMON_INTERCEPT_FUNCTION(xdr_longlong_t); \ + COMMON_INTERCEPT_FUNCTION(xdr_u_longlong_t); \ + COMMON_INTERCEPT_FUNCTION(xdr_int8_t); \ + COMMON_INTERCEPT_FUNCTION(xdr_uint8_t); \ + COMMON_INTERCEPT_FUNCTION(xdr_int16_t); \ + COMMON_INTERCEPT_FUNCTION(xdr_uint16_t); \ + COMMON_INTERCEPT_FUNCTION(xdr_int32_t); \ + COMMON_INTERCEPT_FUNCTION(xdr_uint32_t); \ + COMMON_INTERCEPT_FUNCTION(xdr_int64_t); \ + COMMON_INTERCEPT_FUNCTION(xdr_uint64_t); \ + COMMON_INTERCEPT_FUNCTION(xdr_quad_t); \ + COMMON_INTERCEPT_FUNCTION(xdr_u_quad_t); \ + COMMON_INTERCEPT_FUNCTION(xdr_bool); \ + COMMON_INTERCEPT_FUNCTION(xdr_enum); \ + COMMON_INTERCEPT_FUNCTION(xdr_char); \ + COMMON_INTERCEPT_FUNCTION(xdr_u_char); \ + COMMON_INTERCEPT_FUNCTION(xdr_float); \ + COMMON_INTERCEPT_FUNCTION(xdr_double); \ + COMMON_INTERCEPT_FUNCTION(xdr_bytes); \ + COMMON_INTERCEPT_FUNCTION(xdr_string); +#else +#define INIT_XDR +#endif // SANITIZER_INTERCEPT_XDR + +#if SANITIZER_INTERCEPT_XDRREC +typedef int (*xdrrec_cb)(char*, char*, int); +struct XdrRecWrapper { + char *handle; + xdrrec_cb rd, wr; +}; +typedef AddrHashMap<XdrRecWrapper *, 11> XdrRecWrapMap; +static XdrRecWrapMap *xdrrec_wrap_map; + +static int xdrrec_wr_wrap(char *handle, char *buf, int count) { + COMMON_INTERCEPTOR_UNPOISON_PARAM(3); + COMMON_INTERCEPTOR_INITIALIZE_RANGE(buf, count); + XdrRecWrapper *wrap = (XdrRecWrapper *)handle; + return wrap->wr(wrap->handle, buf, count); +} + +static int xdrrec_rd_wrap(char *handle, char *buf, int count) { + COMMON_INTERCEPTOR_UNPOISON_PARAM(3); + XdrRecWrapper *wrap = (XdrRecWrapper *)handle; + return wrap->rd(wrap->handle, buf, count); +} + +// This doesn't apply to the solaris version as it has a different function +// signature. +INTERCEPTOR(void, xdrrec_create, __sanitizer_XDR *xdr, unsigned sndsize, + unsigned rcvsize, char *handle, int (*rd)(char*, char*, int), + int (*wr)(char*, char*, int)) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, xdrrec_create, xdr, sndsize, rcvsize, + handle, rd, wr); + COMMON_INTERCEPTOR_READ_RANGE(ctx, &xdr->x_op, sizeof xdr->x_op); + + // We can't allocate a wrapper on the stack, as the handle is used outside + // this stack frame. So we put it on the heap, and keep track of it with + // the HashMap (keyed by x_private). When we later need to xdr_destroy, + // we can index the map, free the wrapper, and then clean the map entry. + XdrRecWrapper *wrap_data = + (XdrRecWrapper *)InternalAlloc(sizeof(XdrRecWrapper)); + wrap_data->handle = handle; + wrap_data->rd = rd; + wrap_data->wr = wr; + if (wr) + wr = xdrrec_wr_wrap; + if (rd) + rd = xdrrec_rd_wrap; + handle = (char *)wrap_data; + + REAL(xdrrec_create)(xdr, sndsize, rcvsize, handle, rd, wr); + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, xdr, sizeof *xdr); + + XdrRecWrapMap::Handle wrap(xdrrec_wrap_map, xdr->x_private, false, true); + *wrap = wrap_data; +} + +// We have to intercept this to be able to free wrapper memory; +// otherwise it's not necessary. +INTERCEPTOR(void, xdr_destroy, __sanitizer_XDR *xdr) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, xdr_destroy, xdr); + + XdrRecWrapMap::Handle wrap(xdrrec_wrap_map, xdr->x_private, true); + InternalFree(*wrap); + REAL(xdr_destroy)(xdr); +} +#define INIT_XDRREC_LINUX \ + static u64 xdrrec_wrap_mem[sizeof(XdrRecWrapMap) / sizeof(u64) + 1]; \ + xdrrec_wrap_map = new ((void *)&xdrrec_wrap_mem) XdrRecWrapMap(); \ + COMMON_INTERCEPT_FUNCTION(xdrrec_create); \ + COMMON_INTERCEPT_FUNCTION(xdr_destroy); +#else +#define INIT_XDRREC_LINUX +#endif + +#if SANITIZER_INTERCEPT_TSEARCH +INTERCEPTOR(void *, tsearch, void *key, void **rootp, + int (*compar)(const void *, const void *)) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, tsearch, key, rootp, compar); + // FIXME: under ASan the call below may write to freed memory and corrupt + // its metadata. See + // https://github.com/google/sanitizers/issues/321. + void *res = REAL(tsearch)(key, rootp, compar); + if (res && *(void **)res == key) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, sizeof(void *)); + return res; +} +#define INIT_TSEARCH COMMON_INTERCEPT_FUNCTION(tsearch); +#else +#define INIT_TSEARCH +#endif + +#if SANITIZER_INTERCEPT_LIBIO_INTERNALS || SANITIZER_INTERCEPT_FOPEN || \ + SANITIZER_INTERCEPT_OPEN_MEMSTREAM +void unpoison_file(__sanitizer_FILE *fp) { +#if SANITIZER_HAS_STRUCT_FILE + COMMON_INTERCEPTOR_INITIALIZE_RANGE(fp, sizeof(*fp)); +#if SANITIZER_NETBSD + if (fp->_bf._base && fp->_bf._size > 0) + COMMON_INTERCEPTOR_INITIALIZE_RANGE(fp->_bf._base, + fp->_bf._size); +#else + if (fp->_IO_read_base && fp->_IO_read_base < fp->_IO_read_end) + COMMON_INTERCEPTOR_INITIALIZE_RANGE(fp->_IO_read_base, + fp->_IO_read_end - fp->_IO_read_base); + if (fp->_IO_write_base && fp->_IO_write_base < fp->_IO_write_end) + COMMON_INTERCEPTOR_INITIALIZE_RANGE(fp->_IO_write_base, + fp->_IO_write_end - fp->_IO_write_base); +#endif +#endif // SANITIZER_HAS_STRUCT_FILE +} +#endif + +#if SANITIZER_INTERCEPT_LIBIO_INTERNALS +// These guys are called when a .c source is built with -O2. +INTERCEPTOR(int, __uflow, __sanitizer_FILE *fp) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, __uflow, fp); + int res = REAL(__uflow)(fp); + unpoison_file(fp); + return res; +} +INTERCEPTOR(int, __underflow, __sanitizer_FILE *fp) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, __underflow, fp); + int res = REAL(__underflow)(fp); + unpoison_file(fp); + return res; +} +INTERCEPTOR(int, __overflow, __sanitizer_FILE *fp, int ch) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, __overflow, fp, ch); + int res = REAL(__overflow)(fp, ch); + unpoison_file(fp); + return res; +} +INTERCEPTOR(int, __wuflow, __sanitizer_FILE *fp) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, __wuflow, fp); + int res = REAL(__wuflow)(fp); + unpoison_file(fp); + return res; +} +INTERCEPTOR(int, __wunderflow, __sanitizer_FILE *fp) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, __wunderflow, fp); + int res = REAL(__wunderflow)(fp); + unpoison_file(fp); + return res; +} +INTERCEPTOR(int, __woverflow, __sanitizer_FILE *fp, int ch) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, __woverflow, fp, ch); + int res = REAL(__woverflow)(fp, ch); + unpoison_file(fp); + return res; +} +#define INIT_LIBIO_INTERNALS \ + COMMON_INTERCEPT_FUNCTION(__uflow); \ + COMMON_INTERCEPT_FUNCTION(__underflow); \ + COMMON_INTERCEPT_FUNCTION(__overflow); \ + COMMON_INTERCEPT_FUNCTION(__wuflow); \ + COMMON_INTERCEPT_FUNCTION(__wunderflow); \ + COMMON_INTERCEPT_FUNCTION(__woverflow); +#else +#define INIT_LIBIO_INTERNALS +#endif + +#if SANITIZER_INTERCEPT_FOPEN +INTERCEPTOR(__sanitizer_FILE *, fopen, const char *path, const char *mode) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, fopen, path, mode); + if (path) COMMON_INTERCEPTOR_READ_RANGE(ctx, path, internal_strlen(path) + 1); + COMMON_INTERCEPTOR_READ_RANGE(ctx, mode, internal_strlen(mode) + 1); + __sanitizer_FILE *res = REAL(fopen)(path, mode); + COMMON_INTERCEPTOR_FILE_OPEN(ctx, res, path); + if (res) unpoison_file(res); + return res; +} +INTERCEPTOR(__sanitizer_FILE *, fdopen, int fd, const char *mode) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, fdopen, fd, mode); + COMMON_INTERCEPTOR_READ_RANGE(ctx, mode, internal_strlen(mode) + 1); + __sanitizer_FILE *res = REAL(fdopen)(fd, mode); + if (res) unpoison_file(res); + return res; +} +INTERCEPTOR(__sanitizer_FILE *, freopen, const char *path, const char *mode, + __sanitizer_FILE *fp) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, freopen, path, mode, fp); + if (path) COMMON_INTERCEPTOR_READ_RANGE(ctx, path, internal_strlen(path) + 1); + COMMON_INTERCEPTOR_READ_RANGE(ctx, mode, internal_strlen(mode) + 1); + COMMON_INTERCEPTOR_FILE_CLOSE(ctx, fp); + __sanitizer_FILE *res = REAL(freopen)(path, mode, fp); + COMMON_INTERCEPTOR_FILE_OPEN(ctx, res, path); + if (res) unpoison_file(res); + return res; +} +#define INIT_FOPEN \ + COMMON_INTERCEPT_FUNCTION(fopen); \ + COMMON_INTERCEPT_FUNCTION(fdopen); \ + COMMON_INTERCEPT_FUNCTION(freopen); +#else +#define INIT_FOPEN +#endif + +#if SANITIZER_INTERCEPT_FLOPEN +INTERCEPTOR(int, flopen, const char *path, int flags, ...) { + void *ctx; + va_list ap; + va_start(ap, flags); + u16 mode = static_cast<u16>(va_arg(ap, u32)); + va_end(ap); + COMMON_INTERCEPTOR_ENTER(ctx, flopen, path, flags, mode); + if (path) { + COMMON_INTERCEPTOR_READ_RANGE(ctx, path, internal_strlen(path) + 1); + } + return REAL(flopen)(path, flags, mode); +} + +INTERCEPTOR(int, flopenat, int dirfd, const char *path, int flags, ...) { + void *ctx; + va_list ap; + va_start(ap, flags); + u16 mode = static_cast<u16>(va_arg(ap, u32)); + va_end(ap); + COMMON_INTERCEPTOR_ENTER(ctx, flopen, path, flags, mode); + if (path) { + COMMON_INTERCEPTOR_READ_RANGE(ctx, path, internal_strlen(path) + 1); + } + return REAL(flopenat)(dirfd, path, flags, mode); +} + +#define INIT_FLOPEN \ + COMMON_INTERCEPT_FUNCTION(flopen); \ + COMMON_INTERCEPT_FUNCTION(flopenat); +#else +#define INIT_FLOPEN +#endif + +#if SANITIZER_INTERCEPT_FOPEN64 +INTERCEPTOR(__sanitizer_FILE *, fopen64, const char *path, const char *mode) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, fopen64, path, mode); + COMMON_INTERCEPTOR_READ_RANGE(ctx, path, internal_strlen(path) + 1); + COMMON_INTERCEPTOR_READ_RANGE(ctx, mode, internal_strlen(mode) + 1); + __sanitizer_FILE *res = REAL(fopen64)(path, mode); + COMMON_INTERCEPTOR_FILE_OPEN(ctx, res, path); + if (res) unpoison_file(res); + return res; +} +INTERCEPTOR(__sanitizer_FILE *, freopen64, const char *path, const char *mode, + __sanitizer_FILE *fp) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, freopen64, path, mode, fp); + if (path) COMMON_INTERCEPTOR_READ_RANGE(ctx, path, internal_strlen(path) + 1); + COMMON_INTERCEPTOR_READ_RANGE(ctx, mode, internal_strlen(mode) + 1); + COMMON_INTERCEPTOR_FILE_CLOSE(ctx, fp); + __sanitizer_FILE *res = REAL(freopen64)(path, mode, fp); + COMMON_INTERCEPTOR_FILE_OPEN(ctx, res, path); + if (res) unpoison_file(res); + return res; +} +#define INIT_FOPEN64 \ + COMMON_INTERCEPT_FUNCTION(fopen64); \ + COMMON_INTERCEPT_FUNCTION(freopen64); +#else +#define INIT_FOPEN64 +#endif + +#if SANITIZER_INTERCEPT_OPEN_MEMSTREAM +INTERCEPTOR(__sanitizer_FILE *, open_memstream, char **ptr, SIZE_T *sizeloc) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, open_memstream, ptr, sizeloc); + // FIXME: under ASan the call below may write to freed memory and corrupt + // its metadata. See + // https://github.com/google/sanitizers/issues/321. + __sanitizer_FILE *res = REAL(open_memstream)(ptr, sizeloc); + if (res) { + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ptr, sizeof(*ptr)); + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, sizeloc, sizeof(*sizeloc)); + unpoison_file(res); + FileMetadata file = {ptr, sizeloc}; + SetInterceptorMetadata(res, file); + } + return res; +} +INTERCEPTOR(__sanitizer_FILE *, open_wmemstream, wchar_t **ptr, + SIZE_T *sizeloc) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, open_wmemstream, ptr, sizeloc); + __sanitizer_FILE *res = REAL(open_wmemstream)(ptr, sizeloc); + if (res) { + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ptr, sizeof(*ptr)); + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, sizeloc, sizeof(*sizeloc)); + unpoison_file(res); + FileMetadata file = {(char **)ptr, sizeloc}; + SetInterceptorMetadata(res, file); + } + return res; +} +INTERCEPTOR(__sanitizer_FILE *, fmemopen, void *buf, SIZE_T size, + const char *mode) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, fmemopen, buf, size, mode); + // FIXME: under ASan the call below may write to freed memory and corrupt + // its metadata. See + // https://github.com/google/sanitizers/issues/321. + __sanitizer_FILE *res = REAL(fmemopen)(buf, size, mode); + if (res) unpoison_file(res); + return res; +} +#define INIT_OPEN_MEMSTREAM \ + COMMON_INTERCEPT_FUNCTION(open_memstream); \ + COMMON_INTERCEPT_FUNCTION(open_wmemstream); \ + COMMON_INTERCEPT_FUNCTION(fmemopen); +#else +#define INIT_OPEN_MEMSTREAM +#endif + +#if SANITIZER_INTERCEPT_OBSTACK +static void initialize_obstack(__sanitizer_obstack *obstack) { + COMMON_INTERCEPTOR_INITIALIZE_RANGE(obstack, sizeof(*obstack)); + if (obstack->chunk) + COMMON_INTERCEPTOR_INITIALIZE_RANGE(obstack->chunk, + sizeof(*obstack->chunk)); +} + +INTERCEPTOR(int, _obstack_begin_1, __sanitizer_obstack *obstack, int sz, + int align, void *(*alloc_fn)(uptr arg, uptr sz), + void (*free_fn)(uptr arg, void *p)) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, _obstack_begin_1, obstack, sz, align, alloc_fn, + free_fn); + int res = REAL(_obstack_begin_1)(obstack, sz, align, alloc_fn, free_fn); + if (res) initialize_obstack(obstack); + return res; +} +INTERCEPTOR(int, _obstack_begin, __sanitizer_obstack *obstack, int sz, + int align, void *(*alloc_fn)(uptr sz), void (*free_fn)(void *p)) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, _obstack_begin, obstack, sz, align, alloc_fn, + free_fn); + int res = REAL(_obstack_begin)(obstack, sz, align, alloc_fn, free_fn); + if (res) initialize_obstack(obstack); + return res; +} +INTERCEPTOR(void, _obstack_newchunk, __sanitizer_obstack *obstack, int length) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, _obstack_newchunk, obstack, length); + REAL(_obstack_newchunk)(obstack, length); + if (obstack->chunk) + COMMON_INTERCEPTOR_INITIALIZE_RANGE( + obstack->chunk, obstack->next_free - (char *)obstack->chunk); +} +#define INIT_OBSTACK \ + COMMON_INTERCEPT_FUNCTION(_obstack_begin_1); \ + COMMON_INTERCEPT_FUNCTION(_obstack_begin); \ + COMMON_INTERCEPT_FUNCTION(_obstack_newchunk); +#else +#define INIT_OBSTACK +#endif + +#if SANITIZER_INTERCEPT_FFLUSH +INTERCEPTOR(int, fflush, __sanitizer_FILE *fp) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, fflush, fp); + if (fp) + unpoison_file(fp); + int res = REAL(fflush)(fp); + // FIXME: handle fp == NULL + if (fp) { + const FileMetadata *m = GetInterceptorMetadata(fp); + if (m) COMMON_INTERCEPTOR_INITIALIZE_RANGE(*m->addr, *m->size); + } + return res; +} +#define INIT_FFLUSH COMMON_INTERCEPT_FUNCTION(fflush); +#else +#define INIT_FFLUSH +#endif + +#if SANITIZER_INTERCEPT_FCLOSE +INTERCEPTOR(int, fclose, __sanitizer_FILE *fp) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, fclose, fp); + COMMON_INTERCEPTOR_FILE_CLOSE(ctx, fp); + const FileMetadata *m = GetInterceptorMetadata(fp); + if (fp) + unpoison_file(fp); + int res = REAL(fclose)(fp); + if (m) { + COMMON_INTERCEPTOR_INITIALIZE_RANGE(*m->addr, *m->size); + DeleteInterceptorMetadata(fp); + } + return res; +} +#define INIT_FCLOSE COMMON_INTERCEPT_FUNCTION(fclose); +#else +#define INIT_FCLOSE +#endif + +#if SANITIZER_INTERCEPT_DLOPEN_DLCLOSE +INTERCEPTOR(void*, dlopen, const char *filename, int flag) { + void *ctx; + COMMON_INTERCEPTOR_ENTER_NOIGNORE(ctx, dlopen, filename, flag); + if (filename) COMMON_INTERCEPTOR_READ_STRING(ctx, filename, 0); + void *res = COMMON_INTERCEPTOR_DLOPEN(filename, flag); + Symbolizer::GetOrInit()->InvalidateModuleList(); + COMMON_INTERCEPTOR_LIBRARY_LOADED(filename, res); + return res; +} + +INTERCEPTOR(int, dlclose, void *handle) { + void *ctx; + COMMON_INTERCEPTOR_ENTER_NOIGNORE(ctx, dlclose, handle); + int res = REAL(dlclose)(handle); + Symbolizer::GetOrInit()->InvalidateModuleList(); + COMMON_INTERCEPTOR_LIBRARY_UNLOADED(); + return res; +} +#define INIT_DLOPEN_DLCLOSE \ + COMMON_INTERCEPT_FUNCTION(dlopen); \ + COMMON_INTERCEPT_FUNCTION(dlclose); +#else +#define INIT_DLOPEN_DLCLOSE +#endif + +#if SANITIZER_INTERCEPT_GETPASS +INTERCEPTOR(char *, getpass, const char *prompt) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, getpass, prompt); + if (prompt) + COMMON_INTERCEPTOR_READ_RANGE(ctx, prompt, internal_strlen(prompt)+1); + char *res = REAL(getpass)(prompt); + if (res) COMMON_INTERCEPTOR_INITIALIZE_RANGE(res, internal_strlen(res)+1); + return res; +} + +#define INIT_GETPASS COMMON_INTERCEPT_FUNCTION(getpass); +#else +#define INIT_GETPASS +#endif + +#if SANITIZER_INTERCEPT_TIMERFD +INTERCEPTOR(int, timerfd_settime, int fd, int flags, void *new_value, + void *old_value) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, timerfd_settime, fd, flags, new_value, + old_value); + COMMON_INTERCEPTOR_READ_RANGE(ctx, new_value, struct_itimerspec_sz); + int res = REAL(timerfd_settime)(fd, flags, new_value, old_value); + if (res != -1 && old_value) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, old_value, struct_itimerspec_sz); + return res; +} + +INTERCEPTOR(int, timerfd_gettime, int fd, void *curr_value) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, timerfd_gettime, fd, curr_value); + int res = REAL(timerfd_gettime)(fd, curr_value); + if (res != -1 && curr_value) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, curr_value, struct_itimerspec_sz); + return res; +} +#define INIT_TIMERFD \ + COMMON_INTERCEPT_FUNCTION(timerfd_settime); \ + COMMON_INTERCEPT_FUNCTION(timerfd_gettime); +#else +#define INIT_TIMERFD +#endif + +#if SANITIZER_INTERCEPT_MLOCKX +// Linux kernel has a bug that leads to kernel deadlock if a process +// maps TBs of memory and then calls mlock(). +static void MlockIsUnsupported() { + static atomic_uint8_t printed; + if (atomic_exchange(&printed, 1, memory_order_relaxed)) + return; + VPrintf(1, "%s ignores mlock/mlockall/munlock/munlockall\n", + SanitizerToolName); +} + +INTERCEPTOR(int, mlock, const void *addr, uptr len) { + MlockIsUnsupported(); + return 0; +} + +INTERCEPTOR(int, munlock, const void *addr, uptr len) { + MlockIsUnsupported(); + return 0; +} + +INTERCEPTOR(int, mlockall, int flags) { + MlockIsUnsupported(); + return 0; +} + +INTERCEPTOR(int, munlockall, void) { + MlockIsUnsupported(); + return 0; +} + +#define INIT_MLOCKX \ + COMMON_INTERCEPT_FUNCTION(mlock); \ + COMMON_INTERCEPT_FUNCTION(munlock); \ + COMMON_INTERCEPT_FUNCTION(mlockall); \ + COMMON_INTERCEPT_FUNCTION(munlockall); + +#else +#define INIT_MLOCKX +#endif // SANITIZER_INTERCEPT_MLOCKX + +#if SANITIZER_INTERCEPT_FOPENCOOKIE +struct WrappedCookie { + void *real_cookie; + __sanitizer_cookie_io_functions_t real_io_funcs; +}; + +static uptr wrapped_read(void *cookie, char *buf, uptr size) { + COMMON_INTERCEPTOR_UNPOISON_PARAM(3); + WrappedCookie *wrapped_cookie = (WrappedCookie *)cookie; + __sanitizer_cookie_io_read real_read = wrapped_cookie->real_io_funcs.read; + return real_read ? real_read(wrapped_cookie->real_cookie, buf, size) : 0; +} + +static uptr wrapped_write(void *cookie, const char *buf, uptr size) { + COMMON_INTERCEPTOR_UNPOISON_PARAM(3); + WrappedCookie *wrapped_cookie = (WrappedCookie *)cookie; + __sanitizer_cookie_io_write real_write = wrapped_cookie->real_io_funcs.write; + return real_write ? real_write(wrapped_cookie->real_cookie, buf, size) : size; +} + +static int wrapped_seek(void *cookie, u64 *offset, int whence) { + COMMON_INTERCEPTOR_UNPOISON_PARAM(3); + COMMON_INTERCEPTOR_INITIALIZE_RANGE(offset, sizeof(*offset)); + WrappedCookie *wrapped_cookie = (WrappedCookie *)cookie; + __sanitizer_cookie_io_seek real_seek = wrapped_cookie->real_io_funcs.seek; + return real_seek ? real_seek(wrapped_cookie->real_cookie, offset, whence) + : -1; +} + +static int wrapped_close(void *cookie) { + COMMON_INTERCEPTOR_UNPOISON_PARAM(1); + WrappedCookie *wrapped_cookie = (WrappedCookie *)cookie; + __sanitizer_cookie_io_close real_close = wrapped_cookie->real_io_funcs.close; + int res = real_close ? real_close(wrapped_cookie->real_cookie) : 0; + InternalFree(wrapped_cookie); + return res; +} + +INTERCEPTOR(__sanitizer_FILE *, fopencookie, void *cookie, const char *mode, + __sanitizer_cookie_io_functions_t io_funcs) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, fopencookie, cookie, mode, io_funcs); + WrappedCookie *wrapped_cookie = + (WrappedCookie *)InternalAlloc(sizeof(WrappedCookie)); + wrapped_cookie->real_cookie = cookie; + wrapped_cookie->real_io_funcs = io_funcs; + __sanitizer_FILE *res = + REAL(fopencookie)(wrapped_cookie, mode, {wrapped_read, wrapped_write, + wrapped_seek, wrapped_close}); + return res; +} + +#define INIT_FOPENCOOKIE COMMON_INTERCEPT_FUNCTION(fopencookie); +#else +#define INIT_FOPENCOOKIE +#endif // SANITIZER_INTERCEPT_FOPENCOOKIE + +#if SANITIZER_INTERCEPT_SEM +INTERCEPTOR(int, sem_init, __sanitizer_sem_t *s, int pshared, unsigned value) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, sem_init, s, pshared, value); + // Workaround a bug in glibc's "old" semaphore implementation by + // zero-initializing the sem_t contents. This has to be done here because + // interceptors bind to the lowest symbols version by default, hitting the + // buggy code path while the non-sanitized build of the same code works fine. + REAL(memset)(s, 0, sizeof(*s)); + int res = REAL(sem_init)(s, pshared, value); + return res; +} + +INTERCEPTOR(int, sem_destroy, __sanitizer_sem_t *s) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, sem_destroy, s); + int res = REAL(sem_destroy)(s); + return res; +} + +INTERCEPTOR(int, sem_wait, __sanitizer_sem_t *s) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, sem_wait, s); + int res = COMMON_INTERCEPTOR_BLOCK_REAL(sem_wait)(s); + if (res == 0) { + COMMON_INTERCEPTOR_ACQUIRE(ctx, (uptr)s); + } + return res; +} + +INTERCEPTOR(int, sem_trywait, __sanitizer_sem_t *s) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, sem_trywait, s); + int res = REAL(sem_trywait)(s); + if (res == 0) { + COMMON_INTERCEPTOR_ACQUIRE(ctx, (uptr)s); + } + return res; +} + +INTERCEPTOR(int, sem_timedwait, __sanitizer_sem_t *s, void *abstime) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, sem_timedwait, s, abstime); + COMMON_INTERCEPTOR_READ_RANGE(ctx, abstime, struct_timespec_sz); + int res = COMMON_INTERCEPTOR_BLOCK_REAL(sem_timedwait)(s, abstime); + if (res == 0) { + COMMON_INTERCEPTOR_ACQUIRE(ctx, (uptr)s); + } + return res; +} + +INTERCEPTOR(int, sem_post, __sanitizer_sem_t *s) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, sem_post, s); + COMMON_INTERCEPTOR_RELEASE(ctx, (uptr)s); + int res = REAL(sem_post)(s); + return res; +} + +INTERCEPTOR(int, sem_getvalue, __sanitizer_sem_t *s, int *sval) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, sem_getvalue, s, sval); + int res = REAL(sem_getvalue)(s, sval); + if (res == 0) { + COMMON_INTERCEPTOR_ACQUIRE(ctx, (uptr)s); + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, sval, sizeof(*sval)); + } + return res; +} + +INTERCEPTOR(__sanitizer_sem_t *, sem_open, const char *name, int oflag, ...) { + void *ctx; + va_list ap; + va_start(ap, oflag); + u32 mode = va_arg(ap, u32); + u32 value = va_arg(ap, u32); + COMMON_INTERCEPTOR_ENTER(ctx, sem_open, name, oflag, mode, value); + COMMON_INTERCEPTOR_READ_RANGE(ctx, name, internal_strlen(name) + 1); + __sanitizer_sem_t *s = REAL(sem_open)(name, oflag, mode, value); + if (s) + COMMON_INTERCEPTOR_INITIALIZE_RANGE(s, sizeof(*s)); + va_end(ap); + return s; +} + +INTERCEPTOR(int, sem_unlink, const char *name) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, sem_unlink, name); + COMMON_INTERCEPTOR_READ_RANGE(ctx, name, internal_strlen(name) + 1); + return REAL(sem_unlink)(name); +} + +# define INIT_SEM \ + COMMON_INTERCEPT_FUNCTION(sem_init); \ + COMMON_INTERCEPT_FUNCTION(sem_destroy); \ + COMMON_INTERCEPT_FUNCTION(sem_wait); \ + COMMON_INTERCEPT_FUNCTION(sem_trywait); \ + COMMON_INTERCEPT_FUNCTION(sem_timedwait); \ + COMMON_INTERCEPT_FUNCTION(sem_post); \ + COMMON_INTERCEPT_FUNCTION(sem_getvalue); \ + COMMON_INTERCEPT_FUNCTION(sem_open); \ + COMMON_INTERCEPT_FUNCTION(sem_unlink); +#else +# define INIT_SEM +#endif // SANITIZER_INTERCEPT_SEM + +#if SANITIZER_INTERCEPT_PTHREAD_SETCANCEL +INTERCEPTOR(int, pthread_setcancelstate, int state, int *oldstate) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, pthread_setcancelstate, state, oldstate); + int res = REAL(pthread_setcancelstate)(state, oldstate); + if (res == 0 && oldstate != nullptr) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, oldstate, sizeof(*oldstate)); + return res; +} + +INTERCEPTOR(int, pthread_setcanceltype, int type, int *oldtype) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, pthread_setcanceltype, type, oldtype); + int res = REAL(pthread_setcanceltype)(type, oldtype); + if (res == 0 && oldtype != nullptr) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, oldtype, sizeof(*oldtype)); + return res; +} +#define INIT_PTHREAD_SETCANCEL \ + COMMON_INTERCEPT_FUNCTION(pthread_setcancelstate); \ + COMMON_INTERCEPT_FUNCTION(pthread_setcanceltype); +#else +#define INIT_PTHREAD_SETCANCEL +#endif + +#if SANITIZER_INTERCEPT_MINCORE +INTERCEPTOR(int, mincore, void *addr, uptr length, unsigned char *vec) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, mincore, addr, length, vec); + int res = REAL(mincore)(addr, length, vec); + if (res == 0) { + uptr page_size = GetPageSizeCached(); + uptr vec_size = ((length + page_size - 1) & (~(page_size - 1))) / page_size; + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, vec, vec_size); + } + return res; +} +#define INIT_MINCORE COMMON_INTERCEPT_FUNCTION(mincore); +#else +#define INIT_MINCORE +#endif + +#if SANITIZER_INTERCEPT_PROCESS_VM_READV +INTERCEPTOR(SSIZE_T, process_vm_readv, int pid, __sanitizer_iovec *local_iov, + uptr liovcnt, __sanitizer_iovec *remote_iov, uptr riovcnt, + uptr flags) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, process_vm_readv, pid, local_iov, liovcnt, + remote_iov, riovcnt, flags); + SSIZE_T res = REAL(process_vm_readv)(pid, local_iov, liovcnt, remote_iov, + riovcnt, flags); + if (res > 0) + write_iovec(ctx, local_iov, liovcnt, res); + return res; +} + +INTERCEPTOR(SSIZE_T, process_vm_writev, int pid, __sanitizer_iovec *local_iov, + uptr liovcnt, __sanitizer_iovec *remote_iov, uptr riovcnt, + uptr flags) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, process_vm_writev, pid, local_iov, liovcnt, + remote_iov, riovcnt, flags); + SSIZE_T res = REAL(process_vm_writev)(pid, local_iov, liovcnt, remote_iov, + riovcnt, flags); + if (res > 0) + read_iovec(ctx, local_iov, liovcnt, res); + return res; +} +#define INIT_PROCESS_VM_READV \ + COMMON_INTERCEPT_FUNCTION(process_vm_readv); \ + COMMON_INTERCEPT_FUNCTION(process_vm_writev); +#else +#define INIT_PROCESS_VM_READV +#endif + +#if SANITIZER_INTERCEPT_CTERMID +INTERCEPTOR(char *, ctermid, char *s) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, ctermid, s); + char *res = REAL(ctermid)(s); + if (res) { + COMMON_INTERCEPTOR_INITIALIZE_RANGE(res, internal_strlen(res) + 1); + } + return res; +} +#define INIT_CTERMID COMMON_INTERCEPT_FUNCTION(ctermid); +#else +#define INIT_CTERMID +#endif + +#if SANITIZER_INTERCEPT_CTERMID_R +INTERCEPTOR(char *, ctermid_r, char *s) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, ctermid_r, s); + char *res = REAL(ctermid_r)(s); + if (res) { + COMMON_INTERCEPTOR_INITIALIZE_RANGE(res, internal_strlen(res) + 1); + } + return res; +} +#define INIT_CTERMID_R COMMON_INTERCEPT_FUNCTION(ctermid_r); +#else +#define INIT_CTERMID_R +#endif + +#if SANITIZER_INTERCEPT_RECV_RECVFROM +INTERCEPTOR(SSIZE_T, recv, int fd, void *buf, SIZE_T len, int flags) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, recv, fd, buf, len, flags); + COMMON_INTERCEPTOR_FD_ACCESS(ctx, fd); + SSIZE_T res = REAL(recv)(fd, buf, len, flags); + if (res > 0) { + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, Min((SIZE_T)res, len)); + } + if (res >= 0 && fd >= 0) COMMON_INTERCEPTOR_FD_ACQUIRE(ctx, fd); + return res; +} + +INTERCEPTOR(SSIZE_T, recvfrom, int fd, void *buf, SIZE_T len, int flags, + void *srcaddr, int *addrlen) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, recvfrom, fd, buf, len, flags, srcaddr, + addrlen); + COMMON_INTERCEPTOR_FD_ACCESS(ctx, fd); + SIZE_T srcaddr_sz; + if (srcaddr) srcaddr_sz = *addrlen; + (void)srcaddr_sz; // prevent "set but not used" warning + SSIZE_T res = REAL(recvfrom)(fd, buf, len, flags, srcaddr, addrlen); + if (res > 0) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, Min((SIZE_T)res, len)); + if (res >= 0 && srcaddr) + COMMON_INTERCEPTOR_INITIALIZE_RANGE(srcaddr, + Min((SIZE_T)*addrlen, srcaddr_sz)); + return res; +} +#define INIT_RECV_RECVFROM \ + COMMON_INTERCEPT_FUNCTION(recv); \ + COMMON_INTERCEPT_FUNCTION(recvfrom); +#else +#define INIT_RECV_RECVFROM +#endif + +#if SANITIZER_INTERCEPT_SEND_SENDTO +INTERCEPTOR(SSIZE_T, send, int fd, void *buf, SIZE_T len, int flags) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, send, fd, buf, len, flags); + if (fd >= 0) { + COMMON_INTERCEPTOR_FD_ACCESS(ctx, fd); + COMMON_INTERCEPTOR_FD_RELEASE(ctx, fd); + } + SSIZE_T res = REAL(send)(fd, buf, len, flags); + if (common_flags()->intercept_send && res > 0) + COMMON_INTERCEPTOR_READ_RANGE(ctx, buf, Min((SIZE_T)res, len)); + return res; +} + +INTERCEPTOR(SSIZE_T, sendto, int fd, void *buf, SIZE_T len, int flags, + void *dstaddr, int addrlen) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, sendto, fd, buf, len, flags, dstaddr, addrlen); + if (fd >= 0) { + COMMON_INTERCEPTOR_FD_ACCESS(ctx, fd); + COMMON_INTERCEPTOR_FD_RELEASE(ctx, fd); + } + // Can't check dstaddr as it may have uninitialized padding at the end. + SSIZE_T res = REAL(sendto)(fd, buf, len, flags, dstaddr, addrlen); + if (common_flags()->intercept_send && res > 0) + COMMON_INTERCEPTOR_READ_RANGE(ctx, buf, Min((SIZE_T)res, len)); + return res; +} +#define INIT_SEND_SENDTO \ + COMMON_INTERCEPT_FUNCTION(send); \ + COMMON_INTERCEPT_FUNCTION(sendto); +#else +#define INIT_SEND_SENDTO +#endif + +#if SANITIZER_INTERCEPT_EVENTFD_READ_WRITE +INTERCEPTOR(int, eventfd_read, int fd, u64 *value) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, eventfd_read, fd, value); + COMMON_INTERCEPTOR_FD_ACCESS(ctx, fd); + int res = REAL(eventfd_read)(fd, value); + if (res == 0) { + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, value, sizeof(*value)); + if (fd >= 0) COMMON_INTERCEPTOR_FD_ACQUIRE(ctx, fd); + } + return res; +} +INTERCEPTOR(int, eventfd_write, int fd, u64 value) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, eventfd_write, fd, value); + if (fd >= 0) { + COMMON_INTERCEPTOR_FD_ACCESS(ctx, fd); + COMMON_INTERCEPTOR_FD_RELEASE(ctx, fd); + } + int res = REAL(eventfd_write)(fd, value); + return res; +} +#define INIT_EVENTFD_READ_WRITE \ + COMMON_INTERCEPT_FUNCTION(eventfd_read); \ + COMMON_INTERCEPT_FUNCTION(eventfd_write) +#else +#define INIT_EVENTFD_READ_WRITE +#endif + +#if SANITIZER_INTERCEPT_STAT +INTERCEPTOR(int, stat, const char *path, void *buf) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, stat, path, buf); + if (common_flags()->intercept_stat) + COMMON_INTERCEPTOR_READ_STRING(ctx, path, 0); + int res = REAL(stat)(path, buf); + if (!res) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, __sanitizer::struct_stat_sz); + return res; +} +#define INIT_STAT COMMON_INTERCEPT_FUNCTION(stat) +#else +#define INIT_STAT +#endif + +#if SANITIZER_INTERCEPT_LSTAT +INTERCEPTOR(int, lstat, const char *path, void *buf) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, lstat, path, buf); + if (common_flags()->intercept_stat) + COMMON_INTERCEPTOR_READ_STRING(ctx, path, 0); + int res = REAL(lstat)(path, buf); + if (!res) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, __sanitizer::struct_stat_sz); + return res; +} +#define INIT_LSTAT COMMON_INTERCEPT_FUNCTION(lstat) +#else +#define INIT_LSTAT +#endif + +#if SANITIZER_INTERCEPT___XSTAT +INTERCEPTOR(int, __xstat, int version, const char *path, void *buf) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, __xstat, version, path, buf); + if (common_flags()->intercept_stat) + COMMON_INTERCEPTOR_READ_STRING(ctx, path, 0); + int res = REAL(__xstat)(version, path, buf); + if (!res) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, __sanitizer::struct_stat_sz); + return res; +} +#define INIT___XSTAT COMMON_INTERCEPT_FUNCTION(__xstat) +#else +#define INIT___XSTAT +#endif + +#if SANITIZER_INTERCEPT___XSTAT64 +INTERCEPTOR(int, __xstat64, int version, const char *path, void *buf) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, __xstat64, version, path, buf); + if (common_flags()->intercept_stat) + COMMON_INTERCEPTOR_READ_STRING(ctx, path, 0); + int res = REAL(__xstat64)(version, path, buf); + if (!res) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, __sanitizer::struct_stat64_sz); + return res; +} +#define INIT___XSTAT64 COMMON_INTERCEPT_FUNCTION(__xstat64) +#else +#define INIT___XSTAT64 +#endif + +#if SANITIZER_INTERCEPT___LXSTAT +INTERCEPTOR(int, __lxstat, int version, const char *path, void *buf) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, __lxstat, version, path, buf); + if (common_flags()->intercept_stat) + COMMON_INTERCEPTOR_READ_STRING(ctx, path, 0); + int res = REAL(__lxstat)(version, path, buf); + if (!res) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, __sanitizer::struct_stat_sz); + return res; +} +#define INIT___LXSTAT COMMON_INTERCEPT_FUNCTION(__lxstat) +#else +#define INIT___LXSTAT +#endif + +#if SANITIZER_INTERCEPT___LXSTAT64 +INTERCEPTOR(int, __lxstat64, int version, const char *path, void *buf) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, __lxstat64, version, path, buf); + if (common_flags()->intercept_stat) + COMMON_INTERCEPTOR_READ_STRING(ctx, path, 0); + int res = REAL(__lxstat64)(version, path, buf); + if (!res) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, __sanitizer::struct_stat64_sz); + return res; +} +#define INIT___LXSTAT64 COMMON_INTERCEPT_FUNCTION(__lxstat64) +#else +#define INIT___LXSTAT64 +#endif + +// FIXME: add other *stat interceptor + +#if SANITIZER_INTERCEPT_UTMP +INTERCEPTOR(void *, getutent, int dummy) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, getutent, dummy); + void *res = REAL(getutent)(dummy); + if (res) + COMMON_INTERCEPTOR_INITIALIZE_RANGE(res, __sanitizer::struct_utmp_sz); + return res; +} +INTERCEPTOR(void *, getutid, void *ut) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, getutid, ut); + void *res = REAL(getutid)(ut); + if (res) + COMMON_INTERCEPTOR_INITIALIZE_RANGE(res, __sanitizer::struct_utmp_sz); + return res; +} +INTERCEPTOR(void *, getutline, void *ut) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, getutline, ut); + void *res = REAL(getutline)(ut); + if (res) + COMMON_INTERCEPTOR_INITIALIZE_RANGE(res, __sanitizer::struct_utmp_sz); + return res; +} +#define INIT_UTMP \ + COMMON_INTERCEPT_FUNCTION(getutent); \ + COMMON_INTERCEPT_FUNCTION(getutid); \ + COMMON_INTERCEPT_FUNCTION(getutline); +#else +#define INIT_UTMP +#endif + +#if SANITIZER_INTERCEPT_UTMPX +INTERCEPTOR(void *, getutxent, int dummy) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, getutxent, dummy); + void *res = REAL(getutxent)(dummy); + if (res) + COMMON_INTERCEPTOR_INITIALIZE_RANGE(res, __sanitizer::struct_utmpx_sz); + return res; +} +INTERCEPTOR(void *, getutxid, void *ut) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, getutxid, ut); + void *res = REAL(getutxid)(ut); + if (res) + COMMON_INTERCEPTOR_INITIALIZE_RANGE(res, __sanitizer::struct_utmpx_sz); + return res; +} +INTERCEPTOR(void *, getutxline, void *ut) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, getutxline, ut); + void *res = REAL(getutxline)(ut); + if (res) + COMMON_INTERCEPTOR_INITIALIZE_RANGE(res, __sanitizer::struct_utmpx_sz); + return res; +} +INTERCEPTOR(void *, pututxline, const void *ut) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, pututxline, ut); + if (ut) + COMMON_INTERCEPTOR_READ_RANGE(ctx, ut, __sanitizer::struct_utmpx_sz); + void *res = REAL(pututxline)(ut); + if (res) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, __sanitizer::struct_utmpx_sz); + return res; +} +#define INIT_UTMPX \ + COMMON_INTERCEPT_FUNCTION(getutxent); \ + COMMON_INTERCEPT_FUNCTION(getutxid); \ + COMMON_INTERCEPT_FUNCTION(getutxline); \ + COMMON_INTERCEPT_FUNCTION(pututxline); +#else +#define INIT_UTMPX +#endif + +#if SANITIZER_INTERCEPT_GETLOADAVG +INTERCEPTOR(int, getloadavg, double *loadavg, int nelem) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, getloadavg, loadavg, nelem); + int res = REAL(getloadavg)(loadavg, nelem); + if (res > 0) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, loadavg, res * sizeof(*loadavg)); + return res; +} +#define INIT_GETLOADAVG \ + COMMON_INTERCEPT_FUNCTION(getloadavg); +#else +#define INIT_GETLOADAVG +#endif + +#if SANITIZER_INTERCEPT_MCHECK_MPROBE +INTERCEPTOR(int, mcheck, void (*abortfunc)(int mstatus)) { + return 0; +} + +INTERCEPTOR(int, mcheck_pedantic, void (*abortfunc)(int mstatus)) { + return 0; +} + +INTERCEPTOR(int, mprobe, void *ptr) { + return 0; +} +#endif + +INTERCEPTOR(SIZE_T, wcslen, const wchar_t *s) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, wcslen, s); + SIZE_T res = REAL(wcslen)(s); + COMMON_INTERCEPTOR_READ_RANGE(ctx, s, sizeof(wchar_t) * (res + 1)); + return res; +} + +INTERCEPTOR(SIZE_T, wcsnlen, const wchar_t *s, SIZE_T n) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, wcsnlen, s, n); + SIZE_T res = REAL(wcsnlen)(s, n); + COMMON_INTERCEPTOR_READ_RANGE(ctx, s, sizeof(wchar_t) * Min(res + 1, n)); + return res; +} +#define INIT_WCSLEN \ + COMMON_INTERCEPT_FUNCTION(wcslen); \ + COMMON_INTERCEPT_FUNCTION(wcsnlen); + +#if SANITIZER_INTERCEPT_WCSCAT +INTERCEPTOR(wchar_t *, wcscat, wchar_t *dst, const wchar_t *src) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, wcscat, dst, src); + SIZE_T src_size = internal_wcslen(src); + SIZE_T dst_size = internal_wcslen(dst); + COMMON_INTERCEPTOR_READ_RANGE(ctx, src, (src_size + 1) * sizeof(wchar_t)); + COMMON_INTERCEPTOR_READ_RANGE(ctx, dst, (dst_size + 1) * sizeof(wchar_t)); + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, dst + dst_size, + (src_size + 1) * sizeof(wchar_t)); + return REAL(wcscat)(dst, src); +} + +INTERCEPTOR(wchar_t *, wcsncat, wchar_t *dst, const wchar_t *src, SIZE_T n) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, wcsncat, dst, src, n); + SIZE_T src_size = internal_wcsnlen(src, n); + SIZE_T dst_size = internal_wcslen(dst); + COMMON_INTERCEPTOR_READ_RANGE(ctx, src, + Min(src_size + 1, n) * sizeof(wchar_t)); + COMMON_INTERCEPTOR_READ_RANGE(ctx, dst, (dst_size + 1) * sizeof(wchar_t)); + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, dst + dst_size, + (src_size + 1) * sizeof(wchar_t)); + return REAL(wcsncat)(dst, src, n); +} +#define INIT_WCSCAT \ + COMMON_INTERCEPT_FUNCTION(wcscat); \ + COMMON_INTERCEPT_FUNCTION(wcsncat); +#else +#define INIT_WCSCAT +#endif + +#if SANITIZER_INTERCEPT_WCSDUP +INTERCEPTOR(wchar_t *, wcsdup, wchar_t *s) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, wcsdup, s); + SIZE_T len = internal_wcslen(s); + COMMON_INTERCEPTOR_READ_RANGE(ctx, s, sizeof(wchar_t) * (len + 1)); + wchar_t *result = REAL(wcsdup)(s); + if (result) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, result, sizeof(wchar_t) * (len + 1)); + return result; +} + +#define INIT_WCSDUP COMMON_INTERCEPT_FUNCTION(wcsdup); +#else +#define INIT_WCSDUP +#endif + +#if SANITIZER_INTERCEPT_STRXFRM +static SIZE_T RealStrLen(const char *str) { return internal_strlen(str); } + +static SIZE_T RealStrLen(const wchar_t *str) { return internal_wcslen(str); } + +#define STRXFRM_INTERCEPTOR_IMPL(strxfrm, dest, src, len, ...) \ + { \ + void *ctx; \ + COMMON_INTERCEPTOR_ENTER(ctx, strxfrm, dest, src, len, ##__VA_ARGS__); \ + COMMON_INTERCEPTOR_READ_RANGE(ctx, src, \ + sizeof(*src) * (RealStrLen(src) + 1)); \ + SIZE_T res = REAL(strxfrm)(dest, src, len, ##__VA_ARGS__); \ + if (res < len) \ + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, dest, sizeof(*src) * (res + 1)); \ + return res; \ + } + +INTERCEPTOR(SIZE_T, strxfrm, char *dest, const char *src, SIZE_T len) { + STRXFRM_INTERCEPTOR_IMPL(strxfrm, dest, src, len); +} + +INTERCEPTOR(SIZE_T, strxfrm_l, char *dest, const char *src, SIZE_T len, + void *locale) { + STRXFRM_INTERCEPTOR_IMPL(strxfrm_l, dest, src, len, locale); +} + +#define INIT_STRXFRM \ + COMMON_INTERCEPT_FUNCTION(strxfrm); \ + COMMON_INTERCEPT_FUNCTION(strxfrm_l); +#else +#define INIT_STRXFRM +#endif + +#if SANITIZER_INTERCEPT___STRXFRM_L +INTERCEPTOR(SIZE_T, __strxfrm_l, char *dest, const char *src, SIZE_T len, + void *locale) { + STRXFRM_INTERCEPTOR_IMPL(__strxfrm_l, dest, src, len, locale); +} + +#define INIT___STRXFRM_L COMMON_INTERCEPT_FUNCTION(__strxfrm_l); +#else +#define INIT___STRXFRM_L +#endif + +#if SANITIZER_INTERCEPT_WCSXFRM +INTERCEPTOR(SIZE_T, wcsxfrm, wchar_t *dest, const wchar_t *src, SIZE_T len) { + STRXFRM_INTERCEPTOR_IMPL(wcsxfrm, dest, src, len); +} + +INTERCEPTOR(SIZE_T, wcsxfrm_l, wchar_t *dest, const wchar_t *src, SIZE_T len, + void *locale) { + STRXFRM_INTERCEPTOR_IMPL(wcsxfrm_l, dest, src, len, locale); +} + +#define INIT_WCSXFRM \ + COMMON_INTERCEPT_FUNCTION(wcsxfrm); \ + COMMON_INTERCEPT_FUNCTION(wcsxfrm_l); +#else +#define INIT_WCSXFRM +#endif + +#if SANITIZER_INTERCEPT___WCSXFRM_L +INTERCEPTOR(SIZE_T, __wcsxfrm_l, wchar_t *dest, const wchar_t *src, SIZE_T len, + void *locale) { + STRXFRM_INTERCEPTOR_IMPL(__wcsxfrm_l, dest, src, len, locale); +} + +#define INIT___WCSXFRM_L COMMON_INTERCEPT_FUNCTION(__wcsxfrm_l); +#else +#define INIT___WCSXFRM_L +#endif + +#if SANITIZER_INTERCEPT_ACCT +INTERCEPTOR(int, acct, const char *file) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, acct, file); + if (file) + COMMON_INTERCEPTOR_READ_RANGE(ctx, file, internal_strlen(file) + 1); + return REAL(acct)(file); +} +#define INIT_ACCT COMMON_INTERCEPT_FUNCTION(acct) +#else +#define INIT_ACCT +#endif + +#if SANITIZER_INTERCEPT_USER_FROM_UID +INTERCEPTOR(const char *, user_from_uid, u32 uid, int nouser) { + void *ctx; + const char *user; + COMMON_INTERCEPTOR_ENTER(ctx, user_from_uid, uid, nouser); + user = REAL(user_from_uid)(uid, nouser); + if (user) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, user, internal_strlen(user) + 1); + return user; +} +#define INIT_USER_FROM_UID COMMON_INTERCEPT_FUNCTION(user_from_uid) +#else +#define INIT_USER_FROM_UID +#endif + +#if SANITIZER_INTERCEPT_UID_FROM_USER +INTERCEPTOR(int, uid_from_user, const char *name, u32 *uid) { + void *ctx; + int res; + COMMON_INTERCEPTOR_ENTER(ctx, uid_from_user, name, uid); + if (name) + COMMON_INTERCEPTOR_READ_RANGE(ctx, name, internal_strlen(name) + 1); + res = REAL(uid_from_user)(name, uid); + if (uid) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, uid, sizeof(*uid)); + return res; +} +#define INIT_UID_FROM_USER COMMON_INTERCEPT_FUNCTION(uid_from_user) +#else +#define INIT_UID_FROM_USER +#endif + +#if SANITIZER_INTERCEPT_GROUP_FROM_GID +INTERCEPTOR(const char *, group_from_gid, u32 gid, int nogroup) { + void *ctx; + const char *group; + COMMON_INTERCEPTOR_ENTER(ctx, group_from_gid, gid, nogroup); + group = REAL(group_from_gid)(gid, nogroup); + if (group) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, group, internal_strlen(group) + 1); + return group; +} +#define INIT_GROUP_FROM_GID COMMON_INTERCEPT_FUNCTION(group_from_gid) +#else +#define INIT_GROUP_FROM_GID +#endif + +#if SANITIZER_INTERCEPT_GID_FROM_GROUP +INTERCEPTOR(int, gid_from_group, const char *group, u32 *gid) { + void *ctx; + int res; + COMMON_INTERCEPTOR_ENTER(ctx, gid_from_group, group, gid); + if (group) + COMMON_INTERCEPTOR_READ_RANGE(ctx, group, internal_strlen(group) + 1); + res = REAL(gid_from_group)(group, gid); + if (gid) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, gid, sizeof(*gid)); + return res; +} +#define INIT_GID_FROM_GROUP COMMON_INTERCEPT_FUNCTION(gid_from_group) +#else +#define INIT_GID_FROM_GROUP +#endif + +#if SANITIZER_INTERCEPT_ACCESS +INTERCEPTOR(int, access, const char *path, int mode) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, access, path, mode); + if (path) + COMMON_INTERCEPTOR_READ_RANGE(ctx, path, internal_strlen(path) + 1); + return REAL(access)(path, mode); +} +#define INIT_ACCESS COMMON_INTERCEPT_FUNCTION(access) +#else +#define INIT_ACCESS +#endif + +#if SANITIZER_INTERCEPT_FACCESSAT +INTERCEPTOR(int, faccessat, int fd, const char *path, int mode, int flags) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, faccessat, fd, path, mode, flags); + if (path) + COMMON_INTERCEPTOR_READ_RANGE(ctx, path, internal_strlen(path) + 1); + return REAL(faccessat)(fd, path, mode, flags); +} +#define INIT_FACCESSAT COMMON_INTERCEPT_FUNCTION(faccessat) +#else +#define INIT_FACCESSAT +#endif + +#if SANITIZER_INTERCEPT_GETGROUPLIST +INTERCEPTOR(int, getgrouplist, const char *name, u32 basegid, u32 *groups, + int *ngroups) { + void *ctx; + int res; + COMMON_INTERCEPTOR_ENTER(ctx, getgrouplist, name, basegid, groups, ngroups); + if (name) + COMMON_INTERCEPTOR_READ_RANGE(ctx, name, internal_strlen(name) + 1); + if (ngroups) + COMMON_INTERCEPTOR_READ_RANGE(ctx, ngroups, sizeof(*ngroups)); + res = REAL(getgrouplist)(name, basegid, groups, ngroups); + if (!res && groups && ngroups) { + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, groups, sizeof(*groups) * (*ngroups)); + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ngroups, sizeof(*ngroups)); + } + return res; +} + +#define INIT_GETGROUPLIST COMMON_INTERCEPT_FUNCTION(getgrouplist); +#else +#define INIT_GETGROUPLIST +#endif + +#if SANITIZER_INTERCEPT_GETGROUPMEMBERSHIP +INTERCEPTOR(int, getgroupmembership, const char *name, u32 basegid, u32 *groups, + int maxgrp, int *ngroups) { + void *ctx; + int res; + COMMON_INTERCEPTOR_ENTER(ctx, getgroupmembership, name, basegid, groups, + maxgrp, ngroups); + if (name) + COMMON_INTERCEPTOR_READ_RANGE(ctx, name, internal_strlen(name) + 1); + res = REAL(getgroupmembership)(name, basegid, groups, maxgrp, ngroups); + if (!res && groups && ngroups) { + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, groups, sizeof(*groups) * (*ngroups)); + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ngroups, sizeof(*ngroups)); + } + return res; +} + +#define INIT_GETGROUPMEMBERSHIP COMMON_INTERCEPT_FUNCTION(getgroupmembership); +#else +#define INIT_GETGROUPMEMBERSHIP +#endif + +#if SANITIZER_INTERCEPT_READLINK +INTERCEPTOR(SSIZE_T, readlink, const char *path, char *buf, SIZE_T bufsiz) { + void* ctx; + COMMON_INTERCEPTOR_ENTER(ctx, readlink, path, buf, bufsiz); + COMMON_INTERCEPTOR_READ_RANGE(ctx, path, internal_strlen(path) + 1); + SSIZE_T res = REAL(readlink)(path, buf, bufsiz); + if (res > 0) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, res); + return res; +} + +#define INIT_READLINK COMMON_INTERCEPT_FUNCTION(readlink) +#else +#define INIT_READLINK +#endif + +#if SANITIZER_INTERCEPT_READLINKAT +INTERCEPTOR(SSIZE_T, readlinkat, int dirfd, const char *path, char *buf, + SIZE_T bufsiz) { + void* ctx; + COMMON_INTERCEPTOR_ENTER(ctx, readlinkat, dirfd, path, buf, bufsiz); + COMMON_INTERCEPTOR_READ_RANGE(ctx, path, internal_strlen(path) + 1); + SSIZE_T res = REAL(readlinkat)(dirfd, path, buf, bufsiz); + if (res > 0) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, res); + return res; +} + +#define INIT_READLINKAT COMMON_INTERCEPT_FUNCTION(readlinkat) +#else +#define INIT_READLINKAT +#endif + +#if SANITIZER_INTERCEPT_NAME_TO_HANDLE_AT +INTERCEPTOR(int, name_to_handle_at, int dirfd, const char *pathname, + struct file_handle *handle, int *mount_id, int flags) { + void* ctx; + COMMON_INTERCEPTOR_ENTER(ctx, name_to_handle_at, dirfd, pathname, handle, + mount_id, flags); + COMMON_INTERCEPTOR_READ_RANGE(ctx, pathname, internal_strlen(pathname) + 1); + + __sanitizer_file_handle *sanitizer_handle = + reinterpret_cast<__sanitizer_file_handle*>(handle); + COMMON_INTERCEPTOR_READ_RANGE( + ctx, &sanitizer_handle->handle_bytes, + sizeof(sanitizer_handle->handle_bytes)); + + int res = REAL(name_to_handle_at)(dirfd, pathname, handle, mount_id, flags); + if (!res) { + COMMON_INTERCEPTOR_WRITE_RANGE( + ctx, &sanitizer_handle->handle_bytes, + sizeof(sanitizer_handle->handle_bytes)); + COMMON_INTERCEPTOR_WRITE_RANGE( + ctx, &sanitizer_handle->handle_type, + sizeof(sanitizer_handle->handle_type)); + COMMON_INTERCEPTOR_WRITE_RANGE( + ctx, &sanitizer_handle->f_handle, sanitizer_handle->handle_bytes); + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, mount_id, sizeof(*mount_id)); + } + return res; +} + +#define INIT_NAME_TO_HANDLE_AT COMMON_INTERCEPT_FUNCTION(name_to_handle_at) +#else +#define INIT_NAME_TO_HANDLE_AT +#endif + +#if SANITIZER_INTERCEPT_OPEN_BY_HANDLE_AT +INTERCEPTOR(int, open_by_handle_at, int mount_fd, struct file_handle* handle, + int flags) { + void* ctx; + COMMON_INTERCEPTOR_ENTER(ctx, open_by_handle_at, mount_fd, handle, flags); + + __sanitizer_file_handle *sanitizer_handle = + reinterpret_cast<__sanitizer_file_handle*>(handle); + COMMON_INTERCEPTOR_READ_RANGE( + ctx, &sanitizer_handle->handle_bytes, + sizeof(sanitizer_handle->handle_bytes)); + COMMON_INTERCEPTOR_READ_RANGE( + ctx, &sanitizer_handle->handle_type, + sizeof(sanitizer_handle->handle_type)); + COMMON_INTERCEPTOR_READ_RANGE( + ctx, &sanitizer_handle->f_handle, sanitizer_handle->handle_bytes); + + return REAL(open_by_handle_at)(mount_fd, handle, flags); +} + +#define INIT_OPEN_BY_HANDLE_AT COMMON_INTERCEPT_FUNCTION(open_by_handle_at) +#else +#define INIT_OPEN_BY_HANDLE_AT +#endif + +#if SANITIZER_INTERCEPT_STRLCPY +INTERCEPTOR(SIZE_T, strlcpy, char *dst, char *src, SIZE_T size) { + void *ctx; + SIZE_T res; + COMMON_INTERCEPTOR_ENTER(ctx, strlcpy, dst, src, size); + if (src) { + // Keep strnlen as macro argument, as macro may ignore it. + COMMON_INTERCEPTOR_READ_STRING( + ctx, src, Min(internal_strnlen(src, size), size - 1) + 1); + } + res = REAL(strlcpy)(dst, src, size); + COMMON_INTERCEPTOR_COPY_STRING(ctx, dst, src, internal_strlen(dst) + 1); + return res; +} + +INTERCEPTOR(SIZE_T, strlcat, char *dst, char *src, SIZE_T size) { + void *ctx; + SIZE_T len = 0; + COMMON_INTERCEPTOR_ENTER(ctx, strlcat, dst, src, size); + // src is checked in the strlcpy() interceptor + if (dst) { + len = internal_strnlen(dst, size); + COMMON_INTERCEPTOR_READ_STRING(ctx, dst, Min(len, size - 1) + 1); + } + // Reuse the rest of the code in the strlcpy() interceptor + return WRAP(strlcpy)(dst + len, src, size - len) + len; +} +#define INIT_STRLCPY \ + COMMON_INTERCEPT_FUNCTION(strlcpy); \ + COMMON_INTERCEPT_FUNCTION(strlcat); +#else +#define INIT_STRLCPY +#endif + +#if SANITIZER_INTERCEPT_MMAP +INTERCEPTOR(void *, mmap, void *addr, SIZE_T sz, int prot, int flags, int fd, + OFF_T off) { + void *ctx; + if (common_flags()->detect_write_exec) + ReportMmapWriteExec(prot, flags); + if (COMMON_INTERCEPTOR_NOTHING_IS_INITIALIZED) + return (void *)internal_mmap(addr, sz, prot, flags, fd, off); + COMMON_INTERCEPTOR_ENTER(ctx, mmap, addr, sz, prot, flags, fd, off); + COMMON_INTERCEPTOR_MMAP_IMPL(ctx, mmap, addr, sz, prot, flags, fd, off); +} + +INTERCEPTOR(int, mprotect, void *addr, SIZE_T sz, int prot) { + void *ctx; + if (common_flags()->detect_write_exec) + ReportMmapWriteExec(prot, 0); + if (COMMON_INTERCEPTOR_NOTHING_IS_INITIALIZED) + return (int)internal_mprotect(addr, sz, prot); + COMMON_INTERCEPTOR_ENTER(ctx, mprotect, addr, sz, prot); + MprotectMallocZones(addr, prot); + return REAL(mprotect)(addr, sz, prot); +} +#define INIT_MMAP \ + COMMON_INTERCEPT_FUNCTION(mmap); \ + COMMON_INTERCEPT_FUNCTION(mprotect); +#else +#define INIT_MMAP +#endif + +#if SANITIZER_INTERCEPT_MMAP64 +INTERCEPTOR(void *, mmap64, void *addr, SIZE_T sz, int prot, int flags, int fd, + OFF64_T off) { + void *ctx; + if (common_flags()->detect_write_exec) + ReportMmapWriteExec(prot, flags); + if (COMMON_INTERCEPTOR_NOTHING_IS_INITIALIZED) + return (void *)internal_mmap(addr, sz, prot, flags, fd, off); + COMMON_INTERCEPTOR_ENTER(ctx, mmap64, addr, sz, prot, flags, fd, off); + COMMON_INTERCEPTOR_MMAP_IMPL(ctx, mmap64, addr, sz, prot, flags, fd, off); +} +#define INIT_MMAP64 COMMON_INTERCEPT_FUNCTION(mmap64); +#else +#define INIT_MMAP64 +#endif + +#if SANITIZER_INTERCEPT_DEVNAME +INTERCEPTOR(char *, devname, u64 dev, u32 type) { + void *ctx; + char *name; + COMMON_INTERCEPTOR_ENTER(ctx, devname, dev, type); + name = REAL(devname)(dev, type); + if (name) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, name, internal_strlen(name) + 1); + return name; +} +#define INIT_DEVNAME COMMON_INTERCEPT_FUNCTION(devname); +#else +#define INIT_DEVNAME +#endif + +#if SANITIZER_INTERCEPT_DEVNAME_R +#if SANITIZER_NETBSD +#define DEVNAME_R_RETTYPE int +#define DEVNAME_R_SUCCESS(x) (!(x)) +#else +#define DEVNAME_R_RETTYPE char* +#define DEVNAME_R_SUCCESS(x) (x) +#endif +INTERCEPTOR(DEVNAME_R_RETTYPE, devname_r, u64 dev, u32 type, char *path, + uptr len) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, devname_r, dev, type, path, len); + DEVNAME_R_RETTYPE res = REAL(devname_r)(dev, type, path, len); + if (DEVNAME_R_SUCCESS(res)) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, path, internal_strlen(path) + 1); + return res; +} +#define INIT_DEVNAME_R COMMON_INTERCEPT_FUNCTION(devname_r); +#else +#define INIT_DEVNAME_R +#endif + +#if SANITIZER_INTERCEPT_FGETLN +INTERCEPTOR(char *, fgetln, __sanitizer_FILE *stream, SIZE_T *len) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, fgetln, stream, len); + char *str = REAL(fgetln)(stream, len); + if (str && len) { + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, len, sizeof(*len)); + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, str, *len); + } + return str; +} +#define INIT_FGETLN COMMON_INTERCEPT_FUNCTION(fgetln) +#else +#define INIT_FGETLN +#endif + +#if SANITIZER_INTERCEPT_STRMODE +INTERCEPTOR(void, strmode, u32 mode, char *bp) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, strmode, mode, bp); + REAL(strmode)(mode, bp); + if (bp) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, bp, internal_strlen(bp) + 1); +} +#define INIT_STRMODE COMMON_INTERCEPT_FUNCTION(strmode) +#else +#define INIT_STRMODE +#endif + +#if SANITIZER_INTERCEPT_TTYENT +INTERCEPTOR(struct __sanitizer_ttyent *, getttyent, void) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, getttyent); + struct __sanitizer_ttyent *ttyent = REAL(getttyent)(); + if (ttyent) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ttyent, struct_ttyent_sz); + return ttyent; +} +INTERCEPTOR(struct __sanitizer_ttyent *, getttynam, char *name) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, getttynam, name); + if (name) + COMMON_INTERCEPTOR_READ_RANGE(ctx, name, internal_strlen(name) + 1); + struct __sanitizer_ttyent *ttyent = REAL(getttynam)(name); + if (ttyent) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ttyent, struct_ttyent_sz); + return ttyent; +} +#define INIT_TTYENT \ + COMMON_INTERCEPT_FUNCTION(getttyent); \ + COMMON_INTERCEPT_FUNCTION(getttynam); +#else +#define INIT_TTYENT +#endif + +#if SANITIZER_INTERCEPT_TTYENTPATH +INTERCEPTOR(int, setttyentpath, char *path) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, setttyentpath, path); + if (path) + COMMON_INTERCEPTOR_READ_RANGE(ctx, path, internal_strlen(path) + 1); + return REAL(setttyentpath)(path); +} +#define INIT_TTYENTPATH COMMON_INTERCEPT_FUNCTION(setttyentpath); +#else +#define INIT_TTYENTPATH +#endif + +#if SANITIZER_INTERCEPT_PROTOENT +static void write_protoent(void *ctx, struct __sanitizer_protoent *p) { + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, p, sizeof(*p)); + + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, p->p_name, internal_strlen(p->p_name) + 1); + + SIZE_T pp_size = 1; // One handles the trailing \0 + + for (char **pp = p->p_aliases; *pp; ++pp, ++pp_size) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, *pp, internal_strlen(*pp) + 1); + + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, p->p_aliases, + pp_size * sizeof(char **)); +} + +INTERCEPTOR(struct __sanitizer_protoent *, getprotoent) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, getprotoent); + struct __sanitizer_protoent *p = REAL(getprotoent)(); + if (p) + write_protoent(ctx, p); + return p; +} + +INTERCEPTOR(struct __sanitizer_protoent *, getprotobyname, const char *name) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, getprotobyname, name); + if (name) + COMMON_INTERCEPTOR_READ_RANGE(ctx, name, internal_strlen(name) + 1); + struct __sanitizer_protoent *p = REAL(getprotobyname)(name); + if (p) + write_protoent(ctx, p); + return p; +} + +INTERCEPTOR(struct __sanitizer_protoent *, getprotobynumber, int proto) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, getprotobynumber, proto); + struct __sanitizer_protoent *p = REAL(getprotobynumber)(proto); + if (p) + write_protoent(ctx, p); + return p; +} +#define INIT_PROTOENT \ + COMMON_INTERCEPT_FUNCTION(getprotoent); \ + COMMON_INTERCEPT_FUNCTION(getprotobyname); \ + COMMON_INTERCEPT_FUNCTION(getprotobynumber) +#else +#define INIT_PROTOENT +#endif + +#if SANITIZER_INTERCEPT_PROTOENT_R +INTERCEPTOR(int, getprotoent_r, struct __sanitizer_protoent *result_buf, + char *buf, SIZE_T buflen, struct __sanitizer_protoent **result) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, getprotoent_r, result_buf, buf, buflen, + result); + int res = REAL(getprotoent_r)(result_buf, buf, buflen, result); + + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, result, sizeof *result); + if (!res && *result) + write_protoent(ctx, *result); + return res; +} + +INTERCEPTOR(int, getprotobyname_r, const char *name, + struct __sanitizer_protoent *result_buf, char *buf, SIZE_T buflen, + struct __sanitizer_protoent **result) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, getprotobyname_r, name, result_buf, buf, + buflen, result); + if (name) + COMMON_INTERCEPTOR_READ_RANGE(ctx, name, internal_strlen(name) + 1); + int res = REAL(getprotobyname_r)(name, result_buf, buf, buflen, result); + + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, result, sizeof *result); + if (!res && *result) + write_protoent(ctx, *result); + return res; +} + +INTERCEPTOR(int, getprotobynumber_r, int num, + struct __sanitizer_protoent *result_buf, char *buf, + SIZE_T buflen, struct __sanitizer_protoent **result) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, getprotobynumber_r, num, result_buf, buf, + buflen, result); + int res = REAL(getprotobynumber_r)(num, result_buf, buf, buflen, result); + + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, result, sizeof *result); + if (!res && *result) + write_protoent(ctx, *result); + return res; +} + +#define INIT_PROTOENT_R \ + COMMON_INTERCEPT_FUNCTION(getprotoent_r); \ + COMMON_INTERCEPT_FUNCTION(getprotobyname_r); \ + COMMON_INTERCEPT_FUNCTION(getprotobynumber_r); +#else +#define INIT_PROTOENT_R +#endif + +#if SANITIZER_INTERCEPT_NETENT +INTERCEPTOR(struct __sanitizer_netent *, getnetent) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, getnetent); + struct __sanitizer_netent *n = REAL(getnetent)(); + if (n) { + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, n, sizeof(*n)); + + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, n->n_name, internal_strlen(n->n_name) + 1); + + SIZE_T nn_size = 1; // One handles the trailing \0 + + for (char **nn = n->n_aliases; *nn; ++nn, ++nn_size) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, *nn, internal_strlen(*nn) + 1); + + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, n->n_aliases, + nn_size * sizeof(char **)); + } + return n; +} + +INTERCEPTOR(struct __sanitizer_netent *, getnetbyname, const char *name) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, getnetbyname, name); + if (name) + COMMON_INTERCEPTOR_READ_RANGE(ctx, name, internal_strlen(name) + 1); + struct __sanitizer_netent *n = REAL(getnetbyname)(name); + if (n) { + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, n, sizeof(*n)); + + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, n->n_name, internal_strlen(n->n_name) + 1); + + SIZE_T nn_size = 1; // One handles the trailing \0 + + for (char **nn = n->n_aliases; *nn; ++nn, ++nn_size) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, *nn, internal_strlen(*nn) + 1); + + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, n->n_aliases, + nn_size * sizeof(char **)); + } + return n; +} + +INTERCEPTOR(struct __sanitizer_netent *, getnetbyaddr, u32 net, int type) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, getnetbyaddr, net, type); + struct __sanitizer_netent *n = REAL(getnetbyaddr)(net, type); + if (n) { + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, n, sizeof(*n)); + + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, n->n_name, internal_strlen(n->n_name) + 1); + + SIZE_T nn_size = 1; // One handles the trailing \0 + + for (char **nn = n->n_aliases; *nn; ++nn, ++nn_size) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, *nn, internal_strlen(*nn) + 1); + + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, n->n_aliases, + nn_size * sizeof(char **)); + } + return n; +} +#define INIT_NETENT \ + COMMON_INTERCEPT_FUNCTION(getnetent); \ + COMMON_INTERCEPT_FUNCTION(getnetbyname); \ + COMMON_INTERCEPT_FUNCTION(getnetbyaddr) +#else +#define INIT_NETENT +#endif + +#if SANITIZER_INTERCEPT_GETMNTINFO +INTERCEPTOR(int, getmntinfo, void **mntbufp, int flags) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, getmntinfo, mntbufp, flags); + int cnt = REAL(getmntinfo)(mntbufp, flags); + if (cnt > 0 && mntbufp) { + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, mntbufp, sizeof(void *)); + if (*mntbufp) +#if SANITIZER_NETBSD + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, *mntbufp, cnt * struct_statvfs_sz); +#else + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, *mntbufp, cnt * struct_statfs_sz); +#endif + } + return cnt; +} +#define INIT_GETMNTINFO COMMON_INTERCEPT_FUNCTION(getmntinfo) +#else +#define INIT_GETMNTINFO +#endif + +#if SANITIZER_INTERCEPT_MI_VECTOR_HASH +INTERCEPTOR(void, mi_vector_hash, const void *key, SIZE_T len, u32 seed, + u32 hashes[3]) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, mi_vector_hash, key, len, seed, hashes); + if (key) + COMMON_INTERCEPTOR_READ_RANGE(ctx, key, len); + REAL(mi_vector_hash)(key, len, seed, hashes); + if (hashes) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, hashes, sizeof(hashes[0]) * 3); +} +#define INIT_MI_VECTOR_HASH COMMON_INTERCEPT_FUNCTION(mi_vector_hash) +#else +#define INIT_MI_VECTOR_HASH +#endif + +#if SANITIZER_INTERCEPT_SETVBUF +INTERCEPTOR(int, setvbuf, __sanitizer_FILE *stream, char *buf, int mode, + SIZE_T size) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, setvbuf, stream, buf, mode, size); + int ret = REAL(setvbuf)(stream, buf, mode, size); + if (buf) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, size); + if (stream) + unpoison_file(stream); + return ret; +} + +INTERCEPTOR(void, setbuf, __sanitizer_FILE *stream, char *buf) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, setbuf, stream, buf); + REAL(setbuf)(stream, buf); + if (buf) { + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, __sanitizer_bufsiz); + } + if (stream) + unpoison_file(stream); +} + +INTERCEPTOR(void, setbuffer, __sanitizer_FILE *stream, char *buf, SIZE_T size) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, setbuffer, stream, buf, size); + REAL(setbuffer)(stream, buf, size); + if (buf) { + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, size); + } + if (stream) + unpoison_file(stream); +} + +INTERCEPTOR(void, setlinebuf, __sanitizer_FILE *stream) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, setlinebuf, stream); + REAL(setlinebuf)(stream); + if (stream) + unpoison_file(stream); +} +#define INIT_SETVBUF COMMON_INTERCEPT_FUNCTION(setvbuf); \ + COMMON_INTERCEPT_FUNCTION(setbuf); \ + COMMON_INTERCEPT_FUNCTION(setbuffer); \ + COMMON_INTERCEPT_FUNCTION(setlinebuf) +#else +#define INIT_SETVBUF +#endif + +#if SANITIZER_INTERCEPT_GETVFSSTAT +INTERCEPTOR(int, getvfsstat, void *buf, SIZE_T bufsize, int flags) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, getvfsstat, buf, bufsize, flags); + int ret = REAL(getvfsstat)(buf, bufsize, flags); + if (buf && ret > 0) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, ret * struct_statvfs_sz); + return ret; +} +#define INIT_GETVFSSTAT COMMON_INTERCEPT_FUNCTION(getvfsstat) +#else +#define INIT_GETVFSSTAT +#endif + +#if SANITIZER_INTERCEPT_REGEX +INTERCEPTOR(int, regcomp, void *preg, const char *pattern, int cflags) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, regcomp, preg, pattern, cflags); + if (pattern) + COMMON_INTERCEPTOR_READ_RANGE(ctx, pattern, internal_strlen(pattern) + 1); + int res = REAL(regcomp)(preg, pattern, cflags); + if (!res) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, preg, struct_regex_sz); + return res; +} +INTERCEPTOR(int, regexec, const void *preg, const char *string, SIZE_T nmatch, + struct __sanitizer_regmatch *pmatch[], int eflags) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, regexec, preg, string, nmatch, pmatch, eflags); + if (preg) + COMMON_INTERCEPTOR_READ_RANGE(ctx, preg, struct_regex_sz); + if (string) + COMMON_INTERCEPTOR_READ_RANGE(ctx, string, internal_strlen(string) + 1); + int res = REAL(regexec)(preg, string, nmatch, pmatch, eflags); + if (!res && pmatch) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, pmatch, nmatch * struct_regmatch_sz); + return res; +} +INTERCEPTOR(SIZE_T, regerror, int errcode, const void *preg, char *errbuf, + SIZE_T errbuf_size) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, regerror, errcode, preg, errbuf, errbuf_size); + if (preg) + COMMON_INTERCEPTOR_READ_RANGE(ctx, preg, struct_regex_sz); + SIZE_T res = REAL(regerror)(errcode, preg, errbuf, errbuf_size); + if (errbuf) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, errbuf, internal_strlen(errbuf) + 1); + return res; +} +INTERCEPTOR(void, regfree, const void *preg) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, regfree, preg); + if (preg) + COMMON_INTERCEPTOR_READ_RANGE(ctx, preg, struct_regex_sz); + REAL(regfree)(preg); +} +#define INIT_REGEX \ + COMMON_INTERCEPT_FUNCTION(regcomp); \ + COMMON_INTERCEPT_FUNCTION_GLIBC_VER_MIN(regexec, "GLIBC_2.3.4"); \ + COMMON_INTERCEPT_FUNCTION(regerror); \ + COMMON_INTERCEPT_FUNCTION(regfree); +#else +#define INIT_REGEX +#endif + +#if SANITIZER_INTERCEPT_REGEXSUB +INTERCEPTOR(SSIZE_T, regnsub, char *buf, SIZE_T bufsiz, const char *sub, + const struct __sanitizer_regmatch *rm, const char *str) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, regnsub, buf, bufsiz, sub, rm, str); + if (sub) + COMMON_INTERCEPTOR_READ_RANGE(ctx, sub, internal_strlen(sub) + 1); + // The implementation demands and hardcodes 10 elements + if (rm) + COMMON_INTERCEPTOR_READ_RANGE(ctx, rm, 10 * struct_regmatch_sz); + if (str) + COMMON_INTERCEPTOR_READ_RANGE(ctx, str, internal_strlen(str) + 1); + SSIZE_T res = REAL(regnsub)(buf, bufsiz, sub, rm, str); + if (res > 0 && buf) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, internal_strlen(buf) + 1); + return res; +} +INTERCEPTOR(SSIZE_T, regasub, char **buf, const char *sub, + const struct __sanitizer_regmatch *rm, const char *sstr) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, regasub, buf, sub, rm, sstr); + if (sub) + COMMON_INTERCEPTOR_READ_RANGE(ctx, sub, internal_strlen(sub) + 1); + // Hardcode 10 elements as this is hardcoded size + if (rm) + COMMON_INTERCEPTOR_READ_RANGE(ctx, rm, 10 * struct_regmatch_sz); + if (sstr) + COMMON_INTERCEPTOR_READ_RANGE(ctx, sstr, internal_strlen(sstr) + 1); + SSIZE_T res = REAL(regasub)(buf, sub, rm, sstr); + if (res > 0 && buf) { + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, sizeof(char *)); + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, *buf, internal_strlen(*buf) + 1); + } + return res; +} + +#define INIT_REGEXSUB \ + COMMON_INTERCEPT_FUNCTION(regnsub); \ + COMMON_INTERCEPT_FUNCTION(regasub); +#else +#define INIT_REGEXSUB +#endif + +#if SANITIZER_INTERCEPT_FTS +INTERCEPTOR(void *, fts_open, char *const *path_argv, int options, + int (*compar)(void **, void **)) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, fts_open, path_argv, options, compar); + if (path_argv) { + for (char *const *pa = path_argv; ; ++pa) { + COMMON_INTERCEPTOR_READ_RANGE(ctx, pa, sizeof(char **)); + if (!*pa) + break; + COMMON_INTERCEPTOR_READ_RANGE(ctx, *pa, internal_strlen(*pa) + 1); + } + } + // TODO(kamil): handle compar callback + void *fts = REAL(fts_open)(path_argv, options, compar); + if (fts) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, fts, struct_FTS_sz); + return fts; +} + +INTERCEPTOR(void *, fts_read, void *ftsp) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, fts_read, ftsp); + if (ftsp) + COMMON_INTERCEPTOR_READ_RANGE(ctx, ftsp, struct_FTS_sz); + void *ftsent = REAL(fts_read)(ftsp); + if (ftsent) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ftsent, struct_FTSENT_sz); + return ftsent; +} + +INTERCEPTOR(void *, fts_children, void *ftsp, int options) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, fts_children, ftsp, options); + if (ftsp) + COMMON_INTERCEPTOR_READ_RANGE(ctx, ftsp, struct_FTS_sz); + void *ftsent = REAL(fts_children)(ftsp, options); + if (ftsent) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ftsent, struct_FTSENT_sz); + return ftsent; +} + +INTERCEPTOR(int, fts_set, void *ftsp, void *f, int options) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, fts_set, ftsp, f, options); + if (ftsp) + COMMON_INTERCEPTOR_READ_RANGE(ctx, ftsp, struct_FTS_sz); + if (f) + COMMON_INTERCEPTOR_READ_RANGE(ctx, f, struct_FTSENT_sz); + return REAL(fts_set)(ftsp, f, options); +} + +INTERCEPTOR(int, fts_close, void *ftsp) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, fts_close, ftsp); + if (ftsp) + COMMON_INTERCEPTOR_READ_RANGE(ctx, ftsp, struct_FTS_sz); + return REAL(fts_close)(ftsp); +} +#define INIT_FTS \ + COMMON_INTERCEPT_FUNCTION(fts_open); \ + COMMON_INTERCEPT_FUNCTION(fts_read); \ + COMMON_INTERCEPT_FUNCTION(fts_children); \ + COMMON_INTERCEPT_FUNCTION(fts_set); \ + COMMON_INTERCEPT_FUNCTION(fts_close); +#else +#define INIT_FTS +#endif + +#if SANITIZER_INTERCEPT_SYSCTL +INTERCEPTOR(int, sysctl, int *name, unsigned int namelen, void *oldp, + SIZE_T *oldlenp, void *newp, SIZE_T newlen) { + void *ctx; + if (COMMON_INTERCEPTOR_NOTHING_IS_INITIALIZED) + return internal_sysctl(name, namelen, oldp, oldlenp, newp, newlen); + COMMON_INTERCEPTOR_ENTER(ctx, sysctl, name, namelen, oldp, oldlenp, newp, + newlen); + if (name) + COMMON_INTERCEPTOR_READ_RANGE(ctx, name, namelen * sizeof(*name)); + if (oldlenp) + COMMON_INTERCEPTOR_READ_RANGE(ctx, oldlenp, sizeof(*oldlenp)); + if (newp && newlen) + COMMON_INTERCEPTOR_READ_RANGE(ctx, newp, newlen); + int res = REAL(sysctl)(name, namelen, oldp, oldlenp, newp, newlen); + if (!res) { + if (oldlenp) { + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, oldlenp, sizeof(*oldlenp)); + if (oldp) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, oldp, *oldlenp); + } + } + return res; +} + +INTERCEPTOR(int, sysctlbyname, char *sname, void *oldp, SIZE_T *oldlenp, + void *newp, SIZE_T newlen) { + void *ctx; + if (COMMON_INTERCEPTOR_NOTHING_IS_INITIALIZED) + return internal_sysctlbyname(sname, oldp, oldlenp, newp, newlen); + COMMON_INTERCEPTOR_ENTER(ctx, sysctlbyname, sname, oldp, oldlenp, newp, + newlen); + if (sname) + COMMON_INTERCEPTOR_READ_RANGE(ctx, sname, internal_strlen(sname) + 1); + if (oldlenp) + COMMON_INTERCEPTOR_READ_RANGE(ctx, oldlenp, sizeof(*oldlenp)); + if (newp && newlen) + COMMON_INTERCEPTOR_READ_RANGE(ctx, newp, newlen); + int res = REAL(sysctlbyname)(sname, oldp, oldlenp, newp, newlen); + if (!res) { + if (oldlenp) { + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, oldlenp, sizeof(*oldlenp)); + if (oldp) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, oldp, *oldlenp); + } + } + return res; +} + +INTERCEPTOR(int, sysctlnametomib, const char *sname, int *name, + SIZE_T *namelenp) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, sysctlnametomib, sname, name, namelenp); + if (sname) + COMMON_INTERCEPTOR_READ_RANGE(ctx, sname, internal_strlen(sname) + 1); + if (namelenp) + COMMON_INTERCEPTOR_READ_RANGE(ctx, namelenp, sizeof(*namelenp)); + int res = REAL(sysctlnametomib)(sname, name, namelenp); + if (!res) { + if (namelenp) { + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, namelenp, sizeof(*namelenp)); + if (name) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, name, *namelenp * sizeof(*name)); + } + } + return res; +} + +#define INIT_SYSCTL \ + COMMON_INTERCEPT_FUNCTION(sysctl); \ + COMMON_INTERCEPT_FUNCTION(sysctlbyname); \ + COMMON_INTERCEPT_FUNCTION(sysctlnametomib); +#else +#define INIT_SYSCTL +#endif + +#if SANITIZER_INTERCEPT_ASYSCTL +INTERCEPTOR(void *, asysctl, const int *name, SIZE_T namelen, SIZE_T *len) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, asysctl, name, namelen, len); + if (name) + COMMON_INTERCEPTOR_READ_RANGE(ctx, name, sizeof(*name) * namelen); + void *res = REAL(asysctl)(name, namelen, len); + if (res && len) { + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, len, sizeof(*len)); + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, *len); + } + return res; +} + +INTERCEPTOR(void *, asysctlbyname, const char *sname, SIZE_T *len) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, asysctlbyname, sname, len); + if (sname) + COMMON_INTERCEPTOR_READ_RANGE(ctx, sname, internal_strlen(sname) + 1); + void *res = REAL(asysctlbyname)(sname, len); + if (res && len) { + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, len, sizeof(*len)); + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, *len); + } + return res; +} +#define INIT_ASYSCTL \ + COMMON_INTERCEPT_FUNCTION(asysctl); \ + COMMON_INTERCEPT_FUNCTION(asysctlbyname); +#else +#define INIT_ASYSCTL +#endif + +#if SANITIZER_INTERCEPT_SYSCTLGETMIBINFO +INTERCEPTOR(int, sysctlgetmibinfo, char *sname, int *name, + unsigned int *namelenp, char *cname, SIZE_T *csz, void **rnode, + int v) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, sysctlgetmibinfo, sname, name, namelenp, cname, + csz, rnode, v); + if (sname) + COMMON_INTERCEPTOR_READ_RANGE(ctx, sname, internal_strlen(sname) + 1); + if (namelenp) + COMMON_INTERCEPTOR_READ_RANGE(ctx, namelenp, sizeof(*namelenp)); + if (csz) + COMMON_INTERCEPTOR_READ_RANGE(ctx, csz, sizeof(*csz)); + // Skip rnode, it's rarely used and not trivial to sanitize + // It's also used mostly internally + int res = REAL(sysctlgetmibinfo)(sname, name, namelenp, cname, csz, rnode, v); + if (!res) { + if (namelenp) { + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, namelenp, sizeof(*namelenp)); + if (name) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, name, *namelenp * sizeof(*name)); + } + if (csz) { + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, csz, sizeof(*csz)); + if (cname) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, cname, *csz); + } + } + return res; +} +#define INIT_SYSCTLGETMIBINFO \ + COMMON_INTERCEPT_FUNCTION(sysctlgetmibinfo); +#else +#define INIT_SYSCTLGETMIBINFO +#endif + +#if SANITIZER_INTERCEPT_NL_LANGINFO +INTERCEPTOR(char *, nl_langinfo, long item) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, nl_langinfo, item); + char *ret = REAL(nl_langinfo)(item); + if (ret) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ret, internal_strlen(ret) + 1); + return ret; +} +#define INIT_NL_LANGINFO COMMON_INTERCEPT_FUNCTION(nl_langinfo) +#else +#define INIT_NL_LANGINFO +#endif + +#if SANITIZER_INTERCEPT_MODCTL +INTERCEPTOR(int, modctl, int operation, void *argp) { + void *ctx; + int ret; + COMMON_INTERCEPTOR_ENTER(ctx, modctl, operation, argp); + + if (operation == modctl_load) { + if (argp) { + __sanitizer_modctl_load_t *ml = (__sanitizer_modctl_load_t *)argp; + COMMON_INTERCEPTOR_READ_RANGE(ctx, ml, sizeof(*ml)); + if (ml->ml_filename) + COMMON_INTERCEPTOR_READ_RANGE(ctx, ml->ml_filename, + internal_strlen(ml->ml_filename) + 1); + if (ml->ml_props) + COMMON_INTERCEPTOR_READ_RANGE(ctx, ml->ml_props, ml->ml_propslen); + } + ret = REAL(modctl)(operation, argp); + } else if (operation == modctl_unload) { + if (argp) { + const char *name = (const char *)argp; + COMMON_INTERCEPTOR_READ_RANGE(ctx, name, internal_strlen(name) + 1); + } + ret = REAL(modctl)(operation, argp); + } else if (operation == modctl_stat) { + uptr iov_len; + struct __sanitizer_iovec *iov = (struct __sanitizer_iovec *)argp; + if (iov) { + COMMON_INTERCEPTOR_READ_RANGE(ctx, iov, sizeof(*iov)); + iov_len = iov->iov_len; + } + ret = REAL(modctl)(operation, argp); + if (iov) + COMMON_INTERCEPTOR_WRITE_RANGE( + ctx, iov->iov_base, Min(iov_len, iov->iov_len)); + } else if (operation == modctl_exists) { + ret = REAL(modctl)(operation, argp); + } else { + ret = REAL(modctl)(operation, argp); + } + + return ret; +} +#define INIT_MODCTL COMMON_INTERCEPT_FUNCTION(modctl) +#else +#define INIT_MODCTL +#endif + +#if SANITIZER_INTERCEPT_STRTONUM +INTERCEPTOR(long long, strtonum, const char *nptr, long long minval, + long long maxval, const char **errstr) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, strtonum, nptr, minval, maxval, errstr); + + // TODO(kamil): Implement strtoll as a common inteceptor + char *real_endptr; + long long ret = (long long)REAL(strtoimax)(nptr, &real_endptr, 10); + StrtolFixAndCheck(ctx, nptr, nullptr, real_endptr, 10); + + ret = REAL(strtonum)(nptr, minval, maxval, errstr); + if (errstr) { + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, errstr, sizeof(const char *)); + if (*errstr) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, *errstr, internal_strlen(*errstr) + 1); + } + return ret; +} +#define INIT_STRTONUM COMMON_INTERCEPT_FUNCTION(strtonum) +#else +#define INIT_STRTONUM +#endif + +#if SANITIZER_INTERCEPT_FPARSELN +INTERCEPTOR(char *, fparseln, __sanitizer_FILE *stream, SIZE_T *len, + SIZE_T *lineno, const char delim[3], int flags) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, fparseln, stream, len, lineno, delim, flags); + if (lineno) + COMMON_INTERCEPTOR_READ_RANGE(ctx, lineno, sizeof(*lineno)); + if (delim) + COMMON_INTERCEPTOR_READ_RANGE(ctx, delim, sizeof(delim[0]) * 3); + char *ret = REAL(fparseln)(stream, len, lineno, delim, flags); + if (ret) { + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ret, internal_strlen(ret) + 1); + if (len) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, len, sizeof(*len)); + if (lineno) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, lineno, sizeof(*lineno)); + } + return ret; +} +#define INIT_FPARSELN COMMON_INTERCEPT_FUNCTION(fparseln) +#else +#define INIT_FPARSELN +#endif + +#if SANITIZER_INTERCEPT_STATVFS1 +INTERCEPTOR(int, statvfs1, const char *path, void *buf, int flags) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, statvfs1, path, buf, flags); + if (path) COMMON_INTERCEPTOR_READ_RANGE(ctx, path, internal_strlen(path) + 1); + int res = REAL(statvfs1)(path, buf, flags); + if (!res) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, struct_statvfs_sz); + return res; +} +INTERCEPTOR(int, fstatvfs1, int fd, void *buf, int flags) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, fstatvfs1, fd, buf, flags); + COMMON_INTERCEPTOR_FD_ACCESS(ctx, fd); + int res = REAL(fstatvfs1)(fd, buf, flags); + if (!res) { + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, struct_statvfs_sz); + if (fd >= 0) + COMMON_INTERCEPTOR_FD_ACQUIRE(ctx, fd); + } + return res; +} +#define INIT_STATVFS1 \ + COMMON_INTERCEPT_FUNCTION(statvfs1); \ + COMMON_INTERCEPT_FUNCTION(fstatvfs1); +#else +#define INIT_STATVFS1 +#endif + +#if SANITIZER_INTERCEPT_STRTOI +INTERCEPTOR(INTMAX_T, strtoi, const char *nptr, char **endptr, int base, + INTMAX_T low, INTMAX_T high, int *rstatus) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, strtoi, nptr, endptr, base, low, high, rstatus); + char *real_endptr; + INTMAX_T ret = REAL(strtoi)(nptr, &real_endptr, base, low, high, rstatus); + StrtolFixAndCheck(ctx, nptr, endptr, real_endptr, base); + if (rstatus) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, rstatus, sizeof(*rstatus)); + return ret; +} + +INTERCEPTOR(UINTMAX_T, strtou, const char *nptr, char **endptr, int base, + UINTMAX_T low, UINTMAX_T high, int *rstatus) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, strtou, nptr, endptr, base, low, high, rstatus); + char *real_endptr; + UINTMAX_T ret = REAL(strtou)(nptr, &real_endptr, base, low, high, rstatus); + StrtolFixAndCheck(ctx, nptr, endptr, real_endptr, base); + if (rstatus) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, rstatus, sizeof(*rstatus)); + return ret; +} +#define INIT_STRTOI \ + COMMON_INTERCEPT_FUNCTION(strtoi); \ + COMMON_INTERCEPT_FUNCTION(strtou) +#else +#define INIT_STRTOI +#endif + +#if SANITIZER_INTERCEPT_CAPSICUM +#define CAP_RIGHTS_INIT_INTERCEPTOR(cap_rights_init, rights, ...) \ + { \ + void *ctx; \ + COMMON_INTERCEPTOR_ENTER(ctx, cap_rights_init, rights, ##__VA_ARGS__); \ + if (rights) \ + COMMON_INTERCEPTOR_READ_RANGE(ctx, rights, sizeof(*rights)); \ + __sanitizer_cap_rights_t *ret = \ + REAL(cap_rights_init)(rights, ##__VA_ARGS__); \ + if (ret) \ + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ret, sizeof(*ret)); \ + return ret; \ + } + +#define CAP_RIGHTS_SET_INTERCEPTOR(cap_rights_set, rights, ...) \ + { \ + void *ctx; \ + COMMON_INTERCEPTOR_ENTER(ctx, cap_rights_set, rights, ##__VA_ARGS__); \ + if (rights) \ + COMMON_INTERCEPTOR_READ_RANGE(ctx, rights, sizeof(*rights)); \ + __sanitizer_cap_rights_t *ret = \ + REAL(cap_rights_set)(rights, ##__VA_ARGS__); \ + if (ret) \ + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ret, sizeof(*ret)); \ + return ret; \ + } + +#define CAP_RIGHTS_CLEAR_INTERCEPTOR(cap_rights_clear, rights, ...) \ + { \ + void *ctx; \ + COMMON_INTERCEPTOR_ENTER(ctx, cap_rights_clear, rights, ##__VA_ARGS__); \ + if (rights) \ + COMMON_INTERCEPTOR_READ_RANGE(ctx, rights, sizeof(*rights)); \ + __sanitizer_cap_rights_t *ret = \ + REAL(cap_rights_clear)(rights, ##__VA_ARGS__); \ + if (ret) \ + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ret, sizeof(*ret)); \ + return ret; \ + } + +#define CAP_RIGHTS_IS_SET_INTERCEPTOR(cap_rights_is_set, rights, ...) \ + { \ + void *ctx; \ + COMMON_INTERCEPTOR_ENTER(ctx, cap_rights_is_set, rights, ##__VA_ARGS__); \ + if (rights) \ + COMMON_INTERCEPTOR_READ_RANGE(ctx, rights, sizeof(*rights)); \ + return REAL(cap_rights_is_set)(rights, ##__VA_ARGS__); \ + } + +INTERCEPTOR(__sanitizer_cap_rights_t *, cap_rights_init, + __sanitizer_cap_rights_t *rights) { + CAP_RIGHTS_INIT_INTERCEPTOR(cap_rights_init, rights); +} + +INTERCEPTOR(__sanitizer_cap_rights_t *, cap_rights_set, + __sanitizer_cap_rights_t *rights) { + CAP_RIGHTS_SET_INTERCEPTOR(cap_rights_set, rights); +} + +INTERCEPTOR(__sanitizer_cap_rights_t *, cap_rights_clear, + __sanitizer_cap_rights_t *rights) { + CAP_RIGHTS_CLEAR_INTERCEPTOR(cap_rights_clear, rights); +} + +INTERCEPTOR(bool, cap_rights_is_set, + __sanitizer_cap_rights_t *rights) { + CAP_RIGHTS_IS_SET_INTERCEPTOR(cap_rights_is_set, rights); +} + +INTERCEPTOR(int, cap_rights_limit, int fd, + const __sanitizer_cap_rights_t *rights) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, cap_rights_limit, fd, rights); + if (rights) + COMMON_INTERCEPTOR_READ_RANGE(ctx, rights, sizeof(*rights)); + + return REAL(cap_rights_limit)(fd, rights); +} + +INTERCEPTOR(int, cap_rights_get, int fd, __sanitizer_cap_rights_t *rights) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, cap_rights_get, fd, rights); + int ret = REAL(cap_rights_get)(fd, rights); + if (!ret && rights) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, rights, sizeof(*rights)); + + return ret; +} + +INTERCEPTOR(bool, cap_rights_is_valid, const __sanitizer_cap_rights_t *rights) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, cap_rights_is_valid, rights); + if (rights) + COMMON_INTERCEPTOR_READ_RANGE(ctx, rights, sizeof(*rights)); + + return REAL(cap_rights_is_valid(rights)); +} + +INTERCEPTOR(__sanitizer_cap_rights *, cap_rights_merge, + __sanitizer_cap_rights *dst, const __sanitizer_cap_rights *src) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, cap_rights_merge, dst, src); + if (src) + COMMON_INTERCEPTOR_READ_RANGE(ctx, src, sizeof(*src)); + + __sanitizer_cap_rights *ret = REAL(cap_rights_merge)(dst, src); + if (dst) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, dst, sizeof(*dst)); + + return ret; +} + +INTERCEPTOR(__sanitizer_cap_rights *, cap_rights_remove, + __sanitizer_cap_rights *dst, const __sanitizer_cap_rights *src) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, cap_rights_remove, dst, src); + if (src) + COMMON_INTERCEPTOR_READ_RANGE(ctx, src, sizeof(*src)); + + __sanitizer_cap_rights *ret = REAL(cap_rights_remove)(dst, src); + if (dst) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, dst, sizeof(*dst)); + + return ret; +} + +INTERCEPTOR(bool, cap_rights_contains, const __sanitizer_cap_rights *big, + const __sanitizer_cap_rights *little) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, cap_rights_contains, big, little); + if (little) + COMMON_INTERCEPTOR_READ_RANGE(ctx, little, sizeof(*little)); + if (big) + COMMON_INTERCEPTOR_READ_RANGE(ctx, big, sizeof(*big)); + + return REAL(cap_rights_contains)(big, little); +} + +INTERCEPTOR(int, cap_ioctls_limit, int fd, const uptr *cmds, SIZE_T ncmds) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, cap_ioctls_limit, fd, cmds, ncmds); + if (cmds) + COMMON_INTERCEPTOR_READ_RANGE(ctx, cmds, sizeof(*cmds) * ncmds); + + return REAL(cap_ioctls_limit)(fd, cmds, ncmds); +} + +INTERCEPTOR(int, cap_ioctls_get, int fd, uptr *cmds, SIZE_T maxcmds) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, cap_ioctls_get, fd, cmds, maxcmds); + int ret = REAL(cap_ioctls_get)(fd, cmds, maxcmds); + if (!ret && cmds) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, cmds, sizeof(*cmds) * maxcmds); + + return ret; +} +#define INIT_CAPSICUM \ + COMMON_INTERCEPT_FUNCTION(cap_rights_init); \ + COMMON_INTERCEPT_FUNCTION(cap_rights_set); \ + COMMON_INTERCEPT_FUNCTION(cap_rights_clear); \ + COMMON_INTERCEPT_FUNCTION(cap_rights_is_set); \ + COMMON_INTERCEPT_FUNCTION(cap_rights_get); \ + COMMON_INTERCEPT_FUNCTION(cap_rights_limit); \ + COMMON_INTERCEPT_FUNCTION(cap_rights_contains); \ + COMMON_INTERCEPT_FUNCTION(cap_rights_remove); \ + COMMON_INTERCEPT_FUNCTION(cap_rights_merge); \ + COMMON_INTERCEPT_FUNCTION(cap_rights_is_valid); \ + COMMON_INTERCEPT_FUNCTION(cap_ioctls_get); \ + COMMON_INTERCEPT_FUNCTION(cap_ioctls_limit) +#else +#define INIT_CAPSICUM +#endif + +#if SANITIZER_INTERCEPT_SHA1 +INTERCEPTOR(void, SHA1Init, void *context) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, SHA1Init, context); + REAL(SHA1Init)(context); + if (context) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, context, SHA1_CTX_sz); +} +INTERCEPTOR(void, SHA1Update, void *context, const u8 *data, unsigned len) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, SHA1Update, context, data, len); + if (data && len > 0) + COMMON_INTERCEPTOR_READ_RANGE(ctx, data, len); + if (context) + COMMON_INTERCEPTOR_READ_RANGE(ctx, context, SHA1_CTX_sz); + REAL(SHA1Update)(context, data, len); + if (context) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, context, SHA1_CTX_sz); +} +INTERCEPTOR(void, SHA1Final, u8 digest[20], void *context) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, SHA1Final, digest, context); + if (context) + COMMON_INTERCEPTOR_READ_RANGE(ctx, context, SHA1_CTX_sz); + REAL(SHA1Final)(digest, context); + if (digest) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, digest, sizeof(u8) * 20); +} +INTERCEPTOR(void, SHA1Transform, u32 state[5], u8 buffer[64]) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, SHA1Transform, state, buffer); + if (state) + COMMON_INTERCEPTOR_READ_RANGE(ctx, state, sizeof(u32) * 5); + if (buffer) + COMMON_INTERCEPTOR_READ_RANGE(ctx, buffer, sizeof(u8) * 64); + REAL(SHA1Transform)(state, buffer); + if (state) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, state, sizeof(u32) * 5); +} +INTERCEPTOR(char *, SHA1End, void *context, char *buf) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, SHA1End, context, buf); + if (context) + COMMON_INTERCEPTOR_READ_RANGE(ctx, context, SHA1_CTX_sz); + char *ret = REAL(SHA1End)(context, buf); + if (ret) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ret, SHA1_return_length); + return ret; +} +INTERCEPTOR(char *, SHA1File, char *filename, char *buf) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, SHA1File, filename, buf); + if (filename) + COMMON_INTERCEPTOR_READ_RANGE(ctx, filename, internal_strlen(filename) + 1); + char *ret = REAL(SHA1File)(filename, buf); + if (ret) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ret, SHA1_return_length); + return ret; +} +INTERCEPTOR(char *, SHA1FileChunk, char *filename, char *buf, OFF_T offset, + OFF_T length) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, SHA1FileChunk, filename, buf, offset, length); + if (filename) + COMMON_INTERCEPTOR_READ_RANGE(ctx, filename, internal_strlen(filename) + 1); + char *ret = REAL(SHA1FileChunk)(filename, buf, offset, length); + if (ret) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ret, SHA1_return_length); + return ret; +} +INTERCEPTOR(char *, SHA1Data, u8 *data, SIZE_T len, char *buf) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, SHA1Data, data, len, buf); + if (data) + COMMON_INTERCEPTOR_READ_RANGE(ctx, data, len); + char *ret = REAL(SHA1Data)(data, len, buf); + if (ret) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ret, SHA1_return_length); + return ret; +} +#define INIT_SHA1 \ + COMMON_INTERCEPT_FUNCTION(SHA1Init); \ + COMMON_INTERCEPT_FUNCTION(SHA1Update); \ + COMMON_INTERCEPT_FUNCTION(SHA1Final); \ + COMMON_INTERCEPT_FUNCTION(SHA1Transform); \ + COMMON_INTERCEPT_FUNCTION(SHA1End); \ + COMMON_INTERCEPT_FUNCTION(SHA1File); \ + COMMON_INTERCEPT_FUNCTION(SHA1FileChunk); \ + COMMON_INTERCEPT_FUNCTION(SHA1Data) +#else +#define INIT_SHA1 +#endif + +#if SANITIZER_INTERCEPT_MD4 +INTERCEPTOR(void, MD4Init, void *context) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, MD4Init, context); + REAL(MD4Init)(context); + if (context) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, context, MD4_CTX_sz); +} + +INTERCEPTOR(void, MD4Update, void *context, const unsigned char *data, + unsigned int len) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, MD4Update, context, data, len); + if (data && len > 0) + COMMON_INTERCEPTOR_READ_RANGE(ctx, data, len); + if (context) + COMMON_INTERCEPTOR_READ_RANGE(ctx, context, MD4_CTX_sz); + REAL(MD4Update)(context, data, len); + if (context) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, context, MD4_CTX_sz); +} + +INTERCEPTOR(void, MD4Final, unsigned char digest[16], void *context) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, MD4Final, digest, context); + if (context) + COMMON_INTERCEPTOR_READ_RANGE(ctx, context, MD4_CTX_sz); + REAL(MD4Final)(digest, context); + if (digest) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, digest, sizeof(unsigned char) * 16); +} + +INTERCEPTOR(char *, MD4End, void *context, char *buf) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, MD4End, context, buf); + if (context) + COMMON_INTERCEPTOR_READ_RANGE(ctx, context, MD4_CTX_sz); + char *ret = REAL(MD4End)(context, buf); + if (ret) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ret, MD4_return_length); + return ret; +} + +INTERCEPTOR(char *, MD4File, const char *filename, char *buf) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, MD4File, filename, buf); + if (filename) + COMMON_INTERCEPTOR_READ_RANGE(ctx, filename, internal_strlen(filename) + 1); + char *ret = REAL(MD4File)(filename, buf); + if (ret) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ret, MD4_return_length); + return ret; +} + +INTERCEPTOR(char *, MD4Data, const unsigned char *data, unsigned int len, + char *buf) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, MD4Data, data, len, buf); + if (data && len > 0) + COMMON_INTERCEPTOR_READ_RANGE(ctx, data, len); + char *ret = REAL(MD4Data)(data, len, buf); + if (ret) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ret, MD4_return_length); + return ret; +} + +#define INIT_MD4 \ + COMMON_INTERCEPT_FUNCTION(MD4Init); \ + COMMON_INTERCEPT_FUNCTION(MD4Update); \ + COMMON_INTERCEPT_FUNCTION(MD4Final); \ + COMMON_INTERCEPT_FUNCTION(MD4End); \ + COMMON_INTERCEPT_FUNCTION(MD4File); \ + COMMON_INTERCEPT_FUNCTION(MD4Data) +#else +#define INIT_MD4 +#endif + +#if SANITIZER_INTERCEPT_RMD160 +INTERCEPTOR(void, RMD160Init, void *context) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, RMD160Init, context); + REAL(RMD160Init)(context); + if (context) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, context, RMD160_CTX_sz); +} +INTERCEPTOR(void, RMD160Update, void *context, const u8 *data, unsigned len) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, RMD160Update, context, data, len); + if (data && len > 0) + COMMON_INTERCEPTOR_READ_RANGE(ctx, data, len); + if (context) + COMMON_INTERCEPTOR_READ_RANGE(ctx, context, RMD160_CTX_sz); + REAL(RMD160Update)(context, data, len); + if (context) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, context, RMD160_CTX_sz); +} +INTERCEPTOR(void, RMD160Final, u8 digest[20], void *context) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, RMD160Final, digest, context); + if (context) + COMMON_INTERCEPTOR_READ_RANGE(ctx, context, RMD160_CTX_sz); + REAL(RMD160Final)(digest, context); + if (digest) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, digest, sizeof(u8) * 20); +} +INTERCEPTOR(void, RMD160Transform, u32 state[5], u16 buffer[16]) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, RMD160Transform, state, buffer); + if (state) + COMMON_INTERCEPTOR_READ_RANGE(ctx, state, sizeof(u32) * 5); + if (buffer) + COMMON_INTERCEPTOR_READ_RANGE(ctx, buffer, sizeof(u32) * 16); + REAL(RMD160Transform)(state, buffer); + if (state) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, state, sizeof(u32) * 5); +} +INTERCEPTOR(char *, RMD160End, void *context, char *buf) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, RMD160End, context, buf); + if (context) + COMMON_INTERCEPTOR_READ_RANGE(ctx, context, RMD160_CTX_sz); + char *ret = REAL(RMD160End)(context, buf); + if (ret) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ret, RMD160_return_length); + return ret; +} +INTERCEPTOR(char *, RMD160File, char *filename, char *buf) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, RMD160File, filename, buf); + if (filename) + COMMON_INTERCEPTOR_READ_RANGE(ctx, filename, internal_strlen(filename) + 1); + char *ret = REAL(RMD160File)(filename, buf); + if (ret) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ret, RMD160_return_length); + return ret; +} +INTERCEPTOR(char *, RMD160FileChunk, char *filename, char *buf, OFF_T offset, + OFF_T length) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, RMD160FileChunk, filename, buf, offset, length); + if (filename) + COMMON_INTERCEPTOR_READ_RANGE(ctx, filename, internal_strlen(filename) + 1); + char *ret = REAL(RMD160FileChunk)(filename, buf, offset, length); + if (ret) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ret, RMD160_return_length); + return ret; +} +INTERCEPTOR(char *, RMD160Data, u8 *data, SIZE_T len, char *buf) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, RMD160Data, data, len, buf); + if (data && len > 0) + COMMON_INTERCEPTOR_READ_RANGE(ctx, data, len); + char *ret = REAL(RMD160Data)(data, len, buf); + if (ret) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ret, RMD160_return_length); + return ret; +} +#define INIT_RMD160 \ + COMMON_INTERCEPT_FUNCTION(RMD160Init); \ + COMMON_INTERCEPT_FUNCTION(RMD160Update); \ + COMMON_INTERCEPT_FUNCTION(RMD160Final); \ + COMMON_INTERCEPT_FUNCTION(RMD160Transform); \ + COMMON_INTERCEPT_FUNCTION(RMD160End); \ + COMMON_INTERCEPT_FUNCTION(RMD160File); \ + COMMON_INTERCEPT_FUNCTION(RMD160FileChunk); \ + COMMON_INTERCEPT_FUNCTION(RMD160Data) +#else +#define INIT_RMD160 +#endif + +#if SANITIZER_INTERCEPT_MD5 +INTERCEPTOR(void, MD5Init, void *context) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, MD5Init, context); + REAL(MD5Init)(context); + if (context) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, context, MD5_CTX_sz); +} + +INTERCEPTOR(void, MD5Update, void *context, const unsigned char *data, + unsigned int len) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, MD5Update, context, data, len); + if (data && len > 0) + COMMON_INTERCEPTOR_READ_RANGE(ctx, data, len); + if (context) + COMMON_INTERCEPTOR_READ_RANGE(ctx, context, MD5_CTX_sz); + REAL(MD5Update)(context, data, len); + if (context) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, context, MD5_CTX_sz); +} + +INTERCEPTOR(void, MD5Final, unsigned char digest[16], void *context) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, MD5Final, digest, context); + if (context) + COMMON_INTERCEPTOR_READ_RANGE(ctx, context, MD5_CTX_sz); + REAL(MD5Final)(digest, context); + if (digest) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, digest, sizeof(unsigned char) * 16); +} + +INTERCEPTOR(char *, MD5End, void *context, char *buf) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, MD5End, context, buf); + if (context) + COMMON_INTERCEPTOR_READ_RANGE(ctx, context, MD5_CTX_sz); + char *ret = REAL(MD5End)(context, buf); + if (ret) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ret, MD5_return_length); + return ret; +} + +INTERCEPTOR(char *, MD5File, const char *filename, char *buf) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, MD5File, filename, buf); + if (filename) + COMMON_INTERCEPTOR_READ_RANGE(ctx, filename, internal_strlen(filename) + 1); + char *ret = REAL(MD5File)(filename, buf); + if (ret) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ret, MD5_return_length); + return ret; +} + +INTERCEPTOR(char *, MD5Data, const unsigned char *data, unsigned int len, + char *buf) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, MD5Data, data, len, buf); + if (data && len > 0) + COMMON_INTERCEPTOR_READ_RANGE(ctx, data, len); + char *ret = REAL(MD5Data)(data, len, buf); + if (ret) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ret, MD5_return_length); + return ret; +} + +#define INIT_MD5 \ + COMMON_INTERCEPT_FUNCTION(MD5Init); \ + COMMON_INTERCEPT_FUNCTION(MD5Update); \ + COMMON_INTERCEPT_FUNCTION(MD5Final); \ + COMMON_INTERCEPT_FUNCTION(MD5End); \ + COMMON_INTERCEPT_FUNCTION(MD5File); \ + COMMON_INTERCEPT_FUNCTION(MD5Data) +#else +#define INIT_MD5 +#endif + +#if SANITIZER_INTERCEPT_FSEEK +INTERCEPTOR(int, fseek, __sanitizer_FILE *stream, long int offset, int whence) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, fseek, stream, offset, whence); + return REAL(fseek)(stream, offset, whence); +} +INTERCEPTOR(int, fseeko, __sanitizer_FILE *stream, OFF_T offset, int whence) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, fseeko, stream, offset, whence); + return REAL(fseeko)(stream, offset, whence); +} +INTERCEPTOR(long int, ftell, __sanitizer_FILE *stream) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, ftell, stream); + return REAL(ftell)(stream); +} +INTERCEPTOR(OFF_T, ftello, __sanitizer_FILE *stream) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, ftello, stream); + return REAL(ftello)(stream); +} +INTERCEPTOR(void, rewind, __sanitizer_FILE *stream) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, rewind, stream); + return REAL(rewind)(stream); +} +INTERCEPTOR(int, fgetpos, __sanitizer_FILE *stream, void *pos) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, fgetpos, stream, pos); + int ret = REAL(fgetpos)(stream, pos); + if (pos && !ret) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, pos, fpos_t_sz); + return ret; +} +INTERCEPTOR(int, fsetpos, __sanitizer_FILE *stream, const void *pos) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, fsetpos, stream, pos); + if (pos) + COMMON_INTERCEPTOR_READ_RANGE(ctx, pos, fpos_t_sz); + return REAL(fsetpos)(stream, pos); +} +#define INIT_FSEEK \ + COMMON_INTERCEPT_FUNCTION(fseek); \ + COMMON_INTERCEPT_FUNCTION(fseeko); \ + COMMON_INTERCEPT_FUNCTION(ftell); \ + COMMON_INTERCEPT_FUNCTION(ftello); \ + COMMON_INTERCEPT_FUNCTION(rewind); \ + COMMON_INTERCEPT_FUNCTION(fgetpos); \ + COMMON_INTERCEPT_FUNCTION(fsetpos) +#else +#define INIT_FSEEK +#endif + +#if SANITIZER_INTERCEPT_MD2 +INTERCEPTOR(void, MD2Init, void *context) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, MD2Init, context); + REAL(MD2Init)(context); + if (context) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, context, MD2_CTX_sz); +} + +INTERCEPTOR(void, MD2Update, void *context, const unsigned char *data, + unsigned int len) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, MD2Update, context, data, len); + if (data && len > 0) + COMMON_INTERCEPTOR_READ_RANGE(ctx, data, len); + if (context) + COMMON_INTERCEPTOR_READ_RANGE(ctx, context, MD2_CTX_sz); + REAL(MD2Update)(context, data, len); + if (context) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, context, MD2_CTX_sz); +} + +INTERCEPTOR(void, MD2Final, unsigned char digest[16], void *context) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, MD2Final, digest, context); + if (context) + COMMON_INTERCEPTOR_READ_RANGE(ctx, context, MD2_CTX_sz); + REAL(MD2Final)(digest, context); + if (digest) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, digest, sizeof(unsigned char) * 16); +} + +INTERCEPTOR(char *, MD2End, void *context, char *buf) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, MD2End, context, buf); + if (context) + COMMON_INTERCEPTOR_READ_RANGE(ctx, context, MD2_CTX_sz); + char *ret = REAL(MD2End)(context, buf); + if (ret) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ret, MD2_return_length); + return ret; +} + +INTERCEPTOR(char *, MD2File, const char *filename, char *buf) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, MD2File, filename, buf); + if (filename) + COMMON_INTERCEPTOR_READ_RANGE(ctx, filename, internal_strlen(filename) + 1); + char *ret = REAL(MD2File)(filename, buf); + if (ret) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ret, MD2_return_length); + return ret; +} + +INTERCEPTOR(char *, MD2Data, const unsigned char *data, unsigned int len, + char *buf) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, MD2Data, data, len, buf); + if (data && len > 0) + COMMON_INTERCEPTOR_READ_RANGE(ctx, data, len); + char *ret = REAL(MD2Data)(data, len, buf); + if (ret) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ret, MD2_return_length); + return ret; +} + +#define INIT_MD2 \ + COMMON_INTERCEPT_FUNCTION(MD2Init); \ + COMMON_INTERCEPT_FUNCTION(MD2Update); \ + COMMON_INTERCEPT_FUNCTION(MD2Final); \ + COMMON_INTERCEPT_FUNCTION(MD2End); \ + COMMON_INTERCEPT_FUNCTION(MD2File); \ + COMMON_INTERCEPT_FUNCTION(MD2Data) +#else +#define INIT_MD2 +#endif + +#if SANITIZER_INTERCEPT_SHA2 +#define SHA2_INTERCEPTORS(LEN, SHA2_STATE_T) \ + INTERCEPTOR(void, SHA##LEN##_Init, void *context) { \ + void *ctx; \ + COMMON_INTERCEPTOR_ENTER(ctx, SHA##LEN##_Init, context); \ + REAL(SHA##LEN##_Init)(context); \ + if (context) \ + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, context, SHA##LEN##_CTX_sz); \ + } \ + INTERCEPTOR(void, SHA##LEN##_Update, void *context, \ + const u8 *data, SIZE_T len) { \ + void *ctx; \ + COMMON_INTERCEPTOR_ENTER(ctx, SHA##LEN##_Update, context, data, len); \ + if (data && len > 0) \ + COMMON_INTERCEPTOR_READ_RANGE(ctx, data, len); \ + if (context) \ + COMMON_INTERCEPTOR_READ_RANGE(ctx, context, SHA##LEN##_CTX_sz); \ + REAL(SHA##LEN##_Update)(context, data, len); \ + if (context) \ + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, context, SHA##LEN##_CTX_sz); \ + } \ + INTERCEPTOR(void, SHA##LEN##_Final, u8 digest[LEN/8], \ + void *context) { \ + void *ctx; \ + CHECK_EQ(SHA##LEN##_digest_length, LEN/8); \ + COMMON_INTERCEPTOR_ENTER(ctx, SHA##LEN##_Final, digest, context); \ + if (context) \ + COMMON_INTERCEPTOR_READ_RANGE(ctx, context, SHA##LEN##_CTX_sz); \ + REAL(SHA##LEN##_Final)(digest, context); \ + if (digest) \ + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, digest, \ + sizeof(digest[0]) * \ + SHA##LEN##_digest_length); \ + } \ + INTERCEPTOR(char *, SHA##LEN##_End, void *context, char *buf) { \ + void *ctx; \ + COMMON_INTERCEPTOR_ENTER(ctx, SHA##LEN##_End, context, buf); \ + if (context) \ + COMMON_INTERCEPTOR_READ_RANGE(ctx, context, SHA##LEN##_CTX_sz); \ + char *ret = REAL(SHA##LEN##_End)(context, buf); \ + if (ret) \ + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ret, SHA##LEN##_return_length); \ + return ret; \ + } \ + INTERCEPTOR(char *, SHA##LEN##_File, const char *filename, char *buf) { \ + void *ctx; \ + COMMON_INTERCEPTOR_ENTER(ctx, SHA##LEN##_File, filename, buf); \ + if (filename) \ + COMMON_INTERCEPTOR_READ_RANGE(ctx, filename, internal_strlen(filename) + 1);\ + char *ret = REAL(SHA##LEN##_File)(filename, buf); \ + if (ret) \ + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ret, SHA##LEN##_return_length); \ + return ret; \ + } \ + INTERCEPTOR(char *, SHA##LEN##_FileChunk, const char *filename, char *buf, \ + OFF_T offset, OFF_T length) { \ + void *ctx; \ + COMMON_INTERCEPTOR_ENTER(ctx, SHA##LEN##_FileChunk, filename, buf, offset, \ + length); \ + if (filename) \ + COMMON_INTERCEPTOR_READ_RANGE(ctx, filename, internal_strlen(filename) + 1);\ + char *ret = REAL(SHA##LEN##_FileChunk)(filename, buf, offset, length); \ + if (ret) \ + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ret, SHA##LEN##_return_length); \ + return ret; \ + } \ + INTERCEPTOR(char *, SHA##LEN##_Data, u8 *data, SIZE_T len, char *buf) { \ + void *ctx; \ + COMMON_INTERCEPTOR_ENTER(ctx, SHA##LEN##_Data, data, len, buf); \ + if (data && len > 0) \ + COMMON_INTERCEPTOR_READ_RANGE(ctx, data, len); \ + char *ret = REAL(SHA##LEN##_Data)(data, len, buf); \ + if (ret) \ + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ret, SHA##LEN##_return_length); \ + return ret; \ + } + +SHA2_INTERCEPTORS(224, u32) +SHA2_INTERCEPTORS(256, u32) +SHA2_INTERCEPTORS(384, u64) +SHA2_INTERCEPTORS(512, u64) + +#define INIT_SHA2_INTECEPTORS(LEN) \ + COMMON_INTERCEPT_FUNCTION(SHA##LEN##_Init); \ + COMMON_INTERCEPT_FUNCTION(SHA##LEN##_Update); \ + COMMON_INTERCEPT_FUNCTION(SHA##LEN##_Final); \ + COMMON_INTERCEPT_FUNCTION(SHA##LEN##_End); \ + COMMON_INTERCEPT_FUNCTION(SHA##LEN##_File); \ + COMMON_INTERCEPT_FUNCTION(SHA##LEN##_FileChunk); \ + COMMON_INTERCEPT_FUNCTION(SHA##LEN##_Data) + +#define INIT_SHA2 \ + INIT_SHA2_INTECEPTORS(224); \ + INIT_SHA2_INTECEPTORS(256); \ + INIT_SHA2_INTECEPTORS(384); \ + INIT_SHA2_INTECEPTORS(512) +#undef SHA2_INTERCEPTORS +#else +#define INIT_SHA2 +#endif + +#if SANITIZER_INTERCEPT_VIS +INTERCEPTOR(char *, vis, char *dst, int c, int flag, int nextc) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, vis, dst, c, flag, nextc); + char *end = REAL(vis)(dst, c, flag, nextc); + // dst is NULL terminated and end points to the NULL char + if (dst && end) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, dst, end - dst + 1); + return end; +} +INTERCEPTOR(char *, nvis, char *dst, SIZE_T dlen, int c, int flag, int nextc) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, nvis, dst, dlen, c, flag, nextc); + char *end = REAL(nvis)(dst, dlen, c, flag, nextc); + // nvis cannot make sure the dst is NULL terminated + if (dst && end) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, dst, end - dst + 1); + return end; +} +INTERCEPTOR(int, strvis, char *dst, const char *src, int flag) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, strvis, dst, src, flag); + if (src) + COMMON_INTERCEPTOR_READ_RANGE(ctx, src, internal_strlen(src) + 1); + int len = REAL(strvis)(dst, src, flag); + if (dst) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, dst, len + 1); + return len; +} +INTERCEPTOR(int, stravis, char **dst, const char *src, int flag) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, stravis, dst, src, flag); + if (src) + COMMON_INTERCEPTOR_READ_RANGE(ctx, src, internal_strlen(src) + 1); + int len = REAL(stravis)(dst, src, flag); + if (dst) { + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, dst, sizeof(char *)); + if (*dst) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, *dst, len + 1); + } + return len; +} +INTERCEPTOR(int, strnvis, char *dst, SIZE_T dlen, const char *src, int flag) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, strnvis, dst, dlen, src, flag); + if (src) + COMMON_INTERCEPTOR_READ_RANGE(ctx, src, internal_strlen(src) + 1); + int len = REAL(strnvis)(dst, dlen, src, flag); + // The interface will be valid even if there is no space for NULL char + if (dst && len > 0) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, dst, len + 1); + return len; +} +INTERCEPTOR(int, strvisx, char *dst, const char *src, SIZE_T len, int flag) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, strvisx, dst, src, len, flag); + if (src) + COMMON_INTERCEPTOR_READ_RANGE(ctx, src, len); + int ret = REAL(strvisx)(dst, src, len, flag); + if (dst) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, dst, ret + 1); + return ret; +} +INTERCEPTOR(int, strnvisx, char *dst, SIZE_T dlen, const char *src, SIZE_T len, + int flag) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, strnvisx, dst, dlen, src, len, flag); + if (src) + COMMON_INTERCEPTOR_READ_RANGE(ctx, src, len); + int ret = REAL(strnvisx)(dst, dlen, src, len, flag); + if (dst && ret >= 0) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, dst, ret + 1); + return ret; +} +INTERCEPTOR(int, strenvisx, char *dst, SIZE_T dlen, const char *src, SIZE_T len, + int flag, int *cerr_ptr) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, strenvisx, dst, dlen, src, len, flag, cerr_ptr); + if (src) + COMMON_INTERCEPTOR_READ_RANGE(ctx, src, len); + // FIXME: only need to be checked when "flag | VIS_NOLOCALE" doesn't hold + // according to the implementation + if (cerr_ptr) + COMMON_INTERCEPTOR_READ_RANGE(ctx, cerr_ptr, sizeof(int)); + int ret = REAL(strenvisx)(dst, dlen, src, len, flag, cerr_ptr); + if (dst && ret >= 0) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, dst, ret + 1); + if (cerr_ptr) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, cerr_ptr, sizeof(int)); + return ret; +} +INTERCEPTOR(char *, svis, char *dst, int c, int flag, int nextc, + const char *extra) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, svis, dst, c, flag, nextc, extra); + if (extra) + COMMON_INTERCEPTOR_READ_RANGE(ctx, extra, internal_strlen(extra) + 1); + char *end = REAL(svis)(dst, c, flag, nextc, extra); + if (dst && end) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, dst, end - dst + 1); + return end; +} +INTERCEPTOR(char *, snvis, char *dst, SIZE_T dlen, int c, int flag, int nextc, + const char *extra) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, snvis, dst, dlen, c, flag, nextc, extra); + if (extra) + COMMON_INTERCEPTOR_READ_RANGE(ctx, extra, internal_strlen(extra) + 1); + char *end = REAL(snvis)(dst, dlen, c, flag, nextc, extra); + if (dst && end) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, dst, + Min((SIZE_T)(end - dst + 1), dlen)); + return end; +} +INTERCEPTOR(int, strsvis, char *dst, const char *src, int flag, + const char *extra) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, strsvis, dst, src, flag, extra); + if (src) + COMMON_INTERCEPTOR_READ_RANGE(ctx, src, internal_strlen(src) + 1); + if (extra) + COMMON_INTERCEPTOR_READ_RANGE(ctx, extra, internal_strlen(extra) + 1); + int len = REAL(strsvis)(dst, src, flag, extra); + if (dst) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, dst, len + 1); + return len; +} +INTERCEPTOR(int, strsnvis, char *dst, SIZE_T dlen, const char *src, int flag, + const char *extra) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, strsnvis, dst, dlen, src, flag, extra); + if (src) + COMMON_INTERCEPTOR_READ_RANGE(ctx, src, internal_strlen(src) + 1); + if (extra) + COMMON_INTERCEPTOR_READ_RANGE(ctx, extra, internal_strlen(extra) + 1); + int len = REAL(strsnvis)(dst, dlen, src, flag, extra); + // The interface will be valid even if there is no space for NULL char + if (dst && len >= 0) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, dst, len + 1); + return len; +} +INTERCEPTOR(int, strsvisx, char *dst, const char *src, SIZE_T len, int flag, + const char *extra) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, strsvisx, dst, src, len, flag, extra); + if (src) + COMMON_INTERCEPTOR_READ_RANGE(ctx, src, len); + if (extra) + COMMON_INTERCEPTOR_READ_RANGE(ctx, extra, internal_strlen(extra) + 1); + int ret = REAL(strsvisx)(dst, src, len, flag, extra); + if (dst) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, dst, ret + 1); + return ret; +} +INTERCEPTOR(int, strsnvisx, char *dst, SIZE_T dlen, const char *src, SIZE_T len, + int flag, const char *extra) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, strsnvisx, dst, dlen, src, len, flag, extra); + if (src) + COMMON_INTERCEPTOR_READ_RANGE(ctx, src, len); + if (extra) + COMMON_INTERCEPTOR_READ_RANGE(ctx, extra, internal_strlen(extra) + 1); + int ret = REAL(strsnvisx)(dst, dlen, src, len, flag, extra); + if (dst && ret >= 0) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, dst, ret + 1); + return ret; +} +INTERCEPTOR(int, strsenvisx, char *dst, SIZE_T dlen, const char *src, + SIZE_T len, int flag, const char *extra, int *cerr_ptr) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, strsenvisx, dst, dlen, src, len, flag, extra, + cerr_ptr); + if (src) + COMMON_INTERCEPTOR_READ_RANGE(ctx, src, len); + if (extra) + COMMON_INTERCEPTOR_READ_RANGE(ctx, extra, internal_strlen(extra) + 1); + // FIXME: only need to be checked when "flag | VIS_NOLOCALE" doesn't hold + // according to the implementation + if (cerr_ptr) + COMMON_INTERCEPTOR_READ_RANGE(ctx, cerr_ptr, sizeof(int)); + int ret = REAL(strsenvisx)(dst, dlen, src, len, flag, extra, cerr_ptr); + if (dst && ret >= 0) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, dst, ret + 1); + if (cerr_ptr) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, cerr_ptr, sizeof(int)); + return ret; +} +INTERCEPTOR(int, unvis, char *cp, int c, int *astate, int flag) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, unvis, cp, c, astate, flag); + if (astate) + COMMON_INTERCEPTOR_READ_RANGE(ctx, astate, sizeof(*astate)); + int ret = REAL(unvis)(cp, c, astate, flag); + if (ret == unvis_valid || ret == unvis_validpush) { + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, cp, sizeof(*cp)); + } + return ret; +} +INTERCEPTOR(int, strunvis, char *dst, const char *src) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, strunvis, dst, src); + if (src) + COMMON_INTERCEPTOR_READ_RANGE(ctx, src, internal_strlen(src) + 1); + int ret = REAL(strunvis)(dst, src); + if (ret != -1) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, dst, ret + 1); + return ret; +} +INTERCEPTOR(int, strnunvis, char *dst, SIZE_T dlen, const char *src) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, strnunvis, dst, dlen, src); + if (src) + COMMON_INTERCEPTOR_READ_RANGE(ctx, src, internal_strlen(src) + 1); + int ret = REAL(strnunvis)(dst, dlen, src); + if (ret != -1) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, dst, ret + 1); + return ret; +} +INTERCEPTOR(int, strunvisx, char *dst, const char *src, int flag) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, strunvisx, dst, src, flag); + if (src) + COMMON_INTERCEPTOR_READ_RANGE(ctx, src, internal_strlen(src) + 1); + int ret = REAL(strunvisx)(dst, src, flag); + if (ret != -1) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, dst, ret + 1); + return ret; +} +INTERCEPTOR(int, strnunvisx, char *dst, SIZE_T dlen, const char *src, + int flag) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, strnunvisx, dst, dlen, src, flag); + if (src) + COMMON_INTERCEPTOR_READ_RANGE(ctx, src, internal_strlen(src) + 1); + int ret = REAL(strnunvisx)(dst, dlen, src, flag); + if (ret != -1) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, dst, ret + 1); + return ret; +} +#define INIT_VIS \ + COMMON_INTERCEPT_FUNCTION(vis); \ + COMMON_INTERCEPT_FUNCTION(nvis); \ + COMMON_INTERCEPT_FUNCTION(strvis); \ + COMMON_INTERCEPT_FUNCTION(stravis); \ + COMMON_INTERCEPT_FUNCTION(strnvis); \ + COMMON_INTERCEPT_FUNCTION(strvisx); \ + COMMON_INTERCEPT_FUNCTION(strnvisx); \ + COMMON_INTERCEPT_FUNCTION(strenvisx); \ + COMMON_INTERCEPT_FUNCTION(svis); \ + COMMON_INTERCEPT_FUNCTION(snvis); \ + COMMON_INTERCEPT_FUNCTION(strsvis); \ + COMMON_INTERCEPT_FUNCTION(strsnvis); \ + COMMON_INTERCEPT_FUNCTION(strsvisx); \ + COMMON_INTERCEPT_FUNCTION(strsnvisx); \ + COMMON_INTERCEPT_FUNCTION(strsenvisx); \ + COMMON_INTERCEPT_FUNCTION(unvis); \ + COMMON_INTERCEPT_FUNCTION(strunvis); \ + COMMON_INTERCEPT_FUNCTION(strnunvis); \ + COMMON_INTERCEPT_FUNCTION(strunvisx); \ + COMMON_INTERCEPT_FUNCTION(strnunvisx) +#else +#define INIT_VIS +#endif + +#if SANITIZER_INTERCEPT_CDB +INTERCEPTOR(struct __sanitizer_cdbr *, cdbr_open, const char *path, int flags) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, cdbr_open, path, flags); + if (path) + COMMON_INTERCEPTOR_READ_RANGE(ctx, path, internal_strlen(path) + 1); + struct __sanitizer_cdbr *cdbr = REAL(cdbr_open)(path, flags); + if (cdbr) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, cdbr, sizeof(*cdbr)); + return cdbr; +} + +INTERCEPTOR(struct __sanitizer_cdbr *, cdbr_open_mem, void *base, SIZE_T size, + int flags, void (*unmap)(void *, void *, SIZE_T), void *cookie) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, cdbr_open_mem, base, size, flags, unmap, + cookie); + if (base && size) + COMMON_INTERCEPTOR_READ_RANGE(ctx, base, size); + struct __sanitizer_cdbr *cdbr = + REAL(cdbr_open_mem)(base, size, flags, unmap, cookie); + if (cdbr) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, cdbr, sizeof(*cdbr)); + return cdbr; +} + +INTERCEPTOR(u32, cdbr_entries, struct __sanitizer_cdbr *cdbr) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, cdbr_entries, cdbr); + if (cdbr) + COMMON_INTERCEPTOR_READ_RANGE(ctx, cdbr, sizeof(*cdbr)); + return REAL(cdbr_entries)(cdbr); +} + +INTERCEPTOR(int, cdbr_get, struct __sanitizer_cdbr *cdbr, u32 index, + const void **data, SIZE_T *datalen) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, cdbr_get, cdbr, index, data, datalen); + if (cdbr) + COMMON_INTERCEPTOR_READ_RANGE(ctx, cdbr, sizeof(*cdbr)); + int ret = REAL(cdbr_get)(cdbr, index, data, datalen); + if (!ret) { + if (data) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, data, sizeof(*data)); + if (datalen) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, datalen, sizeof(*datalen)); + if (data && datalen) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, *data, *datalen); + } + return ret; +} + +INTERCEPTOR(int, cdbr_find, struct __sanitizer_cdbr *cdbr, const void *key, + SIZE_T keylen, const void **data, SIZE_T *datalen) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, cdbr_find, cdbr, key, keylen, data, datalen); + if (cdbr) + COMMON_INTERCEPTOR_READ_RANGE(ctx, cdbr, sizeof(*cdbr)); + if (key) + COMMON_INTERCEPTOR_READ_RANGE(ctx, key, keylen); + int ret = REAL(cdbr_find)(cdbr, key, keylen, data, datalen); + if (!ret) { + if (data) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, data, sizeof(*data)); + if (datalen) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, datalen, sizeof(*datalen)); + if (data && datalen) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, *data, *datalen); + } + return ret; +} + +INTERCEPTOR(void, cdbr_close, struct __sanitizer_cdbr *cdbr) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, cdbr_close, cdbr); + if (cdbr) + COMMON_INTERCEPTOR_READ_RANGE(ctx, cdbr, sizeof(*cdbr)); + REAL(cdbr_close)(cdbr); +} + +INTERCEPTOR(struct __sanitizer_cdbw *, cdbw_open) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, cdbw_open); + struct __sanitizer_cdbw *ret = REAL(cdbw_open)(); + if (ret) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ret, sizeof(*ret)); + return ret; +} + +INTERCEPTOR(int, cdbw_put, struct __sanitizer_cdbw *cdbw, const void *key, + SIZE_T keylen, const void *data, SIZE_T datalen) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, cdbw_put, cdbw, key, keylen, data, datalen); + if (cdbw) + COMMON_INTERCEPTOR_READ_RANGE(ctx, cdbw, sizeof(*cdbw)); + if (data && datalen) + COMMON_INTERCEPTOR_READ_RANGE(ctx, data, datalen); + if (key && keylen) + COMMON_INTERCEPTOR_READ_RANGE(ctx, key, keylen); + int ret = REAL(cdbw_put)(cdbw, key, keylen, data, datalen); + if (!ret && cdbw) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, cdbw, sizeof(*cdbw)); + return ret; +} + +INTERCEPTOR(int, cdbw_put_data, struct __sanitizer_cdbw *cdbw, const void *data, + SIZE_T datalen, u32 *index) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, cdbw_put_data, cdbw, data, datalen, index); + if (cdbw) + COMMON_INTERCEPTOR_READ_RANGE(ctx, cdbw, sizeof(*cdbw)); + if (data && datalen) + COMMON_INTERCEPTOR_READ_RANGE(ctx, data, datalen); + int ret = REAL(cdbw_put_data)(cdbw, data, datalen, index); + if (!ret) { + if (index) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, index, sizeof(*index)); + if (cdbw) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, cdbw, sizeof(*cdbw)); + } + return ret; +} + +INTERCEPTOR(int, cdbw_put_key, struct __sanitizer_cdbw *cdbw, const void *key, + SIZE_T keylen, u32 index) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, cdbw_put_key, cdbw, key, keylen, index); + if (cdbw) + COMMON_INTERCEPTOR_READ_RANGE(ctx, cdbw, sizeof(*cdbw)); + if (key && keylen) + COMMON_INTERCEPTOR_READ_RANGE(ctx, key, keylen); + int ret = REAL(cdbw_put_key)(cdbw, key, keylen, index); + if (!ret && cdbw) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, cdbw, sizeof(*cdbw)); + return ret; +} + +INTERCEPTOR(int, cdbw_output, struct __sanitizer_cdbw *cdbw, int output, + const char descr[16], u32 (*seedgen)(void)) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, cdbw_output, cdbw, output, descr, seedgen); + COMMON_INTERCEPTOR_FD_ACCESS(ctx, output); + if (cdbw) + COMMON_INTERCEPTOR_READ_RANGE(ctx, cdbw, sizeof(*cdbw)); + if (descr) + COMMON_INTERCEPTOR_READ_RANGE(ctx, descr, internal_strnlen(descr, 16)); + if (seedgen) + COMMON_INTERCEPTOR_READ_RANGE(ctx, (void *)seedgen, sizeof(seedgen)); + int ret = REAL(cdbw_output)(cdbw, output, descr, seedgen); + if (!ret) { + if (cdbw) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, cdbw, sizeof(*cdbw)); + if (output >= 0) + COMMON_INTERCEPTOR_FD_ACQUIRE(ctx, output); + } + return ret; +} + +INTERCEPTOR(void, cdbw_close, struct __sanitizer_cdbw *cdbw) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, cdbw_close, cdbw); + if (cdbw) + COMMON_INTERCEPTOR_READ_RANGE(ctx, cdbw, sizeof(*cdbw)); + REAL(cdbw_close)(cdbw); +} + +#define INIT_CDB \ + COMMON_INTERCEPT_FUNCTION(cdbr_open); \ + COMMON_INTERCEPT_FUNCTION(cdbr_open_mem); \ + COMMON_INTERCEPT_FUNCTION(cdbr_entries); \ + COMMON_INTERCEPT_FUNCTION(cdbr_get); \ + COMMON_INTERCEPT_FUNCTION(cdbr_find); \ + COMMON_INTERCEPT_FUNCTION(cdbr_close); \ + COMMON_INTERCEPT_FUNCTION(cdbw_open); \ + COMMON_INTERCEPT_FUNCTION(cdbw_put); \ + COMMON_INTERCEPT_FUNCTION(cdbw_put_data); \ + COMMON_INTERCEPT_FUNCTION(cdbw_put_key); \ + COMMON_INTERCEPT_FUNCTION(cdbw_output); \ + COMMON_INTERCEPT_FUNCTION(cdbw_close) +#else +#define INIT_CDB +#endif + +#if SANITIZER_INTERCEPT_GETFSENT +INTERCEPTOR(void *, getfsent) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, getfsent); + void *ret = REAL(getfsent)(); + if (ret) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ret, struct_fstab_sz); + return ret; +} + +INTERCEPTOR(void *, getfsspec, const char *spec) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, getfsspec, spec); + if (spec) + COMMON_INTERCEPTOR_READ_RANGE(ctx, spec, internal_strlen(spec) + 1); + void *ret = REAL(getfsspec)(spec); + if (ret) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ret, struct_fstab_sz); + return ret; +} + +INTERCEPTOR(void *, getfsfile, const char *file) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, getfsfile, file); + if (file) + COMMON_INTERCEPTOR_READ_RANGE(ctx, file, internal_strlen(file) + 1); + void *ret = REAL(getfsfile)(file); + if (ret) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ret, struct_fstab_sz); + return ret; +} + +#define INIT_GETFSENT \ + COMMON_INTERCEPT_FUNCTION(getfsent); \ + COMMON_INTERCEPT_FUNCTION(getfsspec); \ + COMMON_INTERCEPT_FUNCTION(getfsfile); +#else +#define INIT_GETFSENT +#endif + +#if SANITIZER_INTERCEPT_ARC4RANDOM +INTERCEPTOR(void, arc4random_buf, void *buf, SIZE_T len) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, arc4random_buf, buf, len); + REAL(arc4random_buf)(buf, len); + if (buf && len) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, len); +} + +INTERCEPTOR(void, arc4random_addrandom, u8 *dat, int datlen) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, arc4random_addrandom, dat, datlen); + if (dat && datlen) + COMMON_INTERCEPTOR_READ_RANGE(ctx, dat, datlen); + REAL(arc4random_addrandom)(dat, datlen); +} + +#define INIT_ARC4RANDOM \ + COMMON_INTERCEPT_FUNCTION(arc4random_buf); \ + COMMON_INTERCEPT_FUNCTION(arc4random_addrandom); +#else +#define INIT_ARC4RANDOM +#endif + +#if SANITIZER_INTERCEPT_POPEN +INTERCEPTOR(__sanitizer_FILE *, popen, const char *command, const char *type) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, popen, command, type); + if (command) + COMMON_INTERCEPTOR_READ_RANGE(ctx, command, internal_strlen(command) + 1); + if (type) + COMMON_INTERCEPTOR_READ_RANGE(ctx, type, internal_strlen(type) + 1); + __sanitizer_FILE *res = REAL(popen)(command, type); + COMMON_INTERCEPTOR_FILE_OPEN(ctx, res, nullptr); + if (res) unpoison_file(res); + return res; +} +#define INIT_POPEN COMMON_INTERCEPT_FUNCTION(popen) +#else +#define INIT_POPEN +#endif + +#if SANITIZER_INTERCEPT_POPENVE +INTERCEPTOR(__sanitizer_FILE *, popenve, const char *path, + char *const *argv, char *const *envp, const char *type) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, popenve, path, argv, envp, type); + if (path) + COMMON_INTERCEPTOR_READ_RANGE(ctx, path, internal_strlen(path) + 1); + if (argv) { + for (char *const *pa = argv; ; ++pa) { + COMMON_INTERCEPTOR_READ_RANGE(ctx, pa, sizeof(char **)); + if (!*pa) + break; + COMMON_INTERCEPTOR_READ_RANGE(ctx, *pa, internal_strlen(*pa) + 1); + } + } + if (envp) { + for (char *const *pa = envp; ; ++pa) { + COMMON_INTERCEPTOR_READ_RANGE(ctx, pa, sizeof(char **)); + if (!*pa) + break; + COMMON_INTERCEPTOR_READ_RANGE(ctx, *pa, internal_strlen(*pa) + 1); + } + } + if (type) + COMMON_INTERCEPTOR_READ_RANGE(ctx, type, internal_strlen(type) + 1); + __sanitizer_FILE *res = REAL(popenve)(path, argv, envp, type); + COMMON_INTERCEPTOR_FILE_OPEN(ctx, res, nullptr); + if (res) unpoison_file(res); + return res; +} +#define INIT_POPENVE COMMON_INTERCEPT_FUNCTION(popenve) +#else +#define INIT_POPENVE +#endif + +#if SANITIZER_INTERCEPT_PCLOSE +INTERCEPTOR(int, pclose, __sanitizer_FILE *fp) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, pclose, fp); + COMMON_INTERCEPTOR_FILE_CLOSE(ctx, fp); + const FileMetadata *m = GetInterceptorMetadata(fp); + int res = REAL(pclose)(fp); + if (m) { + COMMON_INTERCEPTOR_INITIALIZE_RANGE(*m->addr, *m->size); + DeleteInterceptorMetadata(fp); + } + return res; +} +#define INIT_PCLOSE COMMON_INTERCEPT_FUNCTION(pclose); +#else +#define INIT_PCLOSE +#endif + +#if SANITIZER_INTERCEPT_FUNOPEN +typedef int (*funopen_readfn)(void *cookie, char *buf, int len); +typedef int (*funopen_writefn)(void *cookie, const char *buf, int len); +typedef OFF_T (*funopen_seekfn)(void *cookie, OFF_T offset, int whence); +typedef int (*funopen_closefn)(void *cookie); + +struct WrappedFunopenCookie { + void *real_cookie; + funopen_readfn real_read; + funopen_writefn real_write; + funopen_seekfn real_seek; + funopen_closefn real_close; +}; + +static int wrapped_funopen_read(void *cookie, char *buf, int len) { + COMMON_INTERCEPTOR_UNPOISON_PARAM(3); + WrappedFunopenCookie *wrapped_cookie = (WrappedFunopenCookie *)cookie; + funopen_readfn real_read = wrapped_cookie->real_read; + return real_read(wrapped_cookie->real_cookie, buf, len); +} + +static int wrapped_funopen_write(void *cookie, const char *buf, int len) { + COMMON_INTERCEPTOR_UNPOISON_PARAM(3); + WrappedFunopenCookie *wrapped_cookie = (WrappedFunopenCookie *)cookie; + funopen_writefn real_write = wrapped_cookie->real_write; + return real_write(wrapped_cookie->real_cookie, buf, len); +} + +static OFF_T wrapped_funopen_seek(void *cookie, OFF_T offset, int whence) { + COMMON_INTERCEPTOR_UNPOISON_PARAM(3); + WrappedFunopenCookie *wrapped_cookie = (WrappedFunopenCookie *)cookie; + funopen_seekfn real_seek = wrapped_cookie->real_seek; + return real_seek(wrapped_cookie->real_cookie, offset, whence); +} + +static int wrapped_funopen_close(void *cookie) { + COMMON_INTERCEPTOR_UNPOISON_PARAM(1); + WrappedFunopenCookie *wrapped_cookie = (WrappedFunopenCookie *)cookie; + funopen_closefn real_close = wrapped_cookie->real_close; + int res = real_close(wrapped_cookie->real_cookie); + InternalFree(wrapped_cookie); + return res; +} + +INTERCEPTOR(__sanitizer_FILE *, funopen, void *cookie, funopen_readfn readfn, + funopen_writefn writefn, funopen_seekfn seekfn, + funopen_closefn closefn) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, funopen, cookie, readfn, writefn, seekfn, + closefn); + + WrappedFunopenCookie *wrapped_cookie = + (WrappedFunopenCookie *)InternalAlloc(sizeof(WrappedFunopenCookie)); + wrapped_cookie->real_cookie = cookie; + wrapped_cookie->real_read = readfn; + wrapped_cookie->real_write = writefn; + wrapped_cookie->real_seek = seekfn; + wrapped_cookie->real_close = closefn; + + __sanitizer_FILE *res = + REAL(funopen)(wrapped_cookie, + readfn ? wrapped_funopen_read : nullptr, + writefn ? wrapped_funopen_write : nullptr, + seekfn ? wrapped_funopen_seek : nullptr, + closefn ? wrapped_funopen_close : nullptr); + if (res) + unpoison_file(res); + return res; +} +#define INIT_FUNOPEN COMMON_INTERCEPT_FUNCTION(funopen) +#else +#define INIT_FUNOPEN +#endif + +#if SANITIZER_INTERCEPT_FUNOPEN2 +typedef SSIZE_T (*funopen2_readfn)(void *cookie, void *buf, SIZE_T len); +typedef SSIZE_T (*funopen2_writefn)(void *cookie, const void *buf, SIZE_T len); +typedef OFF_T (*funopen2_seekfn)(void *cookie, OFF_T offset, int whence); +typedef int (*funopen2_flushfn)(void *cookie); +typedef int (*funopen2_closefn)(void *cookie); + +struct WrappedFunopen2Cookie { + void *real_cookie; + funopen2_readfn real_read; + funopen2_writefn real_write; + funopen2_seekfn real_seek; + funopen2_flushfn real_flush; + funopen2_closefn real_close; +}; + +static SSIZE_T wrapped_funopen2_read(void *cookie, void *buf, SIZE_T len) { + COMMON_INTERCEPTOR_UNPOISON_PARAM(3); + WrappedFunopen2Cookie *wrapped_cookie = (WrappedFunopen2Cookie *)cookie; + funopen2_readfn real_read = wrapped_cookie->real_read; + return real_read(wrapped_cookie->real_cookie, buf, len); +} + +static SSIZE_T wrapped_funopen2_write(void *cookie, const void *buf, + SIZE_T len) { + COMMON_INTERCEPTOR_UNPOISON_PARAM(3); + WrappedFunopen2Cookie *wrapped_cookie = (WrappedFunopen2Cookie *)cookie; + funopen2_writefn real_write = wrapped_cookie->real_write; + return real_write(wrapped_cookie->real_cookie, buf, len); +} + +static OFF_T wrapped_funopen2_seek(void *cookie, OFF_T offset, int whence) { + COMMON_INTERCEPTOR_UNPOISON_PARAM(3); + WrappedFunopen2Cookie *wrapped_cookie = (WrappedFunopen2Cookie *)cookie; + funopen2_seekfn real_seek = wrapped_cookie->real_seek; + return real_seek(wrapped_cookie->real_cookie, offset, whence); +} + +static int wrapped_funopen2_flush(void *cookie) { + COMMON_INTERCEPTOR_UNPOISON_PARAM(1); + WrappedFunopen2Cookie *wrapped_cookie = (WrappedFunopen2Cookie *)cookie; + funopen2_flushfn real_flush = wrapped_cookie->real_flush; + return real_flush(wrapped_cookie->real_cookie); +} + +static int wrapped_funopen2_close(void *cookie) { + COMMON_INTERCEPTOR_UNPOISON_PARAM(1); + WrappedFunopen2Cookie *wrapped_cookie = (WrappedFunopen2Cookie *)cookie; + funopen2_closefn real_close = wrapped_cookie->real_close; + int res = real_close(wrapped_cookie->real_cookie); + InternalFree(wrapped_cookie); + return res; +} + +INTERCEPTOR(__sanitizer_FILE *, funopen2, void *cookie, funopen2_readfn readfn, + funopen2_writefn writefn, funopen2_seekfn seekfn, + funopen2_flushfn flushfn, funopen2_closefn closefn) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, funopen2, cookie, readfn, writefn, seekfn, + flushfn, closefn); + + WrappedFunopen2Cookie *wrapped_cookie = + (WrappedFunopen2Cookie *)InternalAlloc(sizeof(WrappedFunopen2Cookie)); + wrapped_cookie->real_cookie = cookie; + wrapped_cookie->real_read = readfn; + wrapped_cookie->real_write = writefn; + wrapped_cookie->real_seek = seekfn; + wrapped_cookie->real_flush = flushfn; + wrapped_cookie->real_close = closefn; + + __sanitizer_FILE *res = + REAL(funopen2)(wrapped_cookie, + readfn ? wrapped_funopen2_read : nullptr, + writefn ? wrapped_funopen2_write : nullptr, + seekfn ? wrapped_funopen2_seek : nullptr, + flushfn ? wrapped_funopen2_flush : nullptr, + closefn ? wrapped_funopen2_close : nullptr); + if (res) + unpoison_file(res); + return res; +} +#define INIT_FUNOPEN2 COMMON_INTERCEPT_FUNCTION(funopen2) +#else +#define INIT_FUNOPEN2 +#endif + +#if SANITIZER_INTERCEPT_FDEVNAME +INTERCEPTOR(char *, fdevname, int fd) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, fdevname, fd); + COMMON_INTERCEPTOR_FD_ACCESS(ctx, fd); + char *name = REAL(fdevname)(fd); + if (name) { + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, name, internal_strlen(name) + 1); + if (fd > 0) + COMMON_INTERCEPTOR_FD_ACQUIRE(ctx, fd); + } + return name; +} + +INTERCEPTOR(char *, fdevname_r, int fd, char *buf, SIZE_T len) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, fdevname_r, fd, buf, len); + COMMON_INTERCEPTOR_FD_ACCESS(ctx, fd); + char *name = REAL(fdevname_r)(fd, buf, len); + if (name && buf && len > 0) { + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, internal_strlen(buf) + 1); + if (fd > 0) + COMMON_INTERCEPTOR_FD_ACQUIRE(ctx, fd); + } + return name; +} + +#define INIT_FDEVNAME \ + COMMON_INTERCEPT_FUNCTION(fdevname); \ + COMMON_INTERCEPT_FUNCTION(fdevname_r); +#else +#define INIT_FDEVNAME +#endif + +#if SANITIZER_INTERCEPT_GETUSERSHELL +INTERCEPTOR(char *, getusershell) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, getusershell); + char *res = REAL(getusershell)(); + if (res) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, internal_strlen(res) + 1); + return res; +} + +#define INIT_GETUSERSHELL COMMON_INTERCEPT_FUNCTION(getusershell); +#else +#define INIT_GETUSERSHELL +#endif + +#if SANITIZER_INTERCEPT_SL_INIT +INTERCEPTOR(void *, sl_init) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, sl_init); + void *res = REAL(sl_init)(); + if (res) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, __sanitizer::struct_StringList_sz); + return res; +} + +INTERCEPTOR(int, sl_add, void *sl, char *item) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, sl_add, sl, item); + if (sl) + COMMON_INTERCEPTOR_READ_RANGE(ctx, sl, __sanitizer::struct_StringList_sz); + if (item) + COMMON_INTERCEPTOR_READ_RANGE(ctx, item, internal_strlen(item) + 1); + int res = REAL(sl_add)(sl, item); + if (!res) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, sl, __sanitizer::struct_StringList_sz); + return res; +} + +INTERCEPTOR(char *, sl_find, void *sl, const char *item) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, sl_find, sl, item); + if (sl) + COMMON_INTERCEPTOR_READ_RANGE(ctx, sl, __sanitizer::struct_StringList_sz); + if (item) + COMMON_INTERCEPTOR_READ_RANGE(ctx, item, internal_strlen(item) + 1); + char *res = REAL(sl_find)(sl, item); + if (res) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, internal_strlen(res) + 1); + return res; +} + +INTERCEPTOR(void, sl_free, void *sl, int freeall) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, sl_free, sl, freeall); + if (sl) + COMMON_INTERCEPTOR_READ_RANGE(ctx, sl, __sanitizer::struct_StringList_sz); + REAL(sl_free)(sl, freeall); +} + +#define INIT_SL_INIT \ + COMMON_INTERCEPT_FUNCTION(sl_init); \ + COMMON_INTERCEPT_FUNCTION(sl_add); \ + COMMON_INTERCEPT_FUNCTION(sl_find); \ + COMMON_INTERCEPT_FUNCTION(sl_free); +#else +#define INIT_SL_INIT +#endif + +#if SANITIZER_INTERCEPT_GETRANDOM +INTERCEPTOR(SSIZE_T, getrandom, void *buf, SIZE_T buflen, unsigned int flags) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, getrandom, buf, buflen, flags); + SSIZE_T n = REAL(getrandom)(buf, buflen, flags); + if (n > 0) { + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, n); + } + return n; +} +#define INIT_GETRANDOM COMMON_INTERCEPT_FUNCTION(getrandom) +#else +#define INIT_GETRANDOM +#endif + +#if SANITIZER_INTERCEPT_CRYPT +INTERCEPTOR(char *, crypt, char *key, char *salt) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, crypt, key, salt); + COMMON_INTERCEPTOR_READ_RANGE(ctx, key, internal_strlen(key) + 1); + COMMON_INTERCEPTOR_READ_RANGE(ctx, salt, internal_strlen(salt) + 1); + char *res = REAL(crypt)(key, salt); + if (res != nullptr) + COMMON_INTERCEPTOR_INITIALIZE_RANGE(res, internal_strlen(res) + 1); + return res; +} +#define INIT_CRYPT COMMON_INTERCEPT_FUNCTION(crypt); +#else +#define INIT_CRYPT +#endif + +#if SANITIZER_INTERCEPT_CRYPT_R +INTERCEPTOR(char *, crypt_r, char *key, char *salt, void *data) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, crypt_r, key, salt, data); + COMMON_INTERCEPTOR_READ_RANGE(ctx, key, internal_strlen(key) + 1); + COMMON_INTERCEPTOR_READ_RANGE(ctx, salt, internal_strlen(salt) + 1); + char *res = REAL(crypt_r)(key, salt, data); + if (res != nullptr) { + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, data, + __sanitizer::struct_crypt_data_sz); + COMMON_INTERCEPTOR_INITIALIZE_RANGE(res, internal_strlen(res) + 1); + } + return res; +} +#define INIT_CRYPT_R COMMON_INTERCEPT_FUNCTION(crypt_r); +#else +#define INIT_CRYPT_R +#endif + +#if SANITIZER_INTERCEPT_GETENTROPY +INTERCEPTOR(int, getentropy, void *buf, SIZE_T buflen) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, getentropy, buf, buflen); + int r = REAL(getentropy)(buf, buflen); + if (r == 0) { + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, buflen); + } + return r; +} +#define INIT_GETENTROPY COMMON_INTERCEPT_FUNCTION(getentropy) +#else +#define INIT_GETENTROPY +#endif + +#if SANITIZER_INTERCEPT_QSORT_R +typedef int (*qsort_r_compar_f)(const void *, const void *, void *); +struct qsort_r_compar_params { + SIZE_T size; + qsort_r_compar_f compar; + void *arg; +}; +static int wrapped_qsort_r_compar(const void *a, const void *b, void *arg) { + qsort_r_compar_params *params = (qsort_r_compar_params *)arg; + COMMON_INTERCEPTOR_UNPOISON_PARAM(3); + COMMON_INTERCEPTOR_INITIALIZE_RANGE(a, params->size); + COMMON_INTERCEPTOR_INITIALIZE_RANGE(b, params->size); + return params->compar(a, b, params->arg); +} + +INTERCEPTOR(void, qsort_r, void *base, SIZE_T nmemb, SIZE_T size, + qsort_r_compar_f compar, void *arg) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, qsort_r, base, nmemb, size, compar, arg); + // Run the comparator over all array elements to detect any memory issues. + if (nmemb > 1) { + for (SIZE_T i = 0; i < nmemb - 1; ++i) { + void *p = (void *)((char *)base + i * size); + void *q = (void *)((char *)base + (i + 1) * size); + COMMON_INTERCEPTOR_UNPOISON_PARAM(3); + compar(p, q, arg); + } + } + qsort_r_compar_params params = {size, compar, arg}; + REAL(qsort_r)(base, nmemb, size, wrapped_qsort_r_compar, ¶ms); + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, base, nmemb * size); +} +# define INIT_QSORT_R COMMON_INTERCEPT_FUNCTION(qsort_r) +#else +# define INIT_QSORT_R +#endif + +#if SANITIZER_INTERCEPT_QSORT && SANITIZER_INTERCEPT_QSORT_R +INTERCEPTOR(void, qsort, void *base, SIZE_T nmemb, SIZE_T size, + qsort_r_compar_f compar) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, qsort, base, nmemb, size, compar); + WRAP(qsort_r)(base, nmemb, size, compar, nullptr); +} +# define INIT_QSORT COMMON_INTERCEPT_FUNCTION(qsort) +#elif SANITIZER_INTERCEPT_QSORT && !SANITIZER_INTERCEPT_QSORT_R +// Glibc qsort uses a temporary buffer allocated either on stack or on heap. +// Poisoned memory from there may get copied into the comparator arguments, +// where it needs to be dealt with. But even that is not enough - the results of +// the sort may be copied into the input/output array based on the results of +// the comparator calls, but directly from the temp memory, bypassing the +// unpoisoning done in wrapped_qsort_compar. We deal with this by, again, +// unpoisoning the entire array after the sort is done. +// +// We can not check that the entire array is initialized at the beginning. IMHO, +// it's fine for parts of the sorted objects to contain uninitialized memory, +// ex. as padding in structs. +typedef int (*qsort_compar_f)(const void *, const void *); +static THREADLOCAL qsort_compar_f qsort_compar; +static THREADLOCAL SIZE_T qsort_size; +static int wrapped_qsort_compar(const void *a, const void *b) { + COMMON_INTERCEPTOR_UNPOISON_PARAM(2); + COMMON_INTERCEPTOR_INITIALIZE_RANGE(a, qsort_size); + COMMON_INTERCEPTOR_INITIALIZE_RANGE(b, qsort_size); + return qsort_compar(a, b); +} + +INTERCEPTOR(void, qsort, void *base, SIZE_T nmemb, SIZE_T size, + qsort_compar_f compar) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, qsort, base, nmemb, size, compar); + // Run the comparator over all array elements to detect any memory issues. + if (nmemb > 1) { + for (SIZE_T i = 0; i < nmemb - 1; ++i) { + void *p = (void *)((char *)base + i * size); + void *q = (void *)((char *)base + (i + 1) * size); + COMMON_INTERCEPTOR_UNPOISON_PARAM(2); + compar(p, q); + } + } + qsort_compar_f old_compar = qsort_compar; + SIZE_T old_size = qsort_size; + // Handle qsort() implementations that recurse using an + // interposable function call: + bool already_wrapped = compar == wrapped_qsort_compar; + if (already_wrapped) { + // This case should only happen if the qsort() implementation calls itself + // using a preemptible function call (e.g. the FreeBSD libc version). + // Check that the size and comparator arguments are as expected. + CHECK_NE(compar, qsort_compar); + CHECK_EQ(qsort_size, size); + } else { + qsort_compar = compar; + qsort_size = size; + } + REAL(qsort)(base, nmemb, size, wrapped_qsort_compar); + if (!already_wrapped) { + qsort_compar = old_compar; + qsort_size = old_size; + } + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, base, nmemb * size); +} +# define INIT_QSORT COMMON_INTERCEPT_FUNCTION(qsort) +#else +# define INIT_QSORT +#endif + +#if SANITIZER_INTERCEPT_BSEARCH +typedef int (*bsearch_compar_f)(const void *, const void *); +struct bsearch_compar_params { + const void *key; + bsearch_compar_f compar; +}; + +static int wrapped_bsearch_compar(const void *key, const void *b) { + const bsearch_compar_params *params = (const bsearch_compar_params *)key; + COMMON_INTERCEPTOR_UNPOISON_PARAM(2); + return params->compar(params->key, b); +} + +INTERCEPTOR(void *, bsearch, const void *key, const void *base, SIZE_T nmemb, + SIZE_T size, bsearch_compar_f compar) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, bsearch, key, base, nmemb, size, compar); + bsearch_compar_params params = {key, compar}; + return REAL(bsearch)(¶ms, base, nmemb, size, wrapped_bsearch_compar); +} +# define INIT_BSEARCH COMMON_INTERCEPT_FUNCTION(bsearch) +#else +# define INIT_BSEARCH +#endif + +#if SANITIZER_INTERCEPT_SIGALTSTACK +INTERCEPTOR(int, sigaltstack, void *ss, void *oss) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, sigaltstack, ss, oss); + int r = REAL(sigaltstack)(ss, oss); + if (r == 0 && oss != nullptr) { + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, oss, struct_stack_t_sz); + } + return r; +} +#define INIT_SIGALTSTACK COMMON_INTERCEPT_FUNCTION(sigaltstack) +#else +#define INIT_SIGALTSTACK +#endif + +#if SANITIZER_INTERCEPT_UNAME +INTERCEPTOR(int, uname, struct utsname *utsname) { +#if SANITIZER_LINUX + if (COMMON_INTERCEPTOR_NOTHING_IS_INITIALIZED) + return internal_uname(utsname); +#endif + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, uname, utsname); + int res = REAL(uname)(utsname); + if (!res) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, utsname, + __sanitizer::struct_utsname_sz); + return res; +} +#define INIT_UNAME COMMON_INTERCEPT_FUNCTION(uname) +#else +#define INIT_UNAME +#endif + +#if SANITIZER_INTERCEPT___XUNAME +// FreeBSD's <sys/utsname.h> define uname() as +// static __inline int uname(struct utsname *name) { +// return __xuname(SYS_NMLN, (void*)name); +// } +INTERCEPTOR(int, __xuname, int size, void *utsname) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, __xuname, size, utsname); + int res = REAL(__xuname)(size, utsname); + if (!res) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, utsname, + __sanitizer::struct_utsname_sz); + return res; +} +#define INIT___XUNAME COMMON_INTERCEPT_FUNCTION(__xuname) +#else +#define INIT___XUNAME +#endif + +#include "sanitizer_common_interceptors_netbsd_compat.inc" + +static void InitializeCommonInterceptors() { +#if SI_POSIX + static u64 metadata_mem[sizeof(MetadataHashMap) / sizeof(u64) + 1]; + interceptor_metadata_map = new ((void *)&metadata_mem) MetadataHashMap(); +#endif + + INIT_MMAP; + INIT_MMAP64; + INIT_TEXTDOMAIN; + INIT_STRLEN; + INIT_STRNLEN; + INIT_STRNDUP; + INIT___STRNDUP; + INIT_STRCMP; + INIT_STRNCMP; + INIT_STRCASECMP; + INIT_STRNCASECMP; + INIT_STRSTR; + INIT_STRCASESTR; + INIT_STRCHR; + INIT_STRCHRNUL; + INIT_STRRCHR; + INIT_STRSPN; + INIT_STRTOK; + INIT_STRPBRK; + INIT_STRXFRM; + INIT___STRXFRM_L; + INIT_MEMSET; + INIT_MEMMOVE; + INIT_MEMCPY; + INIT_MEMCHR; + INIT_MEMCMP; + INIT_BCMP; + INIT_MEMRCHR; + INIT_MEMMEM; + INIT_READ; + INIT_FREAD; + INIT_PREAD; + INIT_PREAD64; + INIT_READV; + INIT_PREADV; + INIT_PREADV64; + INIT_WRITE; + INIT_FWRITE; + INIT_PWRITE; + INIT_PWRITE64; + INIT_WRITEV; + INIT_PWRITEV; + INIT_PWRITEV64; + INIT_FGETS; + INIT_FPUTS; + INIT_PUTS; + INIT_PRCTL; + INIT_LOCALTIME_AND_FRIENDS; + INIT_STRPTIME; + INIT_SCANF; + INIT_ISOC99_SCANF; + INIT_PRINTF; + INIT_PRINTF_L; + INIT_ISOC99_PRINTF; + INIT_FREXP; + INIT_FREXPF_FREXPL; + INIT_GETPWNAM_AND_FRIENDS; + INIT_GETPWNAM_R_AND_FRIENDS; + INIT_GETPWENT; + INIT_FGETPWENT; + INIT_GETPWENT_R; + INIT_FGETPWENT_R; + INIT_FGETGRENT_R; + INIT_SETPWENT; + INIT_CLOCK_GETTIME; + INIT_CLOCK_GETCPUCLOCKID; + INIT_GETITIMER; + INIT_TIME; + INIT_GLOB; + INIT_GLOB64; + INIT_POSIX_SPAWN; + INIT_WAIT; + INIT_WAIT4; + INIT_INET; + INIT_PTHREAD_GETSCHEDPARAM; + INIT_GETADDRINFO; + INIT_GETNAMEINFO; + INIT_GETSOCKNAME; + INIT_GETHOSTBYNAME; + INIT_GETHOSTBYNAME2; + INIT_GETHOSTBYNAME_R; + INIT_GETHOSTBYNAME2_R; + INIT_GETHOSTBYADDR_R; + INIT_GETHOSTENT_R; + INIT_GETSOCKOPT; + INIT_ACCEPT; + INIT_ACCEPT4; + INIT_PACCEPT; + INIT_MODF; + INIT_RECVMSG; + INIT_SENDMSG; + INIT_RECVMMSG; + INIT_SENDMMSG; + INIT_SYSMSG; + INIT_GETPEERNAME; + INIT_IOCTL; + INIT_INET_ATON; + INIT_SYSINFO; + INIT_READDIR; + INIT_READDIR64; + INIT_PTRACE; + INIT_SETLOCALE; + INIT_GETCWD; + INIT_GET_CURRENT_DIR_NAME; + INIT_STRTOIMAX; + INIT_MBSTOWCS; + INIT_MBSNRTOWCS; + INIT_WCSTOMBS; + INIT_WCSNRTOMBS; + INIT_WCRTOMB; + INIT_WCTOMB; + INIT_TCGETATTR; + INIT_REALPATH; + INIT_CANONICALIZE_FILE_NAME; + INIT_CONFSTR; + INIT_SCHED_GETAFFINITY; + INIT_SCHED_GETPARAM; + INIT_STRERROR; + INIT_STRERROR_R; + INIT_XPG_STRERROR_R; + INIT_SCANDIR; + INIT_SCANDIR64; + INIT_GETGROUPS; + INIT_POLL; + INIT_PPOLL; + INIT_WORDEXP; + INIT_SIGWAIT; + INIT_SIGWAITINFO; + INIT_SIGTIMEDWAIT; + INIT_SIGSETOPS; + INIT_SIGSET_LOGICOPS; + INIT_SIGPENDING; + INIT_SIGPROCMASK; + INIT_PTHREAD_SIGMASK; + INIT_BACKTRACE; + INIT__EXIT; + INIT_PTHREAD_MUTEX_LOCK; + INIT_PTHREAD_MUTEX_UNLOCK; + INIT___PTHREAD_MUTEX_LOCK; + INIT___PTHREAD_MUTEX_UNLOCK; + INIT___LIBC_MUTEX_LOCK; + INIT___LIBC_MUTEX_UNLOCK; + INIT___LIBC_THR_SETCANCELSTATE; + INIT_GETMNTENT; + INIT_GETMNTENT_R; + INIT_STATFS; + INIT_STATFS64; + INIT_STATVFS; + INIT_STATVFS64; + INIT_INITGROUPS; + INIT_ETHER_NTOA_ATON; + INIT_ETHER_HOST; + INIT_ETHER_R; + INIT_SHMCTL; + INIT_RANDOM_R; + INIT_PTHREAD_ATTR_GET; + INIT_PTHREAD_ATTR_GET_SCHED; + INIT_PTHREAD_ATTR_GETINHERITSCHED; + INIT_PTHREAD_ATTR_GETAFFINITY_NP; + INIT_PTHREAD_MUTEXATTR_GETPSHARED; + INIT_PTHREAD_MUTEXATTR_GETTYPE; + INIT_PTHREAD_MUTEXATTR_GETPROTOCOL; + INIT_PTHREAD_MUTEXATTR_GETPRIOCEILING; + INIT_PTHREAD_MUTEXATTR_GETROBUST; + INIT_PTHREAD_MUTEXATTR_GETROBUST_NP; + INIT_PTHREAD_RWLOCKATTR_GETPSHARED; + INIT_PTHREAD_RWLOCKATTR_GETKIND_NP; + INIT_PTHREAD_CONDATTR_GETPSHARED; + INIT_PTHREAD_CONDATTR_GETCLOCK; + INIT_PTHREAD_BARRIERATTR_GETPSHARED; + INIT_TMPNAM; + INIT_TMPNAM_R; + INIT_PTSNAME; + INIT_PTSNAME_R; + INIT_TTYNAME; + INIT_TTYNAME_R; + INIT_TEMPNAM; + INIT_PTHREAD_SETNAME_NP; + INIT_PTHREAD_GETNAME_NP; + INIT_SINCOS; + INIT_REMQUO; + INIT_REMQUOL; + INIT_LGAMMA; + INIT_LGAMMAL; + INIT_LGAMMA_R; + INIT_LGAMMAL_R; + INIT_DRAND48_R; + INIT_RAND_R; + INIT_GETLINE; + INIT_ICONV; + INIT_TIMES; + INIT_TLS_GET_ADDR; + INIT_LISTXATTR; + INIT_GETXATTR; + INIT_GETRESID; + INIT_GETIFADDRS; + INIT_IF_INDEXTONAME; + INIT_CAPGET; + INIT_AEABI_MEM; + INIT___BZERO; + INIT_BZERO; + INIT_FTIME; + INIT_XDR; + INIT_XDRREC_LINUX; + INIT_TSEARCH; + INIT_LIBIO_INTERNALS; + INIT_FOPEN; + INIT_FOPEN64; + INIT_FLOPEN; + INIT_OPEN_MEMSTREAM; + INIT_OBSTACK; + INIT_FFLUSH; + INIT_FCLOSE; + INIT_DLOPEN_DLCLOSE; + INIT_GETPASS; + INIT_TIMERFD; + INIT_MLOCKX; + INIT_FOPENCOOKIE; + INIT_SEM; + INIT_PTHREAD_SETCANCEL; + INIT_MINCORE; + INIT_PROCESS_VM_READV; + INIT_CTERMID; + INIT_CTERMID_R; + INIT_RECV_RECVFROM; + INIT_SEND_SENDTO; + INIT_STAT; + INIT_EVENTFD_READ_WRITE; + INIT_LSTAT; + INIT___XSTAT; + INIT___XSTAT64; + INIT___LXSTAT; + INIT___LXSTAT64; + // FIXME: add other *stat interceptors. + INIT_UTMP; + INIT_UTMPX; + INIT_GETLOADAVG; + INIT_WCSLEN; + INIT_WCSCAT; + INIT_WCSDUP; + INIT_WCSXFRM; + INIT___WCSXFRM_L; + INIT_ACCT; + INIT_USER_FROM_UID; + INIT_UID_FROM_USER; + INIT_GROUP_FROM_GID; + INIT_GID_FROM_GROUP; + INIT_ACCESS; + INIT_FACCESSAT; + INIT_GETGROUPLIST; + INIT_GETGROUPMEMBERSHIP; + INIT_READLINK; + INIT_READLINKAT; + INIT_NAME_TO_HANDLE_AT; + INIT_OPEN_BY_HANDLE_AT; + INIT_STRLCPY; + INIT_DEVNAME; + INIT_DEVNAME_R; + INIT_FGETLN; + INIT_STRMODE; + INIT_TTYENT; + INIT_PROTOENT; + INIT_PROTOENT_R; + INIT_NETENT; + INIT_GETMNTINFO; + INIT_MI_VECTOR_HASH; + INIT_SETVBUF; + INIT_GETVFSSTAT; + INIT_REGEX; + INIT_REGEXSUB; + INIT_FTS; + INIT_SYSCTL; + INIT_ASYSCTL; + INIT_SYSCTLGETMIBINFO; + INIT_NL_LANGINFO; + INIT_MODCTL; + INIT_STRTONUM; + INIT_FPARSELN; + INIT_STATVFS1; + INIT_STRTOI; + INIT_CAPSICUM; + INIT_SHA1; + INIT_MD4; + INIT_RMD160; + INIT_MD5; + INIT_FSEEK; + INIT_MD2; + INIT_SHA2; + INIT_VIS; + INIT_CDB; + INIT_GETFSENT; + INIT_ARC4RANDOM; + INIT_POPEN; + INIT_POPENVE; + INIT_PCLOSE; + INIT_FUNOPEN; + INIT_FUNOPEN2; + INIT_FDEVNAME; + INIT_GETUSERSHELL; + INIT_SL_INIT; + INIT_GETRANDOM; + INIT_CRYPT; + INIT_CRYPT_R; + INIT_GETENTROPY; + INIT_QSORT; + INIT_QSORT_R; + INIT_BSEARCH; + INIT_SIGALTSTACK; + INIT_UNAME; + INIT___XUNAME; + + INIT___PRINTF_CHK; +} diff --git a/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_common_interceptors_format.inc b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_common_interceptors_format.inc new file mode 100644 index 0000000000..220abb89c3 --- /dev/null +++ b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_common_interceptors_format.inc @@ -0,0 +1,568 @@ +//===-- sanitizer_common_interceptors_format.inc ----------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// Scanf/printf implementation for use in *Sanitizer interceptors. +// Follows http://pubs.opengroup.org/onlinepubs/9699919799/functions/fscanf.html +// and http://pubs.opengroup.org/onlinepubs/9699919799/functions/fprintf.html +// with a few common GNU extensions. +// +//===----------------------------------------------------------------------===// + +#include <stdarg.h> + +static const char *parse_number(const char *p, int *out) { + *out = internal_atoll(p); + while (*p >= '0' && *p <= '9') + ++p; + return p; +} + +static const char *maybe_parse_param_index(const char *p, int *out) { + // n$ + if (*p >= '0' && *p <= '9') { + int number; + const char *q = parse_number(p, &number); + CHECK(q); + if (*q == '$') { + *out = number; + p = q + 1; + } + } + + // Otherwise, do not change p. This will be re-parsed later as the field + // width. + return p; +} + +static bool char_is_one_of(char c, const char *s) { + return !!internal_strchr(s, c); +} + +static const char *maybe_parse_length_modifier(const char *p, char ll[2]) { + if (char_is_one_of(*p, "jztLq")) { + ll[0] = *p; + ++p; + } else if (*p == 'h') { + ll[0] = 'h'; + ++p; + if (*p == 'h') { + ll[1] = 'h'; + ++p; + } + } else if (*p == 'l') { + ll[0] = 'l'; + ++p; + if (*p == 'l') { + ll[1] = 'l'; + ++p; + } + } + return p; +} + +// Returns true if the character is an integer conversion specifier. +static bool format_is_integer_conv(char c) { + return char_is_one_of(c, "diouxXn"); +} + +// Returns true if the character is an floating point conversion specifier. +static bool format_is_float_conv(char c) { + return char_is_one_of(c, "aAeEfFgG"); +} + +// Returns string output character size for string-like conversions, +// or 0 if the conversion is invalid. +static int format_get_char_size(char convSpecifier, + const char lengthModifier[2]) { + if (char_is_one_of(convSpecifier, "CS")) { + return sizeof(wchar_t); + } + + if (char_is_one_of(convSpecifier, "cs[")) { + if (lengthModifier[0] == 'l' && lengthModifier[1] == '\0') + return sizeof(wchar_t); + else if (lengthModifier[0] == '\0') + return sizeof(char); + } + + return 0; +} + +enum FormatStoreSize { + // Store size not known in advance; can be calculated as wcslen() of the + // destination buffer. + FSS_WCSLEN = -2, + // Store size not known in advance; can be calculated as strlen() of the + // destination buffer. + FSS_STRLEN = -1, + // Invalid conversion specifier. + FSS_INVALID = 0 +}; + +// Returns the memory size of a format directive (if >0), or a value of +// FormatStoreSize. +static int format_get_value_size(char convSpecifier, + const char lengthModifier[2], + bool promote_float) { + if (format_is_integer_conv(convSpecifier)) { + switch (lengthModifier[0]) { + case 'h': + return lengthModifier[1] == 'h' ? sizeof(char) : sizeof(short); + case 'l': + return lengthModifier[1] == 'l' ? sizeof(long long) : sizeof(long); + case 'q': + return sizeof(long long); + case 'L': + return sizeof(long long); + case 'j': + return sizeof(INTMAX_T); + case 'z': + return sizeof(SIZE_T); + case 't': + return sizeof(PTRDIFF_T); + case 0: + return sizeof(int); + default: + return FSS_INVALID; + } + } + + if (format_is_float_conv(convSpecifier)) { + switch (lengthModifier[0]) { + case 'L': + case 'q': + return sizeof(long double); + case 'l': + return lengthModifier[1] == 'l' ? sizeof(long double) + : sizeof(double); + case 0: + // Printf promotes floats to doubles but scanf does not + return promote_float ? sizeof(double) : sizeof(float); + default: + return FSS_INVALID; + } + } + + if (convSpecifier == 'p') { + if (lengthModifier[0] != 0) + return FSS_INVALID; + return sizeof(void *); + } + + return FSS_INVALID; +} + +struct ScanfDirective { + int argIdx; // argument index, or -1 if not specified ("%n$") + int fieldWidth; + const char *begin; + const char *end; + bool suppressed; // suppress assignment ("*") + bool allocate; // allocate space ("m") + char lengthModifier[2]; + char convSpecifier; + bool maybeGnuMalloc; +}; + +// Parse scanf format string. If a valid directive in encountered, it is +// returned in dir. This function returns the pointer to the first +// unprocessed character, or 0 in case of error. +// In case of the end-of-string, a pointer to the closing \0 is returned. +static const char *scanf_parse_next(const char *p, bool allowGnuMalloc, + ScanfDirective *dir) { + internal_memset(dir, 0, sizeof(*dir)); + dir->argIdx = -1; + + while (*p) { + if (*p != '%') { + ++p; + continue; + } + dir->begin = p; + ++p; + // %% + if (*p == '%') { + ++p; + continue; + } + if (*p == '\0') { + return nullptr; + } + // %n$ + p = maybe_parse_param_index(p, &dir->argIdx); + CHECK(p); + // * + if (*p == '*') { + dir->suppressed = true; + ++p; + } + // Field width + if (*p >= '0' && *p <= '9') { + p = parse_number(p, &dir->fieldWidth); + CHECK(p); + if (dir->fieldWidth <= 0) // Width if at all must be non-zero + return nullptr; + } + // m + if (*p == 'm') { + dir->allocate = true; + ++p; + } + // Length modifier. + p = maybe_parse_length_modifier(p, dir->lengthModifier); + // Conversion specifier. + dir->convSpecifier = *p++; + // Consume %[...] expression. + if (dir->convSpecifier == '[') { + if (*p == '^') + ++p; + if (*p == ']') + ++p; + while (*p && *p != ']') + ++p; + if (*p == 0) + return nullptr; // unexpected end of string + // Consume the closing ']'. + ++p; + } + // This is unfortunately ambiguous between old GNU extension + // of %as, %aS and %a[...] and newer POSIX %a followed by + // letters s, S or [. + if (allowGnuMalloc && dir->convSpecifier == 'a' && + !dir->lengthModifier[0]) { + if (*p == 's' || *p == 'S') { + dir->maybeGnuMalloc = true; + ++p; + } else if (*p == '[') { + // Watch for %a[h-j%d], if % appears in the + // [...] range, then we need to give up, we don't know + // if scanf will parse it as POSIX %a [h-j %d ] or + // GNU allocation of string with range dh-j plus %. + const char *q = p + 1; + if (*q == '^') + ++q; + if (*q == ']') + ++q; + while (*q && *q != ']' && *q != '%') + ++q; + if (*q == 0 || *q == '%') + return nullptr; + p = q + 1; // Consume the closing ']'. + dir->maybeGnuMalloc = true; + } + } + dir->end = p; + break; + } + return p; +} + +static int scanf_get_value_size(ScanfDirective *dir) { + if (dir->allocate) { + if (!char_is_one_of(dir->convSpecifier, "cCsS[")) + return FSS_INVALID; + return sizeof(char *); + } + + if (dir->maybeGnuMalloc) { + if (dir->convSpecifier != 'a' || dir->lengthModifier[0]) + return FSS_INVALID; + // This is ambiguous, so check the smaller size of char * (if it is + // a GNU extension of %as, %aS or %a[...]) and float (if it is + // POSIX %a followed by s, S or [ letters). + return sizeof(char *) < sizeof(float) ? sizeof(char *) : sizeof(float); + } + + if (char_is_one_of(dir->convSpecifier, "cCsS[")) { + bool needsTerminator = char_is_one_of(dir->convSpecifier, "sS["); + unsigned charSize = + format_get_char_size(dir->convSpecifier, dir->lengthModifier); + if (charSize == 0) + return FSS_INVALID; + if (dir->fieldWidth == 0) { + if (!needsTerminator) + return charSize; + return (charSize == sizeof(char)) ? FSS_STRLEN : FSS_WCSLEN; + } + return (dir->fieldWidth + needsTerminator) * charSize; + } + + return format_get_value_size(dir->convSpecifier, dir->lengthModifier, false); +} + +// Common part of *scanf interceptors. +// Process format string and va_list, and report all store ranges. +// Stops when "consuming" n_inputs input items. +static void scanf_common(void *ctx, int n_inputs, bool allowGnuMalloc, + const char *format, va_list aq) { + CHECK_GT(n_inputs, 0); + const char *p = format; + + COMMON_INTERCEPTOR_READ_RANGE(ctx, format, internal_strlen(format) + 1); + + while (*p) { + ScanfDirective dir; + p = scanf_parse_next(p, allowGnuMalloc, &dir); + if (!p) + break; + if (dir.convSpecifier == 0) { + // This can only happen at the end of the format string. + CHECK_EQ(*p, 0); + break; + } + // Here the directive is valid. Do what it says. + if (dir.argIdx != -1) { + // Unsupported. + break; + } + if (dir.suppressed) + continue; + int size = scanf_get_value_size(&dir); + if (size == FSS_INVALID) { + Report("%s: WARNING: unexpected format specifier in scanf interceptor: %.*s\n", + SanitizerToolName, static_cast<int>(dir.end - dir.begin), dir.begin); + break; + } + void *argp = va_arg(aq, void *); + if (dir.convSpecifier != 'n') + --n_inputs; + if (n_inputs < 0) + break; + if (size == FSS_STRLEN) { + size = internal_strlen((const char *)argp) + 1; + } else if (size == FSS_WCSLEN) { + // FIXME: actually use wcslen() to calculate it. + size = 0; + } + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, argp, size); + // For %ms/%mc, write the allocated output buffer as well. + if (dir.allocate) { + char *buf = *(char **)argp; + if (buf) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, internal_strlen(buf) + 1); + } + } +} + +#if SANITIZER_INTERCEPT_PRINTF + +struct PrintfDirective { + int fieldWidth; + int fieldPrecision; + int argIdx; // width argument index, or -1 if not specified ("%*n$") + int precisionIdx; // precision argument index, or -1 if not specified (".*n$") + const char *begin; + const char *end; + bool starredWidth; + bool starredPrecision; + char lengthModifier[2]; + char convSpecifier; +}; + +static const char *maybe_parse_number(const char *p, int *out) { + if (*p >= '0' && *p <= '9') + p = parse_number(p, out); + return p; +} + +static const char *maybe_parse_number_or_star(const char *p, int *out, + bool *star) { + if (*p == '*') { + *star = true; + ++p; + } else { + *star = false; + p = maybe_parse_number(p, out); + } + return p; +} + +// Parse printf format string. Same as scanf_parse_next. +static const char *printf_parse_next(const char *p, PrintfDirective *dir) { + internal_memset(dir, 0, sizeof(*dir)); + dir->argIdx = -1; + dir->precisionIdx = -1; + + while (*p) { + if (*p != '%') { + ++p; + continue; + } + dir->begin = p; + ++p; + // %% + if (*p == '%') { + ++p; + continue; + } + if (*p == '\0') { + return nullptr; + } + // %n$ + p = maybe_parse_param_index(p, &dir->precisionIdx); + CHECK(p); + // Flags + while (char_is_one_of(*p, "'-+ #0")) { + ++p; + } + // Field width + p = maybe_parse_number_or_star(p, &dir->fieldWidth, + &dir->starredWidth); + if (!p) + return nullptr; + // Precision + if (*p == '.') { + ++p; + // Actual precision is optional (surprise!) + p = maybe_parse_number_or_star(p, &dir->fieldPrecision, + &dir->starredPrecision); + if (!p) + return nullptr; + // m$ + if (dir->starredPrecision) { + p = maybe_parse_param_index(p, &dir->precisionIdx); + CHECK(p); + } + } + // Length modifier. + p = maybe_parse_length_modifier(p, dir->lengthModifier); + // Conversion specifier. + dir->convSpecifier = *p++; + dir->end = p; + break; + } + return p; +} + +static int printf_get_value_size(PrintfDirective *dir) { + if (char_is_one_of(dir->convSpecifier, "cCsS")) { + unsigned charSize = + format_get_char_size(dir->convSpecifier, dir->lengthModifier); + if (charSize == 0) + return FSS_INVALID; + if (char_is_one_of(dir->convSpecifier, "sS")) { + return (charSize == sizeof(char)) ? FSS_STRLEN : FSS_WCSLEN; + } + return charSize; + } + + return format_get_value_size(dir->convSpecifier, dir->lengthModifier, true); +} + +#define SKIP_SCALAR_ARG(aq, convSpecifier, size) \ + do { \ + if (format_is_float_conv(convSpecifier)) { \ + switch (size) { \ + case 8: \ + va_arg(*aq, double); \ + break; \ + case 12: \ + va_arg(*aq, long double); \ + break; \ + case 16: \ + va_arg(*aq, long double); \ + break; \ + default: \ + Report("WARNING: unexpected floating-point arg size" \ + " in printf interceptor: %zu\n", static_cast<uptr>(size)); \ + return; \ + } \ + } else { \ + switch (size) { \ + case 1: \ + case 2: \ + case 4: \ + va_arg(*aq, u32); \ + break; \ + case 8: \ + va_arg(*aq, u64); \ + break; \ + default: \ + Report("WARNING: unexpected arg size" \ + " in printf interceptor: %zu\n", static_cast<uptr>(size)); \ + return; \ + } \ + } \ + } while (0) + +// Common part of *printf interceptors. +// Process format string and va_list, and report all load ranges. +static void printf_common(void *ctx, const char *format, va_list aq) { + COMMON_INTERCEPTOR_READ_RANGE(ctx, format, internal_strlen(format) + 1); + + const char *p = format; + + while (*p) { + PrintfDirective dir; + p = printf_parse_next(p, &dir); + if (!p) + break; + if (dir.convSpecifier == 0) { + // This can only happen at the end of the format string. + CHECK_EQ(*p, 0); + break; + } + // Here the directive is valid. Do what it says. + if (dir.argIdx != -1 || dir.precisionIdx != -1) { + // Unsupported. + break; + } + if (dir.starredWidth) { + // Dynamic width + SKIP_SCALAR_ARG(&aq, 'd', sizeof(int)); + } + if (dir.starredPrecision) { + // Dynamic precision + SKIP_SCALAR_ARG(&aq, 'd', sizeof(int)); + } + // %m does not require an argument: strlen(errno). + if (dir.convSpecifier == 'm') + continue; + int size = printf_get_value_size(&dir); + if (size == FSS_INVALID) { + static int ReportedOnce; + if (!ReportedOnce++) + Report( + "%s: WARNING: unexpected format specifier in printf " + "interceptor: %.*s (reported once per process)\n", + SanitizerToolName, static_cast<int>(dir.end - dir.begin), dir.begin); + break; + } + if (dir.convSpecifier == 'n') { + void *argp = va_arg(aq, void *); + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, argp, size); + continue; + } else if (size == FSS_STRLEN) { + if (void *argp = va_arg(aq, void *)) { + if (dir.starredPrecision) { + // FIXME: properly support starred precision for strings. + size = 0; + } else if (dir.fieldPrecision > 0) { + // Won't read more than "precision" symbols. + size = internal_strnlen((const char *)argp, dir.fieldPrecision); + if (size < dir.fieldPrecision) size++; + } else { + // Whole string will be accessed. + size = internal_strlen((const char *)argp) + 1; + } + COMMON_INTERCEPTOR_READ_RANGE(ctx, argp, size); + } + } else if (size == FSS_WCSLEN) { + if (void *argp = va_arg(aq, void *)) { + // FIXME: Properly support wide-character strings (via wcsrtombs). + size = 0; + COMMON_INTERCEPTOR_READ_RANGE(ctx, argp, size); + } + } else { + // Skip non-pointer args + SKIP_SCALAR_ARG(&aq, dir.convSpecifier, size); + } + } +} + +#endif // SANITIZER_INTERCEPT_PRINTF diff --git a/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_common_interceptors_ioctl.inc b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_common_interceptors_ioctl.inc new file mode 100644 index 0000000000..b7da659875 --- /dev/null +++ b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_common_interceptors_ioctl.inc @@ -0,0 +1,604 @@ +//===-- sanitizer_common_interceptors_ioctl.inc -----------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// Ioctl handling in common sanitizer interceptors. +//===----------------------------------------------------------------------===// + +#if !SANITIZER_NETBSD + +#include "sanitizer_flags.h" + +struct ioctl_desc { + unsigned req; + // FIXME: support read+write arguments. Currently READWRITE and WRITE do the + // same thing. + // XXX: The declarations below may use WRITE instead of READWRITE, unless + // explicitly noted. + enum { + NONE, + READ, + WRITE, + READWRITE, + CUSTOM + } type : 3; + unsigned size : 29; + const char* name; +}; + +const unsigned ioctl_table_max = 500; +static ioctl_desc ioctl_table[ioctl_table_max]; +static unsigned ioctl_table_size = 0; + +// This can not be declared as a global, because references to struct_*_sz +// require a global initializer. And this table must be available before global +// initializers are run. +static void ioctl_table_fill() { +#define _(rq, tp, sz) \ + if (IOCTL_##rq != IOCTL_NOT_PRESENT) { \ + CHECK(ioctl_table_size < ioctl_table_max); \ + ioctl_table[ioctl_table_size].req = IOCTL_##rq; \ + ioctl_table[ioctl_table_size].type = ioctl_desc::tp; \ + ioctl_table[ioctl_table_size].size = sz; \ + ioctl_table[ioctl_table_size].name = #rq; \ + ++ioctl_table_size; \ + } + + _(FIOASYNC, READ, sizeof(int)); + _(FIOCLEX, NONE, 0); + _(FIOGETOWN, WRITE, sizeof(int)); + _(FIONBIO, READ, sizeof(int)); + _(FIONCLEX, NONE, 0); + _(FIOSETOWN, READ, sizeof(int)); + _(SIOCATMARK, WRITE, sizeof(int)); + _(SIOCGIFCONF, CUSTOM, 0); + _(SIOCGPGRP, WRITE, sizeof(int)); + _(SIOCSPGRP, READ, sizeof(int)); +#if !SANITIZER_SOLARIS + _(TIOCCONS, NONE, 0); +#endif + _(TIOCEXCL, NONE, 0); + _(TIOCGETD, WRITE, sizeof(int)); + _(TIOCGPGRP, WRITE, pid_t_sz); + _(TIOCGWINSZ, WRITE, struct_winsize_sz); + _(TIOCMBIC, READ, sizeof(int)); + _(TIOCMBIS, READ, sizeof(int)); + _(TIOCMGET, WRITE, sizeof(int)); + _(TIOCMSET, READ, sizeof(int)); + _(TIOCNOTTY, NONE, 0); + _(TIOCNXCL, NONE, 0); + _(TIOCOUTQ, WRITE, sizeof(int)); + _(TIOCPKT, READ, sizeof(int)); + _(TIOCSCTTY, NONE, 0); + _(TIOCSETD, READ, sizeof(int)); + _(TIOCSPGRP, READ, pid_t_sz); + _(TIOCSTI, READ, sizeof(char)); + _(TIOCSWINSZ, READ, struct_winsize_sz); + +#if !SANITIZER_IOS + _(SIOCADDMULTI, READ, struct_ifreq_sz); + _(SIOCDELMULTI, READ, struct_ifreq_sz); + _(SIOCGIFADDR, WRITE, struct_ifreq_sz); + _(SIOCGIFBRDADDR, WRITE, struct_ifreq_sz); + _(SIOCGIFDSTADDR, WRITE, struct_ifreq_sz); + _(SIOCGIFFLAGS, WRITE, struct_ifreq_sz); + _(SIOCGIFMETRIC, WRITE, struct_ifreq_sz); + _(SIOCGIFMTU, WRITE, struct_ifreq_sz); + _(SIOCGIFNETMASK, WRITE, struct_ifreq_sz); + _(SIOCSIFADDR, READ, struct_ifreq_sz); + _(SIOCSIFBRDADDR, READ, struct_ifreq_sz); + _(SIOCSIFDSTADDR, READ, struct_ifreq_sz); + _(SIOCSIFFLAGS, READ, struct_ifreq_sz); + _(SIOCSIFMETRIC, READ, struct_ifreq_sz); + _(SIOCSIFMTU, READ, struct_ifreq_sz); + _(SIOCSIFNETMASK, READ, struct_ifreq_sz); +#endif + +#if (SANITIZER_LINUX && !SANITIZER_ANDROID) + _(SIOCGETSGCNT, WRITE, struct_sioc_sg_req_sz); + _(SIOCGETVIFCNT, WRITE, struct_sioc_vif_req_sz); +#endif + +#if SANITIZER_LINUX + // Conflicting request ids. + // _(CDROMAUDIOBUFSIZ, NONE, 0); + // _(SNDCTL_TMR_CONTINUE, NONE, 0); + // _(SNDCTL_TMR_START, NONE, 0); + // _(SNDCTL_TMR_STOP, NONE, 0); + // _(SOUND_MIXER_READ_LOUD, WRITE, sizeof(int)); // same as ...READ_ENHANCE + // _(SOUND_MIXER_READ_MUTE, WRITE, sizeof(int)); // same as ...READ_ENHANCE + // _(SOUND_MIXER_WRITE_LOUD, WRITE, sizeof(int)); // same as ...WRITE_ENHANCE + // _(SOUND_MIXER_WRITE_MUTE, WRITE, sizeof(int)); // same as ...WRITE_ENHANCE + _(BLKFLSBUF, NONE, 0); + _(BLKGETSIZE, WRITE, sizeof(uptr)); + _(BLKRAGET, WRITE, sizeof(int)); + _(BLKRASET, NONE, 0); + _(BLKROGET, WRITE, sizeof(int)); + _(BLKROSET, READ, sizeof(int)); + _(BLKRRPART, NONE, 0); + _(CDROMEJECT, NONE, 0); + _(CDROMEJECT_SW, NONE, 0); + _(CDROMMULTISESSION, WRITE, struct_cdrom_multisession_sz); + _(CDROMPAUSE, NONE, 0); + _(CDROMPLAYMSF, READ, struct_cdrom_msf_sz); + _(CDROMPLAYTRKIND, READ, struct_cdrom_ti_sz); + _(CDROMREADAUDIO, READ, struct_cdrom_read_audio_sz); + _(CDROMREADCOOKED, READ, struct_cdrom_msf_sz); + _(CDROMREADMODE1, READ, struct_cdrom_msf_sz); + _(CDROMREADMODE2, READ, struct_cdrom_msf_sz); + _(CDROMREADRAW, READ, struct_cdrom_msf_sz); + _(CDROMREADTOCENTRY, WRITE, struct_cdrom_tocentry_sz); + _(CDROMREADTOCHDR, WRITE, struct_cdrom_tochdr_sz); + _(CDROMRESET, NONE, 0); + _(CDROMRESUME, NONE, 0); + _(CDROMSEEK, READ, struct_cdrom_msf_sz); + _(CDROMSTART, NONE, 0); + _(CDROMSTOP, NONE, 0); + _(CDROMSUBCHNL, WRITE, struct_cdrom_subchnl_sz); + _(CDROMVOLCTRL, READ, struct_cdrom_volctrl_sz); + _(CDROMVOLREAD, WRITE, struct_cdrom_volctrl_sz); + _(CDROM_GET_UPC, WRITE, 8); + _(EVIOCGABS, WRITE, struct_input_absinfo_sz); // fixup + _(EVIOCGBIT, WRITE, struct_input_id_sz); // fixup + _(EVIOCGEFFECTS, WRITE, sizeof(int)); + _(EVIOCGID, WRITE, struct_input_id_sz); + _(EVIOCGKEY, WRITE, 0); + _(EVIOCGKEYCODE, WRITE, sizeof(int) * 2); + _(EVIOCGLED, WRITE, 0); + _(EVIOCGNAME, WRITE, 0); + _(EVIOCGPHYS, WRITE, 0); + _(EVIOCGRAB, READ, sizeof(int)); + _(EVIOCGREP, WRITE, sizeof(int) * 2); + _(EVIOCGSND, WRITE, 0); + _(EVIOCGSW, WRITE, 0); + _(EVIOCGUNIQ, WRITE, 0); + _(EVIOCGVERSION, WRITE, sizeof(int)); + _(EVIOCRMFF, READ, sizeof(int)); + _(EVIOCSABS, READ, struct_input_absinfo_sz); // fixup + _(EVIOCSFF, READ, struct_ff_effect_sz); + _(EVIOCSKEYCODE, READ, sizeof(int) * 2); + _(EVIOCSREP, READ, sizeof(int) * 2); + _(FDCLRPRM, NONE, 0); + _(FDDEFPRM, READ, struct_floppy_struct_sz); + _(FDFLUSH, NONE, 0); + _(FDFMTBEG, NONE, 0); + _(FDFMTEND, NONE, 0); + _(FDFMTTRK, READ, struct_format_descr_sz); + _(FDGETDRVPRM, WRITE, struct_floppy_drive_params_sz); + _(FDGETDRVSTAT, WRITE, struct_floppy_drive_struct_sz); + _(FDGETDRVTYP, WRITE, 16); + _(FDGETFDCSTAT, WRITE, struct_floppy_fdc_state_sz); + _(FDGETMAXERRS, WRITE, struct_floppy_max_errors_sz); + _(FDGETPRM, WRITE, struct_floppy_struct_sz); + _(FDMSGOFF, NONE, 0); + _(FDMSGON, NONE, 0); + _(FDPOLLDRVSTAT, WRITE, struct_floppy_drive_struct_sz); + _(FDRAWCMD, WRITE, struct_floppy_raw_cmd_sz); + _(FDRESET, NONE, 0); + _(FDSETDRVPRM, READ, struct_floppy_drive_params_sz); + _(FDSETEMSGTRESH, NONE, 0); + _(FDSETMAXERRS, READ, struct_floppy_max_errors_sz); + _(FDSETPRM, READ, struct_floppy_struct_sz); + _(FDTWADDLE, NONE, 0); + _(FDWERRORCLR, NONE, 0); + _(FDWERRORGET, WRITE, struct_floppy_write_errors_sz); + _(HDIO_DRIVE_CMD, WRITE, sizeof(int)); + _(HDIO_GETGEO, WRITE, struct_hd_geometry_sz); + _(HDIO_GET_32BIT, WRITE, sizeof(int)); + _(HDIO_GET_DMA, WRITE, sizeof(int)); + _(HDIO_GET_IDENTITY, WRITE, struct_hd_driveid_sz); + _(HDIO_GET_KEEPSETTINGS, WRITE, sizeof(int)); + _(HDIO_GET_MULTCOUNT, WRITE, sizeof(int)); + _(HDIO_GET_NOWERR, WRITE, sizeof(int)); + _(HDIO_GET_UNMASKINTR, WRITE, sizeof(int)); + _(HDIO_SET_32BIT, NONE, 0); + _(HDIO_SET_DMA, NONE, 0); + _(HDIO_SET_KEEPSETTINGS, NONE, 0); + _(HDIO_SET_MULTCOUNT, NONE, 0); + _(HDIO_SET_NOWERR, NONE, 0); + _(HDIO_SET_UNMASKINTR, NONE, 0); + _(MTIOCGET, WRITE, struct_mtget_sz); + _(MTIOCPOS, WRITE, struct_mtpos_sz); + _(MTIOCTOP, READ, struct_mtop_sz); + _(PPPIOCGASYNCMAP, WRITE, sizeof(int)); + _(PPPIOCGDEBUG, WRITE, sizeof(int)); + _(PPPIOCGFLAGS, WRITE, sizeof(int)); + _(PPPIOCGUNIT, WRITE, sizeof(int)); + _(PPPIOCGXASYNCMAP, WRITE, sizeof(int) * 8); + _(PPPIOCSASYNCMAP, READ, sizeof(int)); + _(PPPIOCSDEBUG, READ, sizeof(int)); + _(PPPIOCSFLAGS, READ, sizeof(int)); + _(PPPIOCSMAXCID, READ, sizeof(int)); + _(PPPIOCSMRU, READ, sizeof(int)); + _(PPPIOCSXASYNCMAP, READ, sizeof(int) * 8); + _(SIOCADDRT, READ, struct_rtentry_sz); + _(SIOCDARP, READ, struct_arpreq_sz); + _(SIOCDELRT, READ, struct_rtentry_sz); + _(SIOCDRARP, READ, struct_arpreq_sz); + _(SIOCGARP, WRITE, struct_arpreq_sz); + _(SIOCGIFENCAP, WRITE, sizeof(int)); + _(SIOCGIFHWADDR, WRITE, struct_ifreq_sz); + _(SIOCGIFMAP, WRITE, struct_ifreq_sz); + _(SIOCGIFMEM, WRITE, struct_ifreq_sz); + _(SIOCGIFNAME, NONE, 0); + _(SIOCGIFSLAVE, NONE, 0); + _(SIOCGRARP, WRITE, struct_arpreq_sz); + _(SIOCGSTAMP, WRITE, timeval_sz); + _(SIOCSARP, READ, struct_arpreq_sz); + _(SIOCSIFENCAP, READ, sizeof(int)); + _(SIOCSIFHWADDR, READ, struct_ifreq_sz); + _(SIOCSIFLINK, NONE, 0); + _(SIOCSIFMAP, READ, struct_ifreq_sz); + _(SIOCSIFMEM, READ, struct_ifreq_sz); + _(SIOCSIFSLAVE, NONE, 0); + _(SIOCSRARP, READ, struct_arpreq_sz); + _(SNDCTL_COPR_HALT, WRITE, struct_copr_debug_buf_sz); + _(SNDCTL_COPR_LOAD, READ, struct_copr_buffer_sz); + _(SNDCTL_COPR_RCODE, WRITE, struct_copr_debug_buf_sz); + _(SNDCTL_COPR_RCVMSG, WRITE, struct_copr_msg_sz); + _(SNDCTL_COPR_RDATA, WRITE, struct_copr_debug_buf_sz); + _(SNDCTL_COPR_RESET, NONE, 0); + _(SNDCTL_COPR_RUN, WRITE, struct_copr_debug_buf_sz); + _(SNDCTL_COPR_SENDMSG, READ, struct_copr_msg_sz); + _(SNDCTL_COPR_WCODE, READ, struct_copr_debug_buf_sz); + _(SNDCTL_COPR_WDATA, READ, struct_copr_debug_buf_sz); + _(SNDCTL_DSP_GETBLKSIZE, WRITE, sizeof(int)); + _(SNDCTL_DSP_GETFMTS, WRITE, sizeof(int)); + _(SNDCTL_DSP_NONBLOCK, NONE, 0); + _(SNDCTL_DSP_POST, NONE, 0); + _(SNDCTL_DSP_RESET, NONE, 0); + _(SNDCTL_DSP_SETFMT, WRITE, sizeof(int)); + _(SNDCTL_DSP_SETFRAGMENT, WRITE, sizeof(int)); + _(SNDCTL_DSP_SPEED, WRITE, sizeof(int)); + _(SNDCTL_DSP_STEREO, WRITE, sizeof(int)); + _(SNDCTL_DSP_SUBDIVIDE, WRITE, sizeof(int)); + _(SNDCTL_DSP_SYNC, NONE, 0); + _(SNDCTL_FM_4OP_ENABLE, READ, sizeof(int)); + _(SNDCTL_FM_LOAD_INSTR, READ, struct_sbi_instrument_sz); + _(SNDCTL_MIDI_INFO, WRITE, struct_midi_info_sz); + _(SNDCTL_MIDI_PRETIME, WRITE, sizeof(int)); + _(SNDCTL_SEQ_CTRLRATE, WRITE, sizeof(int)); + _(SNDCTL_SEQ_GETINCOUNT, WRITE, sizeof(int)); + _(SNDCTL_SEQ_GETOUTCOUNT, WRITE, sizeof(int)); + _(SNDCTL_SEQ_NRMIDIS, WRITE, sizeof(int)); + _(SNDCTL_SEQ_NRSYNTHS, WRITE, sizeof(int)); + _(SNDCTL_SEQ_OUTOFBAND, READ, struct_seq_event_rec_sz); + _(SNDCTL_SEQ_PANIC, NONE, 0); + _(SNDCTL_SEQ_PERCMODE, NONE, 0); + _(SNDCTL_SEQ_RESET, NONE, 0); + _(SNDCTL_SEQ_RESETSAMPLES, READ, sizeof(int)); + _(SNDCTL_SEQ_SYNC, NONE, 0); + _(SNDCTL_SEQ_TESTMIDI, READ, sizeof(int)); + _(SNDCTL_SEQ_THRESHOLD, READ, sizeof(int)); + _(SNDCTL_SYNTH_INFO, WRITE, struct_synth_info_sz); + _(SNDCTL_SYNTH_MEMAVL, WRITE, sizeof(int)); + _(SNDCTL_TMR_METRONOME, READ, sizeof(int)); + _(SNDCTL_TMR_SELECT, WRITE, sizeof(int)); + _(SNDCTL_TMR_SOURCE, WRITE, sizeof(int)); + _(SNDCTL_TMR_TEMPO, WRITE, sizeof(int)); + _(SNDCTL_TMR_TIMEBASE, WRITE, sizeof(int)); + _(SOUND_MIXER_READ_ALTPCM, WRITE, sizeof(int)); + _(SOUND_MIXER_READ_BASS, WRITE, sizeof(int)); + _(SOUND_MIXER_READ_CAPS, WRITE, sizeof(int)); + _(SOUND_MIXER_READ_CD, WRITE, sizeof(int)); + _(SOUND_MIXER_READ_DEVMASK, WRITE, sizeof(int)); + _(SOUND_MIXER_READ_ENHANCE, WRITE, sizeof(int)); + _(SOUND_MIXER_READ_IGAIN, WRITE, sizeof(int)); + _(SOUND_MIXER_READ_IMIX, WRITE, sizeof(int)); + _(SOUND_MIXER_READ_LINE, WRITE, sizeof(int)); + _(SOUND_MIXER_READ_LINE1, WRITE, sizeof(int)); + _(SOUND_MIXER_READ_LINE2, WRITE, sizeof(int)); + _(SOUND_MIXER_READ_LINE3, WRITE, sizeof(int)); + _(SOUND_MIXER_READ_MIC, WRITE, sizeof(int)); + _(SOUND_MIXER_READ_OGAIN, WRITE, sizeof(int)); + _(SOUND_MIXER_READ_PCM, WRITE, sizeof(int)); + _(SOUND_MIXER_READ_RECLEV, WRITE, sizeof(int)); + _(SOUND_MIXER_READ_RECMASK, WRITE, sizeof(int)); + _(SOUND_MIXER_READ_RECSRC, WRITE, sizeof(int)); + _(SOUND_MIXER_READ_SPEAKER, WRITE, sizeof(int)); + _(SOUND_MIXER_READ_STEREODEVS, WRITE, sizeof(int)); + _(SOUND_MIXER_READ_SYNTH, WRITE, sizeof(int)); + _(SOUND_MIXER_READ_TREBLE, WRITE, sizeof(int)); + _(SOUND_MIXER_READ_VOLUME, WRITE, sizeof(int)); + _(SOUND_MIXER_WRITE_ALTPCM, WRITE, sizeof(int)); + _(SOUND_MIXER_WRITE_BASS, WRITE, sizeof(int)); + _(SOUND_MIXER_WRITE_CD, WRITE, sizeof(int)); + _(SOUND_MIXER_WRITE_ENHANCE, WRITE, sizeof(int)); + _(SOUND_MIXER_WRITE_IGAIN, WRITE, sizeof(int)); + _(SOUND_MIXER_WRITE_IMIX, WRITE, sizeof(int)); + _(SOUND_MIXER_WRITE_LINE, WRITE, sizeof(int)); + _(SOUND_MIXER_WRITE_LINE1, WRITE, sizeof(int)); + _(SOUND_MIXER_WRITE_LINE2, WRITE, sizeof(int)); + _(SOUND_MIXER_WRITE_LINE3, WRITE, sizeof(int)); + _(SOUND_MIXER_WRITE_MIC, WRITE, sizeof(int)); + _(SOUND_MIXER_WRITE_OGAIN, WRITE, sizeof(int)); + _(SOUND_MIXER_WRITE_PCM, WRITE, sizeof(int)); + _(SOUND_MIXER_WRITE_RECLEV, WRITE, sizeof(int)); + _(SOUND_MIXER_WRITE_RECSRC, WRITE, sizeof(int)); + _(SOUND_MIXER_WRITE_SPEAKER, WRITE, sizeof(int)); + _(SOUND_MIXER_WRITE_SYNTH, WRITE, sizeof(int)); + _(SOUND_MIXER_WRITE_TREBLE, WRITE, sizeof(int)); + _(SOUND_MIXER_WRITE_VOLUME, WRITE, sizeof(int)); + _(SOUND_PCM_READ_BITS, WRITE, sizeof(int)); + _(SOUND_PCM_READ_CHANNELS, WRITE, sizeof(int)); + _(SOUND_PCM_READ_FILTER, WRITE, sizeof(int)); + _(SOUND_PCM_READ_RATE, WRITE, sizeof(int)); + _(SOUND_PCM_WRITE_CHANNELS, WRITE, sizeof(int)); + _(SOUND_PCM_WRITE_FILTER, WRITE, sizeof(int)); + _(TCFLSH, NONE, 0); +#if SANITIZER_GLIBC + _(TCGETA, WRITE, struct_termio_sz); +#endif + _(TCGETS, WRITE, struct_termios_sz); + _(TCSBRK, NONE, 0); + _(TCSBRKP, NONE, 0); +#if SANITIZER_GLIBC + _(TCSETA, READ, struct_termio_sz); + _(TCSETAF, READ, struct_termio_sz); + _(TCSETAW, READ, struct_termio_sz); +#endif + _(TCSETS, READ, struct_termios_sz); + _(TCSETSF, READ, struct_termios_sz); + _(TCSETSW, READ, struct_termios_sz); + _(TCXONC, NONE, 0); + _(TIOCGLCKTRMIOS, WRITE, struct_termios_sz); + _(TIOCGSOFTCAR, WRITE, sizeof(int)); + _(TIOCINQ, WRITE, sizeof(int)); + _(TIOCLINUX, READ, sizeof(char)); + _(TIOCSERCONFIG, NONE, 0); + _(TIOCSERGETLSR, WRITE, sizeof(int)); + _(TIOCSERGWILD, WRITE, sizeof(int)); + _(TIOCSERSWILD, READ, sizeof(int)); + _(TIOCSLCKTRMIOS, READ, struct_termios_sz); + _(TIOCSSOFTCAR, READ, sizeof(int)); + _(VT_ACTIVATE, NONE, 0); + _(VT_DISALLOCATE, NONE, 0); + _(VT_GETMODE, WRITE, struct_vt_mode_sz); + _(VT_GETSTATE, WRITE, struct_vt_stat_sz); + _(VT_OPENQRY, WRITE, sizeof(int)); + _(VT_RELDISP, NONE, 0); + _(VT_RESIZE, READ, struct_vt_sizes_sz); + _(VT_RESIZEX, READ, struct_vt_consize_sz); + _(VT_SENDSIG, NONE, 0); + _(VT_SETMODE, READ, struct_vt_mode_sz); + _(VT_WAITACTIVE, NONE, 0); +#endif + +#if SANITIZER_GLIBC + // _(SIOCDEVPLIP, WRITE, struct_ifreq_sz); // the same as EQL_ENSLAVE + _(EQL_EMANCIPATE, WRITE, struct_ifreq_sz); + _(EQL_ENSLAVE, WRITE, struct_ifreq_sz); + _(EQL_GETMASTRCFG, WRITE, struct_ifreq_sz); + _(EQL_GETSLAVECFG, WRITE, struct_ifreq_sz); + _(EQL_SETMASTRCFG, WRITE, struct_ifreq_sz); + _(EQL_SETSLAVECFG, WRITE, struct_ifreq_sz); + _(EVIOCGKEYCODE_V2, WRITE, struct_input_keymap_entry_sz); + _(EVIOCGPROP, WRITE, 0); + _(EVIOCSKEYCODE_V2, READ, struct_input_keymap_entry_sz); + _(FS_IOC_GETFLAGS, WRITE, sizeof(int)); + _(FS_IOC_GETVERSION, WRITE, sizeof(int)); + _(FS_IOC_SETFLAGS, READ, sizeof(int)); + _(FS_IOC_SETVERSION, READ, sizeof(int)); + _(GIO_CMAP, WRITE, 48); + _(GIO_FONT, WRITE, 8192); + _(GIO_SCRNMAP, WRITE, e_tabsz); + _(GIO_UNIMAP, WRITE, struct_unimapdesc_sz); + _(GIO_UNISCRNMAP, WRITE, sizeof(short) * e_tabsz); + _(KDADDIO, NONE, 0); + _(KDDELIO, NONE, 0); + _(KDDISABIO, NONE, 0); + _(KDENABIO, NONE, 0); + _(KDGETKEYCODE, WRITE, struct_kbkeycode_sz); + _(KDGETLED, WRITE, 1); + _(KDGETMODE, WRITE, sizeof(int)); + _(KDGKBDIACR, WRITE, struct_kbdiacrs_sz); + _(KDGKBENT, WRITE, struct_kbentry_sz); + _(KDGKBLED, WRITE, sizeof(int)); + _(KDGKBMETA, WRITE, sizeof(int)); + _(KDGKBMODE, WRITE, sizeof(int)); + _(KDGKBSENT, WRITE, struct_kbsentry_sz); + _(KDGKBTYPE, WRITE, 1); + _(KDMAPDISP, NONE, 0); + _(KDMKTONE, NONE, 0); + _(KDSETKEYCODE, READ, struct_kbkeycode_sz); + _(KDSETLED, NONE, 0); + _(KDSETMODE, NONE, 0); + _(KDSIGACCEPT, NONE, 0); + _(KDSKBDIACR, READ, struct_kbdiacrs_sz); + _(KDSKBENT, READ, struct_kbentry_sz); + _(KDSKBLED, NONE, 0); + _(KDSKBMETA, NONE, 0); + _(KDSKBMODE, NONE, 0); + _(KDSKBSENT, READ, struct_kbsentry_sz); + _(KDUNMAPDISP, NONE, 0); + _(KIOCSOUND, NONE, 0); + _(LPABORT, NONE, 0); + _(LPABORTOPEN, NONE, 0); + _(LPCAREFUL, NONE, 0); + _(LPCHAR, NONE, 0); + _(LPGETIRQ, WRITE, sizeof(int)); + _(LPGETSTATUS, WRITE, sizeof(int)); + _(LPRESET, NONE, 0); + _(LPSETIRQ, NONE, 0); + _(LPTIME, NONE, 0); + _(LPWAIT, NONE, 0); + _(MTIOCGETCONFIG, WRITE, struct_mtconfiginfo_sz); + _(MTIOCSETCONFIG, READ, struct_mtconfiginfo_sz); + _(PIO_CMAP, NONE, 0); + _(PIO_FONT, READ, 8192); + _(PIO_SCRNMAP, READ, e_tabsz); + _(PIO_UNIMAP, READ, struct_unimapdesc_sz); + _(PIO_UNIMAPCLR, READ, struct_unimapinit_sz); + _(PIO_UNISCRNMAP, READ, sizeof(short) * e_tabsz); + _(SCSI_IOCTL_PROBE_HOST, READ, sizeof(int)); + _(SCSI_IOCTL_TAGGED_DISABLE, NONE, 0); + _(SCSI_IOCTL_TAGGED_ENABLE, NONE, 0); + _(SNDCTL_DSP_GETISPACE, WRITE, struct_audio_buf_info_sz); + _(SNDCTL_DSP_GETOSPACE, WRITE, struct_audio_buf_info_sz); + _(TIOCGSERIAL, WRITE, struct_serial_struct_sz); + _(TIOCSERGETMULTI, WRITE, struct_serial_multiport_struct_sz); + _(TIOCSERSETMULTI, READ, struct_serial_multiport_struct_sz); + _(TIOCSSERIAL, READ, struct_serial_struct_sz); + + // The following ioctl requests are shared between AX25, IPX, netrom and + // mrouted. + // _(SIOCAIPXITFCRT, READ, sizeof(char)); + // _(SIOCAX25GETUID, READ, struct_sockaddr_ax25_sz); + // _(SIOCNRGETPARMS, WRITE, struct_nr_parms_struct_sz); + // _(SIOCAIPXPRISLT, READ, sizeof(char)); + // _(SIOCNRSETPARMS, READ, struct_nr_parms_struct_sz); + // _(SIOCAX25ADDUID, READ, struct_sockaddr_ax25_sz); + // _(SIOCNRDECOBS, NONE, 0); + // _(SIOCAX25DELUID, READ, struct_sockaddr_ax25_sz); + // _(SIOCIPXCFGDATA, WRITE, struct_ipx_config_data_sz); + // _(SIOCAX25NOUID, READ, sizeof(int)); + // _(SIOCNRRTCTL, READ, sizeof(int)); + // _(SIOCAX25DIGCTL, READ, sizeof(int)); + // _(SIOCAX25GETPARMS, WRITE, struct_ax25_parms_struct_sz); + // _(SIOCAX25SETPARMS, READ, struct_ax25_parms_struct_sz); +#endif +#undef _ +} + +static bool ioctl_initialized = false; + +struct ioctl_desc_compare { + bool operator()(const ioctl_desc& left, const ioctl_desc& right) const { + return left.req < right.req; + } +}; + +static void ioctl_init() { + ioctl_table_fill(); + Sort(ioctl_table, ioctl_table_size, ioctl_desc_compare()); + + bool bad = false; + for (unsigned i = 0; i < ioctl_table_size - 1; ++i) { + if (ioctl_table[i].req >= ioctl_table[i + 1].req) { + Printf("Duplicate or unsorted ioctl request id %x >= %x (%s vs %s)\n", + ioctl_table[i].req, ioctl_table[i + 1].req, ioctl_table[i].name, + ioctl_table[i + 1].name); + bad = true; + } + } + + if (bad) Die(); + + ioctl_initialized = true; +} + +// Handle the most evil ioctls that encode argument value as part of request id. +static unsigned ioctl_request_fixup(unsigned req) { +#if SANITIZER_LINUX + // Strip size and event number. + const unsigned kEviocgbitMask = + (IOC_SIZEMASK << IOC_SIZESHIFT) | EVIOC_EV_MAX; + if ((req & ~kEviocgbitMask) == IOCTL_EVIOCGBIT) + return IOCTL_EVIOCGBIT; + // Strip absolute axis number. + if ((req & ~EVIOC_ABS_MAX) == IOCTL_EVIOCGABS) + return IOCTL_EVIOCGABS; + if ((req & ~EVIOC_ABS_MAX) == IOCTL_EVIOCSABS) + return IOCTL_EVIOCSABS; +#endif + return req; +} + +static const ioctl_desc *ioctl_table_lookup(unsigned req) { + int left = 0; + int right = ioctl_table_size; + while (left < right) { + int mid = (left + right) / 2; + if (ioctl_table[mid].req < req) + left = mid + 1; + else + right = mid; + } + if (left == right && ioctl_table[left].req == req) + return ioctl_table + left; + else + return nullptr; +} + +static bool ioctl_decode(unsigned req, ioctl_desc *desc) { + CHECK(desc); + desc->req = req; + desc->name = "<DECODED_IOCTL>"; + desc->size = IOC_SIZE(req); + // Sanity check. + if (desc->size > 0xFFFF) return false; + unsigned dir = IOC_DIR(req); + switch (dir) { + case IOC_NONE: + desc->type = ioctl_desc::NONE; + break; + case IOC_READ | IOC_WRITE: + desc->type = ioctl_desc::READWRITE; + break; + case IOC_READ: + desc->type = ioctl_desc::WRITE; + break; + case IOC_WRITE: + desc->type = ioctl_desc::READ; + break; + default: + return false; + } + // Size can be 0 iff type is NONE. + if ((desc->type == IOC_NONE) != (desc->size == 0)) return false; + // Sanity check. + if (IOC_TYPE(req) == 0) return false; + return true; +} + +static const ioctl_desc *ioctl_lookup(unsigned req) { + req = ioctl_request_fixup(req); + const ioctl_desc *desc = ioctl_table_lookup(req); + if (desc) return desc; + + // Try stripping access size from the request id. + desc = ioctl_table_lookup(req & ~(IOC_SIZEMASK << IOC_SIZESHIFT)); + // Sanity check: requests that encode access size are either read or write and + // have size of 0 in the table. + if (desc && desc->size == 0 && + (desc->type == ioctl_desc::READWRITE || desc->type == ioctl_desc::WRITE || + desc->type == ioctl_desc::READ)) + return desc; + return nullptr; +} + +static void ioctl_common_pre(void *ctx, const ioctl_desc *desc, int d, + unsigned request, void *arg) { + if (desc->type == ioctl_desc::READ || desc->type == ioctl_desc::READWRITE) { + unsigned size = desc->size ? desc->size : IOC_SIZE(request); + COMMON_INTERCEPTOR_READ_RANGE(ctx, arg, size); + } + if (desc->type != ioctl_desc::CUSTOM) + return; + if (request == IOCTL_SIOCGIFCONF) { + struct __sanitizer_ifconf *ifc = (__sanitizer_ifconf *)arg; + COMMON_INTERCEPTOR_READ_RANGE(ctx, (char*)&ifc->ifc_len, + sizeof(ifc->ifc_len)); + } +} + +static void ioctl_common_post(void *ctx, const ioctl_desc *desc, int res, int d, + unsigned request, void *arg) { + if (desc->type == ioctl_desc::WRITE || desc->type == ioctl_desc::READWRITE) { + // FIXME: add verbose output + unsigned size = desc->size ? desc->size : IOC_SIZE(request); + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, arg, size); + } + if (desc->type != ioctl_desc::CUSTOM) + return; + if (request == IOCTL_SIOCGIFCONF) { + struct __sanitizer_ifconf *ifc = (__sanitizer_ifconf *)arg; + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ifc->ifc_ifcu.ifcu_req, ifc->ifc_len); + } +} + +#endif diff --git a/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_common_interceptors_netbsd_compat.inc b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_common_interceptors_netbsd_compat.inc new file mode 100644 index 0000000000..f6ac3fa5af --- /dev/null +++ b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_common_interceptors_netbsd_compat.inc @@ -0,0 +1,128 @@ +//===-- sanitizer_common_interceptors_netbsd_compat.inc ---------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// Common function interceptors for tools like AddressSanitizer, +// ThreadSanitizer, MemorySanitizer, etc. +// +// Interceptors for NetBSD old function calls that have been versioned. +// +// NetBSD minimal version supported 9.0. +// NetBSD current version supported 9.99.26. +// +//===----------------------------------------------------------------------===// + +#if SANITIZER_NETBSD + +// First undef all mangled symbols. +// Next, define compat interceptors. +// Finally, undef INIT_ and redefine it. +// This allows to avoid preprocessor issues. + +#undef fstatvfs +#undef fstatvfs1 +#undef getmntinfo +#undef getvfsstat +#undef statvfs +#undef statvfs1 + +INTERCEPTOR(int, statvfs, char *path, void *buf) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, statvfs, path, buf); + if (path) COMMON_INTERCEPTOR_READ_RANGE(ctx, path, internal_strlen(path) + 1); + // FIXME: under ASan the call below may write to freed memory and corrupt + // its metadata. See + // https://github.com/google/sanitizers/issues/321. + int res = REAL(statvfs)(path, buf); + if (!res) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, struct_statvfs90_sz); + return res; +} + +INTERCEPTOR(int, fstatvfs, int fd, void *buf) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, fstatvfs, fd, buf); + COMMON_INTERCEPTOR_FD_ACCESS(ctx, fd); + // FIXME: under ASan the call below may write to freed memory and corrupt + // its metadata. See + // https://github.com/google/sanitizers/issues/321. + int res = REAL(fstatvfs)(fd, buf); + if (!res) { + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, struct_statvfs90_sz); + if (fd >= 0) + COMMON_INTERCEPTOR_FD_ACQUIRE(ctx, fd); + } + return res; +} + +#undef INIT_STATVFS +#define INIT_STATVFS \ + COMMON_INTERCEPT_FUNCTION(statvfs); \ + COMMON_INTERCEPT_FUNCTION(fstatvfs); \ + COMMON_INTERCEPT_FUNCTION(__statvfs90); \ + COMMON_INTERCEPT_FUNCTION(__fstatvfs90) + +INTERCEPTOR(int, __getmntinfo13, void **mntbufp, int flags) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, __getmntinfo13, mntbufp, flags); + int cnt = REAL(__getmntinfo13)(mntbufp, flags); + if (cnt > 0 && mntbufp) { + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, mntbufp, sizeof(void *)); + if (*mntbufp) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, *mntbufp, cnt * struct_statvfs90_sz); + } + return cnt; +} + +#undef INIT_GETMNTINFO +#define INIT_GETMNTINFO \ + COMMON_INTERCEPT_FUNCTION(__getmntinfo13); \ + COMMON_INTERCEPT_FUNCTION(__getmntinfo90) + +INTERCEPTOR(int, getvfsstat, void *buf, SIZE_T bufsize, int flags) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, getvfsstat, buf, bufsize, flags); + int ret = REAL(getvfsstat)(buf, bufsize, flags); + if (buf && ret > 0) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, ret * struct_statvfs90_sz); + return ret; +} + +#undef INIT_GETVFSSTAT +#define INIT_GETVFSSTAT \ + COMMON_INTERCEPT_FUNCTION(getvfsstat); \ + COMMON_INTERCEPT_FUNCTION(__getvfsstat90) + +INTERCEPTOR(int, statvfs1, const char *path, void *buf, int flags) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, statvfs1, path, buf, flags); + if (path) COMMON_INTERCEPTOR_READ_RANGE(ctx, path, internal_strlen(path) + 1); + int res = REAL(statvfs1)(path, buf, flags); + if (!res) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, struct_statvfs90_sz); + return res; +} + +INTERCEPTOR(int, fstatvfs1, int fd, void *buf, int flags) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, fstatvfs1, fd, buf, flags); + COMMON_INTERCEPTOR_FD_ACCESS(ctx, fd); + int res = REAL(fstatvfs1)(fd, buf, flags); + if (!res) { + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, struct_statvfs90_sz); + if (fd >= 0) + COMMON_INTERCEPTOR_FD_ACQUIRE(ctx, fd); + } + return res; +} + +#undef INIT_STATVFS1 +#define INIT_STATVFS1 \ + COMMON_INTERCEPT_FUNCTION(statvfs1); \ + COMMON_INTERCEPT_FUNCTION(fstatvfs1); \ + COMMON_INTERCEPT_FUNCTION(__statvfs190); \ + COMMON_INTERCEPT_FUNCTION(__fstatvfs190) + +#endif diff --git a/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_common_interceptors_vfork_aarch64.inc.S b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_common_interceptors_vfork_aarch64.inc.S new file mode 100644 index 0000000000..72e482754b --- /dev/null +++ b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_common_interceptors_vfork_aarch64.inc.S @@ -0,0 +1,48 @@ +#if defined(__aarch64__) && defined(__linux__) + +#include "sanitizer_common/sanitizer_asm.h" +#include "builtins/assembly.h" + +ASM_HIDDEN(COMMON_INTERCEPTOR_SPILL_AREA) + +.comm _ZN14__interception10real_vforkE,8,8 +.globl ASM_WRAPPER_NAME(vfork) +ASM_TYPE_FUNCTION(ASM_WRAPPER_NAME(vfork)) +ASM_WRAPPER_NAME(vfork): + // Save x30 in the off-stack spill area. + hint #25 // paciasp + stp xzr, x30, [sp, #-16]! + bl COMMON_INTERCEPTOR_SPILL_AREA + ldp xzr, x30, [sp], 16 + str x30, [x0] + + // Call real vfork. This may return twice. User code that runs between the first and the second return + // may clobber the stack frame of the interceptor; that's why it does not have a frame. + adrp x0, _ZN14__interception10real_vforkE + ldr x0, [x0, :lo12:_ZN14__interception10real_vforkE] + blr x0 + + stp x0, xzr, [sp, #-16]! + cmp x0, #0 + b.eq .L_exit + + // x0 != 0 => parent process. Clear stack shadow. + add x0, sp, #16 + bl COMMON_INTERCEPTOR_HANDLE_VFORK + +.L_exit: + // Restore x30. + bl COMMON_INTERCEPTOR_SPILL_AREA + ldr x30, [x0] + ldp x0, xzr, [sp], 16 + hint #29 // autiasp + + ret +ASM_SIZE(vfork) + +.weak vfork +.set vfork, ASM_WRAPPER_NAME(vfork) + +GNU_PROPERTY_BTI_PAC + +#endif diff --git a/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_common_interceptors_vfork_arm.inc.S b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_common_interceptors_vfork_arm.inc.S new file mode 100644 index 0000000000..780a9d46e2 --- /dev/null +++ b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_common_interceptors_vfork_arm.inc.S @@ -0,0 +1,49 @@ +#if defined(__arm__) && defined(__linux__) + +#include "sanitizer_common/sanitizer_asm.h" + +ASM_HIDDEN(COMMON_INTERCEPTOR_SPILL_AREA) + +.comm _ZN14__interception10real_vforkE,4,4 +.globl ASM_WRAPPER_NAME(vfork) +ASM_TYPE_FUNCTION(ASM_WRAPPER_NAME(vfork)) +ASM_WRAPPER_NAME(vfork): + // Save LR in the off-stack spill area. + push {r4, lr} + bl COMMON_INTERCEPTOR_SPILL_AREA + pop {r4, lr} + str lr, [r0] + + // Call real vfork. This may return twice. User code that runs between the first and the second return + // may clobber the stack frame of the interceptor; that's why it does not have a frame. + ldr r0, .LCPI0_0 +.LPC0_0: + ldr r0, [pc, r0] + mov lr, pc + bx r0 + + push {r0, r4} + cmp r0, #0 + beq .L_exit + + // r0 != 0 => parent process. Clear stack shadow. + add r0, sp, #8 + bl COMMON_INTERCEPTOR_HANDLE_VFORK + +.L_exit: + // Restore LR. + bl COMMON_INTERCEPTOR_SPILL_AREA + ldr lr, [r0] + pop {r0, r4} + + mov pc, lr + +.LCPI0_0: + .long _ZN14__interception10real_vforkE - (.LPC0_0+8) + +ASM_SIZE(vfork) + +.weak vfork +.set vfork, ASM_WRAPPER_NAME(vfork) + +#endif diff --git a/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_common_interceptors_vfork_i386.inc.S b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_common_interceptors_vfork_i386.inc.S new file mode 100644 index 0000000000..f60b05d157 --- /dev/null +++ b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_common_interceptors_vfork_i386.inc.S @@ -0,0 +1,64 @@ +#if defined(__i386__) && defined(__linux__) + +#include "sanitizer_common/sanitizer_asm.h" + +.comm _ZN14__interception10real_vforkE,4,4 +.globl ASM_WRAPPER_NAME(vfork) +ASM_TYPE_FUNCTION(ASM_WRAPPER_NAME(vfork)) +ASM_WRAPPER_NAME(vfork): + _CET_ENDBR + // Store return address in the spill area and tear down the stack frame. + sub $12, %esp + call COMMON_INTERCEPTOR_SPILL_AREA + mov 12(%esp), %ecx + mov %ecx, (%eax) + add $16, %esp + + call .L0$pb +.L0$pb: + pop %eax +.Ltmp0: + add $_GLOBAL_OFFSET_TABLE_+(.Ltmp0-.L0$pb), %eax + call *_ZN14__interception10real_vforkE@GOTOFF(%eax) + + // Restore the stack frame. + // 12(%esp) return address + // 8(%esp) spill %ebx + // 4(%esp) spill REAL(vfork) return value + // (%esp) call frame (arg0) for __*_handle_vfork + sub $16, %esp + mov %ebx, 8(%esp) + mov %eax, 4(%esp) + + // Form GOT address in %ebx. + call .L1$pb +.L1$pb: + pop %ebx +.Ltmp1: + add $_GLOBAL_OFFSET_TABLE_+(.Ltmp1-.L1$pb), %ebx + + // Restore original return address. + call COMMON_INTERCEPTOR_SPILL_AREA + mov (%eax), %ecx + mov %ecx, 12(%esp) + mov 4(%esp), %eax + + // Call handle_vfork in the parent process (%rax != 0). + test %eax, %eax + je .L_exit + + lea 16(%esp), %ecx + mov %ecx, (%esp) + call COMMON_INTERCEPTOR_HANDLE_VFORK@PLT + +.L_exit: + mov 4(%esp), %eax + mov 8(%esp), %ebx + add $12, %esp + ret +ASM_SIZE(vfork) + +.weak vfork +.set vfork, ASM_WRAPPER_NAME(vfork) + +#endif diff --git a/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_common_interceptors_vfork_riscv64.inc.S b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_common_interceptors_vfork_riscv64.inc.S new file mode 100644 index 0000000000..b7ec27859b --- /dev/null +++ b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_common_interceptors_vfork_riscv64.inc.S @@ -0,0 +1,56 @@ +#if (defined(__riscv) && (__riscv_xlen == 64)) && defined(__linux__) + +#include "sanitizer_common/sanitizer_asm.h" + +ASM_HIDDEN(COMMON_INTERCEPTOR_SPILL_AREA) + +.comm _ZN14__interception10real_vforkE,8,8 +.globl ASM_WRAPPER_NAME(vfork) +ASM_TYPE_FUNCTION(ASM_WRAPPER_NAME(vfork)) +ASM_WRAPPER_NAME(vfork): + // Save ra in the off-stack spill area. + // allocate space on stack + addi sp, sp, -16 + // store ra value + sd ra, 8(sp) + call COMMON_INTERCEPTOR_SPILL_AREA + // restore previous values from stack + ld ra, 8(sp) + // adjust stack + addi sp, sp, 16 + // store ra by x10 + sd ra, 0(x10) + + // Call real vfork. This may return twice. User code that runs between the first and the second return + // may clobber the stack frame of the interceptor; that's why it does not have a frame. + la x10, _ZN14__interception10real_vforkE + ld x10, 0(x10) + jalr x10 + + // adjust stack + addi sp, sp, -16 + // store x10 by adjusted stack + sd x10, 8(sp) + // jump to exit label if x10 is 0 + beqz x10, .L_exit + + // x0 != 0 => parent process. Clear stack shadow. + // put old sp to x10 + addi x10, sp, 16 + call COMMON_INTERCEPTOR_HANDLE_VFORK + +.L_exit: + // Restore ra + call COMMON_INTERCEPTOR_SPILL_AREA + ld ra, 0(x10) + // load value by stack + ld x10, 8(sp) + // adjust stack + addi sp, sp, 16 + ret +ASM_SIZE(vfork) + +.weak vfork +.set vfork, ASM_WRAPPER_NAME(vfork) + +#endif diff --git a/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_common_interceptors_vfork_x86_64.inc.S b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_common_interceptors_vfork_x86_64.inc.S new file mode 100644 index 0000000000..8fd18ea67f --- /dev/null +++ b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_common_interceptors_vfork_x86_64.inc.S @@ -0,0 +1,42 @@ +#if defined(__x86_64__) && defined(__linux__) + +#include "sanitizer_common/sanitizer_asm.h" + +.comm _ZN14__interception10real_vforkE,8,8 +.globl ASM_WRAPPER_NAME(vfork) +ASM_TYPE_FUNCTION(ASM_WRAPPER_NAME(vfork)) +ASM_WRAPPER_NAME(vfork): + _CET_ENDBR + // Store return address in the spill area and tear down the stack frame. + push %rcx + call COMMON_INTERCEPTOR_SPILL_AREA + pop %rcx + pop %rdi + mov %rdi, (%rax) + + call *_ZN14__interception10real_vforkE(%rip) + + // Restore return address from the spill area. + push %rcx + push %rax + call COMMON_INTERCEPTOR_SPILL_AREA + mov (%rax), %rdx + mov %rdx, 8(%rsp) + mov (%rsp), %rax + + // Call handle_vfork in the parent process (%rax != 0). + test %rax, %rax + je .L_exit + + lea 16(%rsp), %rdi + call COMMON_INTERCEPTOR_HANDLE_VFORK@PLT + +.L_exit: + pop %rax + ret +ASM_SIZE(vfork) + +.weak vfork +.set vfork, ASM_WRAPPER_NAME(vfork) + +#endif diff --git a/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_common_interface.inc b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_common_interface.inc new file mode 100644 index 0000000000..932e547861 --- /dev/null +++ b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_common_interface.inc @@ -0,0 +1,42 @@ +//===-- sanitizer_common_interface.inc ------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// Sanitizer Common interface list. +//===----------------------------------------------------------------------===// +INTERFACE_FUNCTION(__sanitizer_acquire_crash_state) +INTERFACE_FUNCTION(__sanitizer_annotate_contiguous_container) +INTERFACE_FUNCTION(__sanitizer_contiguous_container_find_bad_address) +INTERFACE_FUNCTION(__sanitizer_set_death_callback) +INTERFACE_FUNCTION(__sanitizer_set_report_path) +INTERFACE_FUNCTION(__sanitizer_set_report_fd) +INTERFACE_FUNCTION(__sanitizer_get_report_path) +INTERFACE_FUNCTION(__sanitizer_verify_contiguous_container) +INTERFACE_WEAK_FUNCTION(__sanitizer_on_print) +INTERFACE_WEAK_FUNCTION(__sanitizer_report_error_summary) +INTERFACE_WEAK_FUNCTION(__sanitizer_sandbox_on_notify) +// Sanitizer weak hooks +INTERFACE_WEAK_FUNCTION(__sanitizer_weak_hook_memcmp) +INTERFACE_WEAK_FUNCTION(__sanitizer_weak_hook_strcmp) +INTERFACE_WEAK_FUNCTION(__sanitizer_weak_hook_strncmp) +INTERFACE_WEAK_FUNCTION(__sanitizer_weak_hook_strstr) +// Stacktrace interface. +INTERFACE_FUNCTION(__sanitizer_get_module_and_offset_for_pc) +INTERFACE_FUNCTION(__sanitizer_symbolize_global) +INTERFACE_FUNCTION(__sanitizer_symbolize_pc) +// Allocator interface. +INTERFACE_FUNCTION(__sanitizer_get_allocated_size) +INTERFACE_FUNCTION(__sanitizer_get_current_allocated_bytes) +INTERFACE_FUNCTION(__sanitizer_get_estimated_allocated_size) +INTERFACE_FUNCTION(__sanitizer_get_free_bytes) +INTERFACE_FUNCTION(__sanitizer_get_heap_size) +INTERFACE_FUNCTION(__sanitizer_get_ownership) +INTERFACE_FUNCTION(__sanitizer_get_unmapped_bytes) +INTERFACE_FUNCTION(__sanitizer_install_malloc_and_free_hooks) +INTERFACE_FUNCTION(__sanitizer_purge_allocator) +INTERFACE_FUNCTION(__sanitizer_print_memory_profile) +INTERFACE_WEAK_FUNCTION(__sanitizer_free_hook) +INTERFACE_WEAK_FUNCTION(__sanitizer_malloc_hook) diff --git a/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_common_interface_posix.inc b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_common_interface_posix.inc new file mode 100644 index 0000000000..a5259be933 --- /dev/null +++ b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_common_interface_posix.inc @@ -0,0 +1,15 @@ +//===-- sanitizer_common_interface_posix.inc ------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// Sanitizer Common interface list only available for Posix systems. +//===----------------------------------------------------------------------===// +INTERFACE_WEAK_FUNCTION(__sanitizer_symbolize_code) +INTERFACE_WEAK_FUNCTION(__sanitizer_symbolize_data) +INTERFACE_WEAK_FUNCTION(__sanitizer_symbolize_demangle) +INTERFACE_WEAK_FUNCTION(__sanitizer_symbolize_flush) +INTERFACE_WEAK_FUNCTION(__sanitizer_symbolize_set_demangle) +INTERFACE_WEAK_FUNCTION(__sanitizer_symbolize_set_inline_frames) diff --git a/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_common_libcdep.cpp b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_common_libcdep.cpp new file mode 100644 index 0000000000..c4cc0e4519 --- /dev/null +++ b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_common_libcdep.cpp @@ -0,0 +1,221 @@ +//===-- sanitizer_common_libcdep.cpp --------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file is shared between AddressSanitizer and ThreadSanitizer +// run-time libraries. +//===----------------------------------------------------------------------===// + +#include "sanitizer_allocator.h" +#include "sanitizer_allocator_interface.h" +#include "sanitizer_common.h" +#include "sanitizer_flags.h" +#include "sanitizer_procmaps.h" +#include "sanitizer_stackdepot.h" + +namespace __sanitizer { + +#if (SANITIZER_LINUX || SANITIZER_NETBSD) && !SANITIZER_GO +// Weak default implementation for when sanitizer_stackdepot is not linked in. +SANITIZER_WEAK_ATTRIBUTE StackDepotStats StackDepotGetStats() { return {}; } + +void *BackgroundThread(void *arg) { + VPrintf(1, "%s: Started BackgroundThread\n", SanitizerToolName); + const uptr hard_rss_limit_mb = common_flags()->hard_rss_limit_mb; + const uptr soft_rss_limit_mb = common_flags()->soft_rss_limit_mb; + const bool heap_profile = common_flags()->heap_profile; + uptr prev_reported_rss = 0; + uptr prev_reported_stack_depot_size = 0; + bool reached_soft_rss_limit = false; + uptr rss_during_last_reported_profile = 0; + while (true) { + SleepForMillis(100); + const uptr current_rss_mb = GetRSS() >> 20; + if (Verbosity()) { + // If RSS has grown 10% since last time, print some information. + if (prev_reported_rss * 11 / 10 < current_rss_mb) { + Printf("%s: RSS: %zdMb\n", SanitizerToolName, current_rss_mb); + prev_reported_rss = current_rss_mb; + } + // If stack depot has grown 10% since last time, print it too. + StackDepotStats stack_depot_stats = StackDepotGetStats(); + if (prev_reported_stack_depot_size * 11 / 10 < + stack_depot_stats.allocated) { + Printf("%s: StackDepot: %zd ids; %zdM allocated\n", SanitizerToolName, + stack_depot_stats.n_uniq_ids, stack_depot_stats.allocated >> 20); + prev_reported_stack_depot_size = stack_depot_stats.allocated; + } + } + // Check RSS against the limit. + if (hard_rss_limit_mb && hard_rss_limit_mb < current_rss_mb) { + Report("%s: hard rss limit exhausted (%zdMb vs %zdMb)\n", + SanitizerToolName, hard_rss_limit_mb, current_rss_mb); + DumpProcessMap(); + Die(); + } + if (soft_rss_limit_mb) { + if (soft_rss_limit_mb < current_rss_mb && !reached_soft_rss_limit) { + reached_soft_rss_limit = true; + Report("%s: soft rss limit exhausted (%zdMb vs %zdMb)\n", + SanitizerToolName, soft_rss_limit_mb, current_rss_mb); + SetRssLimitExceeded(true); + } else if (soft_rss_limit_mb >= current_rss_mb && + reached_soft_rss_limit) { + reached_soft_rss_limit = false; + SetRssLimitExceeded(false); + } + } + if (heap_profile && + current_rss_mb > rss_during_last_reported_profile * 1.1) { + Printf("\n\nHEAP PROFILE at RSS %zdMb\n", current_rss_mb); + __sanitizer_print_memory_profile(90, 20); + rss_during_last_reported_profile = current_rss_mb; + } + } +} + +void MaybeStartBackgroudThread() { + // Need to implement/test on other platforms. + // Start the background thread if one of the rss limits is given. + if (!common_flags()->hard_rss_limit_mb && + !common_flags()->soft_rss_limit_mb && + !common_flags()->heap_profile) return; + if (!&real_pthread_create) { + VPrintf(1, "%s: real_pthread_create undefined\n", SanitizerToolName); + return; // Can't spawn the thread anyway. + } + + static bool started = false; + if (!started) { + started = true; + internal_start_thread(BackgroundThread, nullptr); + } +} + +# if !SANITIZER_START_BACKGROUND_THREAD_IN_ASAN_INTERNAL +# pragma clang diagnostic push +// We avoid global-constructors to be sure that globals are ready when +// sanitizers need them. This can happend before global constructors executed. +// Here we don't mind if thread is started on later stages. +# pragma clang diagnostic ignored "-Wglobal-constructors" +static struct BackgroudThreadStarted { + BackgroudThreadStarted() { MaybeStartBackgroudThread(); } +} background_thread_strarter UNUSED; +# pragma clang diagnostic pop +# endif +#else +void MaybeStartBackgroudThread() {} +#endif + +void WriteToSyslog(const char *msg) { + InternalScopedString msg_copy; + msg_copy.append("%s", msg); + const char *p = msg_copy.data(); + + // Print one line at a time. + // syslog, at least on Android, has an implicit message length limit. + while (char* q = internal_strchr(p, '\n')) { + *q = '\0'; + WriteOneLineToSyslog(p); + p = q + 1; + } + // Print remaining characters, if there are any. + // Note that this will add an extra newline at the end. + // FIXME: buffer extra output. This would need a thread-local buffer, which + // on Android requires plugging into the tools (ex. ASan's) Thread class. + if (*p) + WriteOneLineToSyslog(p); +} + +static void (*sandboxing_callback)(); +void SetSandboxingCallback(void (*f)()) { + sandboxing_callback = f; +} + +uptr ReservedAddressRange::InitAligned(uptr size, uptr align, + const char *name) { + CHECK(IsPowerOfTwo(align)); + if (align <= GetPageSizeCached()) + return Init(size, name); + uptr start = Init(size + align, name); + start += align - (start & (align - 1)); + return start; +} + +#if !SANITIZER_FUCHSIA + +// Reserve memory range [beg, end]. +// We need to use inclusive range because end+1 may not be representable. +void ReserveShadowMemoryRange(uptr beg, uptr end, const char *name, + bool madvise_shadow) { + CHECK_EQ((beg % GetMmapGranularity()), 0); + CHECK_EQ(((end + 1) % GetMmapGranularity()), 0); + uptr size = end - beg + 1; + DecreaseTotalMmap(size); // Don't count the shadow against mmap_limit_mb. + if (madvise_shadow ? !MmapFixedSuperNoReserve(beg, size, name) + : !MmapFixedNoReserve(beg, size, name)) { + Report( + "ReserveShadowMemoryRange failed while trying to map 0x%zx bytes. " + "Perhaps you're using ulimit -v\n", + size); + Abort(); + } + if (madvise_shadow && common_flags()->use_madv_dontdump) + DontDumpShadowMemory(beg, size); +} + +void ProtectGap(uptr addr, uptr size, uptr zero_base_shadow_start, + uptr zero_base_max_shadow_start) { + if (!size) + return; + void *res = MmapFixedNoAccess(addr, size, "shadow gap"); + if (addr == (uptr)res) + return; + // A few pages at the start of the address space can not be protected. + // But we really want to protect as much as possible, to prevent this memory + // being returned as a result of a non-FIXED mmap(). + if (addr == zero_base_shadow_start) { + uptr step = GetMmapGranularity(); + while (size > step && addr < zero_base_max_shadow_start) { + addr += step; + size -= step; + void *res = MmapFixedNoAccess(addr, size, "shadow gap"); + if (addr == (uptr)res) + return; + } + } + + Report( + "ERROR: Failed to protect the shadow gap. " + "%s cannot proceed correctly. ABORTING.\n", + SanitizerToolName); + DumpProcessMap(); + Die(); +} + +#endif // !SANITIZER_FUCHSIA + +#if !SANITIZER_WINDOWS && !SANITIZER_GO +// Weak default implementation for when sanitizer_stackdepot is not linked in. +SANITIZER_WEAK_ATTRIBUTE void StackDepotStopBackgroundThread() {} +static void StopStackDepotBackgroundThread() { + StackDepotStopBackgroundThread(); +} +#else +// SANITIZER_WEAK_ATTRIBUTE is unsupported. +static void StopStackDepotBackgroundThread() {} +#endif + +} // namespace __sanitizer + +SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_sandbox_on_notify, + __sanitizer_sandbox_arguments *args) { + __sanitizer::StopStackDepotBackgroundThread(); + __sanitizer::PlatformPrepareForSandboxing(args); + if (__sanitizer::sandboxing_callback) + __sanitizer::sandboxing_callback(); +} diff --git a/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_common_syscalls.inc b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_common_syscalls.inc new file mode 100644 index 0000000000..a38b134085 --- /dev/null +++ b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_common_syscalls.inc @@ -0,0 +1,3175 @@ +//===-- sanitizer_common_syscalls.inc ---------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// Common syscalls handlers for tools like AddressSanitizer, +// ThreadSanitizer, MemorySanitizer, etc. +// +// This file should be included into the tool's interceptor file, +// which has to define it's own macros: +// COMMON_SYSCALL_PRE_READ_RANGE +// Called in prehook for regions that will be read by the kernel and +// must be initialized. +// COMMON_SYSCALL_PRE_WRITE_RANGE +// Called in prehook for regions that will be written to by the kernel +// and must be addressable. The actual write range may be smaller than +// reported in the prehook. See POST_WRITE_RANGE. +// COMMON_SYSCALL_POST_READ_RANGE +// Called in posthook for regions that were read by the kernel. Does +// not make much sense. +// COMMON_SYSCALL_POST_WRITE_RANGE +// Called in posthook for regions that were written to by the kernel +// and are now initialized. +// COMMON_SYSCALL_ACQUIRE(addr) +// Acquire memory visibility from addr. +// COMMON_SYSCALL_RELEASE(addr) +// Release memory visibility to addr. +// COMMON_SYSCALL_FD_CLOSE(fd) +// Called before closing file descriptor fd. +// COMMON_SYSCALL_FD_ACQUIRE(fd) +// Acquire memory visibility from fd. +// COMMON_SYSCALL_FD_RELEASE(fd) +// Release memory visibility to fd. +// COMMON_SYSCALL_PRE_FORK() +// Called before fork syscall. +// COMMON_SYSCALL_POST_FORK(long res) +// Called after fork syscall. +//===----------------------------------------------------------------------===// + +#include "sanitizer_platform.h" +#if SANITIZER_LINUX + +# include "sanitizer_libc.h" + +# define PRE_SYSCALL(name) \ + SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_syscall_pre_impl_##name +# define PRE_READ(p, s) COMMON_SYSCALL_PRE_READ_RANGE(p, s) +# define PRE_WRITE(p, s) COMMON_SYSCALL_PRE_WRITE_RANGE(p, s) + +# define POST_SYSCALL(name) \ + SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_syscall_post_impl_##name +# define POST_READ(p, s) COMMON_SYSCALL_POST_READ_RANGE(p, s) +# define POST_WRITE(p, s) COMMON_SYSCALL_POST_WRITE_RANGE(p, s) + +# ifndef COMMON_SYSCALL_ACQUIRE +# define COMMON_SYSCALL_ACQUIRE(addr) ((void)(addr)) +# endif + +# ifndef COMMON_SYSCALL_RELEASE +# define COMMON_SYSCALL_RELEASE(addr) ((void)(addr)) +# endif + +# ifndef COMMON_SYSCALL_FD_CLOSE +# define COMMON_SYSCALL_FD_CLOSE(fd) ((void)(fd)) +# endif + +# ifndef COMMON_SYSCALL_FD_ACQUIRE +# define COMMON_SYSCALL_FD_ACQUIRE(fd) ((void)(fd)) +# endif + +# ifndef COMMON_SYSCALL_FD_RELEASE +# define COMMON_SYSCALL_FD_RELEASE(fd) ((void)(fd)) +# endif + +# ifndef COMMON_SYSCALL_PRE_FORK +# define COMMON_SYSCALL_PRE_FORK() \ + {} +# endif + +# ifndef COMMON_SYSCALL_POST_FORK +# define COMMON_SYSCALL_POST_FORK(res) \ + {} +# endif + +// FIXME: do some kind of PRE_READ for all syscall arguments (int(s) and such). + +extern "C" { +struct sanitizer_kernel_iovec { + void *iov_base; + unsigned long iov_len; +}; + +struct sanitizer_kernel_msghdr { + void *msg_name; + int msg_namelen; + struct sanitizer_kernel_iovec *msg_iov; + unsigned long msg_iovlen; + void *msg_control; + unsigned long msg_controllen; + unsigned msg_flags; +}; + +struct sanitizer_kernel_mmsghdr { + struct sanitizer_kernel_msghdr msg_hdr; + unsigned msg_len; +}; + +struct sanitizer_kernel_timespec { + long tv_sec; + long tv_nsec; +}; + +struct sanitizer_kernel_timeval { + long tv_sec; + long tv_usec; +}; + +struct sanitizer_kernel_rusage { + struct sanitizer_kernel_timeval ru_timeval[2]; + long ru_long[14]; +}; + +struct sanitizer_kernel_sockaddr { + unsigned short sa_family; + char sa_data[14]; +}; + +// Real sigset size is always passed as a syscall argument. +// Declare it "void" to catch sizeof(kernel_sigset_t). +typedef void kernel_sigset_t; + +static void kernel_write_iovec(const __sanitizer_iovec *iovec, SIZE_T iovlen, + SIZE_T maxlen) { + for (SIZE_T i = 0; i < iovlen && maxlen; ++i) { + SSIZE_T sz = Min(iovec[i].iov_len, maxlen); + POST_WRITE(iovec[i].iov_base, sz); + maxlen -= sz; + } +} + +// This functions uses POST_READ, because it needs to run after syscall to know +// the real read range. +static void kernel_read_iovec(const __sanitizer_iovec *iovec, SIZE_T iovlen, + SIZE_T maxlen) { + POST_READ(iovec, sizeof(*iovec) * iovlen); + for (SIZE_T i = 0; i < iovlen && maxlen; ++i) { + SSIZE_T sz = Min(iovec[i].iov_len, maxlen); + POST_READ(iovec[i].iov_base, sz); + maxlen -= sz; + } +} + +PRE_SYSCALL(recvmsg)(long sockfd, sanitizer_kernel_msghdr *msg, long flags) { + PRE_READ(msg, sizeof(*msg)); +} + +POST_SYSCALL(recvmsg) +(long res, long sockfd, sanitizer_kernel_msghdr *msg, long flags) { + if (res >= 0) { + if (msg) { + for (unsigned long i = 0; i < msg->msg_iovlen; ++i) { + POST_WRITE(msg->msg_iov[i].iov_base, msg->msg_iov[i].iov_len); + } + POST_WRITE(msg->msg_control, msg->msg_controllen); + } + } +} + +PRE_SYSCALL(recvmmsg) +(long fd, sanitizer_kernel_mmsghdr *msg, long vlen, long flags, void *timeout) { + PRE_READ(msg, vlen * sizeof(*msg)); +} + +POST_SYSCALL(recvmmsg) +(long res, long fd, sanitizer_kernel_mmsghdr *msg, long vlen, long flags, + void *timeout) { + if (res >= 0) { + if (msg) { + for (unsigned long i = 0; i < msg->msg_hdr.msg_iovlen; ++i) { + POST_WRITE(msg->msg_hdr.msg_iov[i].iov_base, + msg->msg_hdr.msg_iov[i].iov_len); + } + POST_WRITE(msg->msg_hdr.msg_control, msg->msg_hdr.msg_controllen); + POST_WRITE(&msg->msg_len, sizeof(msg->msg_len)); + } + if (timeout) + POST_WRITE(timeout, struct_timespec_sz); + } +} + +PRE_SYSCALL(read)(long fd, void *buf, uptr count) { + if (buf) { + PRE_WRITE(buf, count); + } +} + +POST_SYSCALL(read)(long res, long fd, void *buf, uptr count) { + if (res > 0 && buf) { + POST_WRITE(buf, res); + } +} + +PRE_SYSCALL(time)(void *tloc) {} + +POST_SYSCALL(time)(long res, void *tloc) { + if (res >= 0) { + if (tloc) + POST_WRITE(tloc, sizeof(long)); + } +} + +PRE_SYSCALL(stime)(void *tptr) {} + +POST_SYSCALL(stime)(long res, void *tptr) { + if (res >= 0) { + if (tptr) + POST_WRITE(tptr, sizeof(long)); + } +} + +PRE_SYSCALL(gettimeofday)(void *tv, void *tz) {} + +POST_SYSCALL(gettimeofday)(long res, void *tv, void *tz) { + if (res >= 0) { + if (tv) + POST_WRITE(tv, timeval_sz); + if (tz) + POST_WRITE(tz, struct_timezone_sz); + } +} + +PRE_SYSCALL(settimeofday)(void *tv, void *tz) {} + +POST_SYSCALL(settimeofday)(long res, void *tv, void *tz) { + if (res >= 0) { + if (tv) + POST_WRITE(tv, timeval_sz); + if (tz) + POST_WRITE(tz, struct_timezone_sz); + } +} + +# if !SANITIZER_ANDROID +PRE_SYSCALL(adjtimex)(void *txc_p) {} + +POST_SYSCALL(adjtimex)(long res, void *txc_p) { + if (res >= 0) { + if (txc_p) + POST_WRITE(txc_p, struct_timex_sz); + } +} +# endif + +PRE_SYSCALL(times)(void *tbuf) {} + +POST_SYSCALL(times)(long res, void *tbuf) { + if (res >= 0) { + if (tbuf) + POST_WRITE(tbuf, struct_tms_sz); + } +} + +PRE_SYSCALL(gettid)() {} + +POST_SYSCALL(gettid)(long res) {} + +PRE_SYSCALL(nanosleep)(void *rqtp, void *rmtp) {} + +POST_SYSCALL(nanosleep)(long res, void *rqtp, void *rmtp) { + if (res >= 0) { + if (rqtp) + POST_WRITE(rqtp, struct_timespec_sz); + if (rmtp) + POST_WRITE(rmtp, struct_timespec_sz); + } +} + +PRE_SYSCALL(alarm)(long seconds) {} + +POST_SYSCALL(alarm)(long res, long seconds) {} + +PRE_SYSCALL(getpid)() {} + +POST_SYSCALL(getpid)(long res) {} + +PRE_SYSCALL(getppid)() {} + +POST_SYSCALL(getppid)(long res) {} + +PRE_SYSCALL(getuid)() {} + +POST_SYSCALL(getuid)(long res) {} + +PRE_SYSCALL(geteuid)() {} + +POST_SYSCALL(geteuid)(long res) {} + +PRE_SYSCALL(getgid)() {} + +POST_SYSCALL(getgid)(long res) {} + +PRE_SYSCALL(getegid)() {} + +POST_SYSCALL(getegid)(long res) {} + +PRE_SYSCALL(getresuid)(void *ruid, void *euid, void *suid) {} + +POST_SYSCALL(getresuid)(long res, void *ruid, void *euid, void *suid) { + if (res >= 0) { + if (ruid) + POST_WRITE(ruid, sizeof(unsigned)); + if (euid) + POST_WRITE(euid, sizeof(unsigned)); + if (suid) + POST_WRITE(suid, sizeof(unsigned)); + } +} + +PRE_SYSCALL(getresgid)(void *rgid, void *egid, void *sgid) {} + +POST_SYSCALL(getresgid)(long res, void *rgid, void *egid, void *sgid) { + if (res >= 0) { + if (rgid) + POST_WRITE(rgid, sizeof(unsigned)); + if (egid) + POST_WRITE(egid, sizeof(unsigned)); + if (sgid) + POST_WRITE(sgid, sizeof(unsigned)); + } +} + +PRE_SYSCALL(getpgid)(long pid) {} + +POST_SYSCALL(getpgid)(long res, long pid) {} + +PRE_SYSCALL(getpgrp)() {} + +POST_SYSCALL(getpgrp)(long res) {} + +PRE_SYSCALL(getsid)(long pid) {} + +POST_SYSCALL(getsid)(long res, long pid) {} + +PRE_SYSCALL(getgroups)(long gidsetsize, void *grouplist) {} + +POST_SYSCALL(getgroups) +(long res, long gidsetsize, __sanitizer___kernel_gid_t *grouplist) { + if (res >= 0) { + if (grouplist) + POST_WRITE(grouplist, res * sizeof(*grouplist)); + } +} + +PRE_SYSCALL(setregid)(long rgid, long egid) {} + +POST_SYSCALL(setregid)(long res, long rgid, long egid) {} + +PRE_SYSCALL(setgid)(long gid) {} + +POST_SYSCALL(setgid)(long res, long gid) {} + +PRE_SYSCALL(setreuid)(long ruid, long euid) {} + +POST_SYSCALL(setreuid)(long res, long ruid, long euid) {} + +PRE_SYSCALL(setuid)(long uid) {} + +POST_SYSCALL(setuid)(long res, long uid) {} + +PRE_SYSCALL(setresuid)(long ruid, long euid, long suid) {} + +POST_SYSCALL(setresuid)(long res, long ruid, long euid, long suid) {} + +PRE_SYSCALL(setresgid)(long rgid, long egid, long sgid) {} + +POST_SYSCALL(setresgid)(long res, long rgid, long egid, long sgid) {} + +PRE_SYSCALL(setfsuid)(long uid) {} + +POST_SYSCALL(setfsuid)(long res, long uid) {} + +PRE_SYSCALL(setfsgid)(long gid) {} + +POST_SYSCALL(setfsgid)(long res, long gid) {} + +PRE_SYSCALL(setpgid)(long pid, long pgid) {} + +POST_SYSCALL(setpgid)(long res, long pid, long pgid) {} + +PRE_SYSCALL(setsid)() {} + +POST_SYSCALL(setsid)(long res) {} + +PRE_SYSCALL(setgroups)(long gidsetsize, __sanitizer___kernel_gid_t *grouplist) { + if (grouplist) + POST_WRITE(grouplist, gidsetsize * sizeof(*grouplist)); +} + +POST_SYSCALL(setgroups) +(long res, long gidsetsize, __sanitizer___kernel_gid_t *grouplist) {} + +PRE_SYSCALL(acct)(const void *name) { + if (name) + PRE_READ(name, __sanitizer::internal_strlen((const char *)name) + 1); +} + +POST_SYSCALL(acct)(long res, const void *name) {} + +PRE_SYSCALL(capget)(void *header, void *dataptr) { + if (header) + PRE_READ(header, __user_cap_header_struct_sz); +} + +POST_SYSCALL(capget)(long res, void *header, void *dataptr) { + if (res >= 0) + if (dataptr) + POST_WRITE(dataptr, __user_cap_data_struct_sz); +} + +PRE_SYSCALL(capset)(void *header, const void *data) { + if (header) + PRE_READ(header, __user_cap_header_struct_sz); + if (data) + PRE_READ(data, __user_cap_data_struct_sz); +} + +POST_SYSCALL(capset)(long res, void *header, const void *data) {} + +PRE_SYSCALL(personality)(long personality) {} + +POST_SYSCALL(personality)(long res, long personality) {} + +PRE_SYSCALL(sigpending)(void *set) {} + +POST_SYSCALL(sigpending)(long res, void *set) { + if (res >= 0) { + if (set) + POST_WRITE(set, old_sigset_t_sz); + } +} + +PRE_SYSCALL(sigprocmask)(long how, void *set, void *oset) {} + +POST_SYSCALL(sigprocmask)(long res, long how, void *set, void *oset) { + if (res >= 0) { + if (set) + POST_WRITE(set, old_sigset_t_sz); + if (oset) + POST_WRITE(oset, old_sigset_t_sz); + } +} + +PRE_SYSCALL(getitimer)(long which, void *value) {} + +POST_SYSCALL(getitimer)(long res, long which, void *value) { + if (res >= 0) { + if (value) + POST_WRITE(value, struct_itimerval_sz); + } +} + +PRE_SYSCALL(setitimer)(long which, void *value, void *ovalue) {} + +POST_SYSCALL(setitimer)(long res, long which, void *value, void *ovalue) { + if (res >= 0) { + if (value) + POST_WRITE(value, struct_itimerval_sz); + if (ovalue) + POST_WRITE(ovalue, struct_itimerval_sz); + } +} + +PRE_SYSCALL(timer_create) +(long which_clock, void *timer_event_spec, void *created_timer_id) {} + +POST_SYSCALL(timer_create) +(long res, long which_clock, void *timer_event_spec, void *created_timer_id) { + if (res >= 0) { + if (timer_event_spec) + POST_WRITE(timer_event_spec, struct_sigevent_sz); + if (created_timer_id) + POST_WRITE(created_timer_id, sizeof(long)); + } +} + +PRE_SYSCALL(timer_gettime)(long timer_id, void *setting) {} + +POST_SYSCALL(timer_gettime)(long res, long timer_id, void *setting) { + if (res >= 0) { + if (setting) + POST_WRITE(setting, struct_itimerspec_sz); + } +} + +PRE_SYSCALL(timer_getoverrun)(long timer_id) {} + +POST_SYSCALL(timer_getoverrun)(long res, long timer_id) {} + +PRE_SYSCALL(timer_settime) +(long timer_id, long flags, const void *new_setting, void *old_setting) { + if (new_setting) + PRE_READ(new_setting, struct_itimerspec_sz); +} + +POST_SYSCALL(timer_settime) +(long res, long timer_id, long flags, const void *new_setting, + void *old_setting) { + if (res >= 0) { + if (old_setting) + POST_WRITE(old_setting, struct_itimerspec_sz); + } +} + +PRE_SYSCALL(timer_delete)(long timer_id) {} + +POST_SYSCALL(timer_delete)(long res, long timer_id) {} + +PRE_SYSCALL(clock_settime)(long which_clock, const void *tp) { + if (tp) + PRE_READ(tp, struct_timespec_sz); +} + +POST_SYSCALL(clock_settime)(long res, long which_clock, const void *tp) {} + +PRE_SYSCALL(clock_gettime)(long which_clock, void *tp) {} + +POST_SYSCALL(clock_gettime)(long res, long which_clock, void *tp) { + if (res >= 0) { + if (tp) + POST_WRITE(tp, struct_timespec_sz); + } +} + +# if !SANITIZER_ANDROID +PRE_SYSCALL(clock_adjtime)(long which_clock, void *tx) {} + +POST_SYSCALL(clock_adjtime)(long res, long which_clock, void *tx) { + if (res >= 0) { + if (tx) + POST_WRITE(tx, struct_timex_sz); + } +} +# endif + +PRE_SYSCALL(clock_getres)(long which_clock, void *tp) {} + +POST_SYSCALL(clock_getres)(long res, long which_clock, void *tp) { + if (res >= 0) { + if (tp) + POST_WRITE(tp, struct_timespec_sz); + } +} + +PRE_SYSCALL(clock_nanosleep) +(long which_clock, long flags, const void *rqtp, void *rmtp) { + if (rqtp) + PRE_READ(rqtp, struct_timespec_sz); +} + +POST_SYSCALL(clock_nanosleep) +(long res, long which_clock, long flags, const void *rqtp, void *rmtp) { + if (res >= 0) { + if (rmtp) + POST_WRITE(rmtp, struct_timespec_sz); + } +} + +PRE_SYSCALL(nice)(long increment) {} + +POST_SYSCALL(nice)(long res, long increment) {} + +PRE_SYSCALL(sched_setscheduler)(long pid, long policy, void *param) {} + +POST_SYSCALL(sched_setscheduler)(long res, long pid, long policy, void *param) { + if (res >= 0) { + if (param) + POST_WRITE(param, struct_sched_param_sz); + } +} + +PRE_SYSCALL(sched_setparam)(long pid, void *param) { + if (param) + PRE_READ(param, struct_sched_param_sz); +} + +POST_SYSCALL(sched_setparam)(long res, long pid, void *param) {} + +PRE_SYSCALL(sched_getscheduler)(long pid) {} + +POST_SYSCALL(sched_getscheduler)(long res, long pid) {} + +PRE_SYSCALL(sched_getparam)(long pid, void *param) {} + +POST_SYSCALL(sched_getparam)(long res, long pid, void *param) { + if (res >= 0) { + if (param) + POST_WRITE(param, struct_sched_param_sz); + } +} + +PRE_SYSCALL(sched_setaffinity)(long pid, long len, void *user_mask_ptr) { + if (user_mask_ptr) + PRE_READ(user_mask_ptr, len); +} + +POST_SYSCALL(sched_setaffinity) +(long res, long pid, long len, void *user_mask_ptr) {} + +PRE_SYSCALL(sched_getaffinity)(long pid, long len, void *user_mask_ptr) {} + +POST_SYSCALL(sched_getaffinity) +(long res, long pid, long len, void *user_mask_ptr) { + if (res >= 0) { + if (user_mask_ptr) + POST_WRITE(user_mask_ptr, len); + } +} + +PRE_SYSCALL(sched_yield)() {} + +POST_SYSCALL(sched_yield)(long res) {} + +PRE_SYSCALL(sched_get_priority_max)(long policy) {} + +POST_SYSCALL(sched_get_priority_max)(long res, long policy) {} + +PRE_SYSCALL(sched_get_priority_min)(long policy) {} + +POST_SYSCALL(sched_get_priority_min)(long res, long policy) {} + +PRE_SYSCALL(sched_rr_get_interval)(long pid, void *interval) {} + +POST_SYSCALL(sched_rr_get_interval)(long res, long pid, void *interval) { + if (res >= 0) { + if (interval) + POST_WRITE(interval, struct_timespec_sz); + } +} + +PRE_SYSCALL(setpriority)(long which, long who, long niceval) {} + +POST_SYSCALL(setpriority)(long res, long which, long who, long niceval) {} + +PRE_SYSCALL(getpriority)(long which, long who) {} + +POST_SYSCALL(getpriority)(long res, long which, long who) {} + +PRE_SYSCALL(shutdown)(long arg0, long arg1) {} + +POST_SYSCALL(shutdown)(long res, long arg0, long arg1) {} + +PRE_SYSCALL(reboot)(long magic1, long magic2, long cmd, void *arg) {} + +POST_SYSCALL(reboot)(long res, long magic1, long magic2, long cmd, void *arg) {} + +PRE_SYSCALL(restart_syscall)() {} + +POST_SYSCALL(restart_syscall)(long res) {} + +PRE_SYSCALL(kexec_load) +(long entry, long nr_segments, void *segments, long flags) {} + +POST_SYSCALL(kexec_load) +(long res, long entry, long nr_segments, void *segments, long flags) { + if (res >= 0) { + if (segments) + POST_WRITE(segments, struct_kexec_segment_sz); + } +} + +PRE_SYSCALL(exit)(long error_code) {} + +POST_SYSCALL(exit)(long res, long error_code) {} + +PRE_SYSCALL(exit_group)(long error_code) {} + +POST_SYSCALL(exit_group)(long res, long error_code) {} + +PRE_SYSCALL(wait4)(long pid, void *stat_addr, long options, void *ru) {} + +POST_SYSCALL(wait4) +(long res, long pid, void *stat_addr, long options, void *ru) { + if (res >= 0) { + if (stat_addr) + POST_WRITE(stat_addr, sizeof(int)); + if (ru) + POST_WRITE(ru, struct_rusage_sz); + } +} + +PRE_SYSCALL(waitid) +(long which, long pid, void *infop, long options, void *ru) {} + +POST_SYSCALL(waitid) +(long res, long which, long pid, void *infop, long options, void *ru) { + if (res >= 0) { + if (infop) + POST_WRITE(infop, siginfo_t_sz); + if (ru) + POST_WRITE(ru, struct_rusage_sz); + } +} + +PRE_SYSCALL(waitpid)(long pid, void *stat_addr, long options) {} + +POST_SYSCALL(waitpid)(long res, long pid, void *stat_addr, long options) { + if (res >= 0) { + if (stat_addr) + POST_WRITE(stat_addr, sizeof(int)); + } +} + +PRE_SYSCALL(set_tid_address)(void *tidptr) {} + +POST_SYSCALL(set_tid_address)(long res, void *tidptr) { + if (res >= 0) { + if (tidptr) + POST_WRITE(tidptr, sizeof(int)); + } +} + +PRE_SYSCALL(init_module)(void *umod, long len, const void *uargs) { + if (uargs) + PRE_READ(uargs, __sanitizer::internal_strlen((const char *)uargs) + 1); +} + +POST_SYSCALL(init_module)(long res, void *umod, long len, const void *uargs) {} + +PRE_SYSCALL(delete_module)(const void *name_user, long flags) { + if (name_user) + PRE_READ(name_user, + __sanitizer::internal_strlen((const char *)name_user) + 1); +} + +POST_SYSCALL(delete_module)(long res, const void *name_user, long flags) {} + +PRE_SYSCALL(rt_sigprocmask)(long how, void *set, void *oset, long sigsetsize) {} + +POST_SYSCALL(rt_sigprocmask) +(long res, long how, kernel_sigset_t *set, kernel_sigset_t *oset, + long sigsetsize) { + if (res >= 0) { + if (set) + POST_WRITE(set, sigsetsize); + if (oset) + POST_WRITE(oset, sigsetsize); + } +} + +PRE_SYSCALL(rt_sigpending)(void *set, long sigsetsize) {} + +POST_SYSCALL(rt_sigpending)(long res, kernel_sigset_t *set, long sigsetsize) { + if (res >= 0) { + if (set) + POST_WRITE(set, sigsetsize); + } +} + +PRE_SYSCALL(rt_sigtimedwait) +(const kernel_sigset_t *uthese, void *uinfo, const void *uts, long sigsetsize) { + if (uthese) + PRE_READ(uthese, sigsetsize); + if (uts) + PRE_READ(uts, struct_timespec_sz); +} + +POST_SYSCALL(rt_sigtimedwait) +(long res, const void *uthese, void *uinfo, const void *uts, long sigsetsize) { + if (res >= 0) { + if (uinfo) + POST_WRITE(uinfo, siginfo_t_sz); + } +} + +PRE_SYSCALL(rt_tgsigqueueinfo)(long tgid, long pid, long sig, void *uinfo) {} + +POST_SYSCALL(rt_tgsigqueueinfo) +(long res, long tgid, long pid, long sig, void *uinfo) { + if (res >= 0) { + if (uinfo) + POST_WRITE(uinfo, siginfo_t_sz); + } +} + +PRE_SYSCALL(kill)(long pid, long sig) {} + +POST_SYSCALL(kill)(long res, long pid, long sig) {} + +PRE_SYSCALL(tgkill)(long tgid, long pid, long sig) {} + +POST_SYSCALL(tgkill)(long res, long tgid, long pid, long sig) {} + +PRE_SYSCALL(tkill)(long pid, long sig) {} + +POST_SYSCALL(tkill)(long res, long pid, long sig) {} + +PRE_SYSCALL(rt_sigqueueinfo)(long pid, long sig, void *uinfo) {} + +POST_SYSCALL(rt_sigqueueinfo)(long res, long pid, long sig, void *uinfo) { + if (res >= 0) { + if (uinfo) + POST_WRITE(uinfo, siginfo_t_sz); + } +} + +PRE_SYSCALL(sgetmask)() {} + +POST_SYSCALL(sgetmask)(long res) {} + +PRE_SYSCALL(ssetmask)(long newmask) {} + +POST_SYSCALL(ssetmask)(long res, long newmask) {} + +PRE_SYSCALL(signal)(long sig, long handler) {} + +POST_SYSCALL(signal)(long res, long sig, long handler) {} + +PRE_SYSCALL(pause)() {} + +POST_SYSCALL(pause)(long res) {} + +PRE_SYSCALL(sync)() {} + +POST_SYSCALL(sync)(long res) {} + +PRE_SYSCALL(fsync)(long fd) {} + +POST_SYSCALL(fsync)(long res, long fd) {} + +PRE_SYSCALL(fdatasync)(long fd) {} + +POST_SYSCALL(fdatasync)(long res, long fd) {} + +PRE_SYSCALL(bdflush)(long func, long data) {} + +POST_SYSCALL(bdflush)(long res, long func, long data) {} + +PRE_SYSCALL(mount) +(void *dev_name, void *dir_name, void *type, long flags, void *data) {} + +POST_SYSCALL(mount) +(long res, void *dev_name, void *dir_name, void *type, long flags, void *data) { + if (res >= 0) { + if (dev_name) + POST_WRITE(dev_name, + __sanitizer::internal_strlen((const char *)dev_name) + 1); + if (dir_name) + POST_WRITE(dir_name, + __sanitizer::internal_strlen((const char *)dir_name) + 1); + if (type) + POST_WRITE(type, __sanitizer::internal_strlen((const char *)type) + 1); + } +} + +PRE_SYSCALL(umount)(void *name, long flags) {} + +POST_SYSCALL(umount)(long res, void *name, long flags) { + if (res >= 0) { + if (name) + POST_WRITE(name, __sanitizer::internal_strlen((const char *)name) + 1); + } +} + +PRE_SYSCALL(oldumount)(void *name) {} + +POST_SYSCALL(oldumount)(long res, void *name) { + if (res >= 0) { + if (name) + POST_WRITE(name, __sanitizer::internal_strlen((const char *)name) + 1); + } +} + +PRE_SYSCALL(truncate)(const void *path, long length) { + if (path) + PRE_READ(path, __sanitizer::internal_strlen((const char *)path) + 1); +} + +POST_SYSCALL(truncate)(long res, const void *path, long length) {} + +PRE_SYSCALL(ftruncate)(long fd, long length) {} + +POST_SYSCALL(ftruncate)(long res, long fd, long length) {} + +PRE_SYSCALL(stat)(const void *filename, void *statbuf) { + if (filename) + PRE_READ(filename, + __sanitizer::internal_strlen((const char *)filename) + 1); +} + +POST_SYSCALL(stat)(long res, const void *filename, void *statbuf) { + if (res >= 0) { + if (statbuf) + POST_WRITE(statbuf, struct___old_kernel_stat_sz); + } +} + +# if !SANITIZER_ANDROID +PRE_SYSCALL(statfs)(const void *path, void *buf) { + if (path) + PRE_READ(path, __sanitizer::internal_strlen((const char *)path) + 1); +} + +POST_SYSCALL(statfs)(long res, const void *path, void *buf) { + if (res >= 0) { + if (buf) + POST_WRITE(buf, struct_statfs_sz); + } +} + +PRE_SYSCALL(statfs64)(const void *path, long sz, void *buf) { + if (path) + PRE_READ(path, __sanitizer::internal_strlen((const char *)path) + 1); +} + +POST_SYSCALL(statfs64)(long res, const void *path, long sz, void *buf) { + if (res >= 0) { + if (buf) + POST_WRITE(buf, struct_statfs64_sz); + } +} + +PRE_SYSCALL(fstatfs)(long fd, void *buf) {} + +POST_SYSCALL(fstatfs)(long res, long fd, void *buf) { + if (res >= 0) { + if (buf) + POST_WRITE(buf, struct_statfs_sz); + } +} + +PRE_SYSCALL(fstatfs64)(long fd, long sz, void *buf) {} + +POST_SYSCALL(fstatfs64)(long res, long fd, long sz, void *buf) { + if (res >= 0) { + if (buf) + POST_WRITE(buf, struct_statfs64_sz); + } +} +# endif // !SANITIZER_ANDROID + +PRE_SYSCALL(lstat)(const void *filename, void *statbuf) { + if (filename) + PRE_READ(filename, + __sanitizer::internal_strlen((const char *)filename) + 1); +} + +POST_SYSCALL(lstat)(long res, const void *filename, void *statbuf) { + if (res >= 0) { + if (statbuf) + POST_WRITE(statbuf, struct___old_kernel_stat_sz); + } +} + +PRE_SYSCALL(fstat)(long fd, void *statbuf) {} + +POST_SYSCALL(fstat)(long res, long fd, void *statbuf) { + if (res >= 0) { + if (statbuf) + POST_WRITE(statbuf, struct___old_kernel_stat_sz); + } +} + +PRE_SYSCALL(newstat)(const void *filename, void *statbuf) { + if (filename) + PRE_READ(filename, + __sanitizer::internal_strlen((const char *)filename) + 1); +} + +POST_SYSCALL(newstat)(long res, const void *filename, void *statbuf) { + if (res >= 0) { + if (statbuf) + POST_WRITE(statbuf, struct_kernel_stat_sz); + } +} + +PRE_SYSCALL(newlstat)(const void *filename, void *statbuf) { + if (filename) + PRE_READ(filename, + __sanitizer::internal_strlen((const char *)filename) + 1); +} + +POST_SYSCALL(newlstat)(long res, const void *filename, void *statbuf) { + if (res >= 0) { + if (statbuf) + POST_WRITE(statbuf, struct_kernel_stat_sz); + } +} + +PRE_SYSCALL(newfstat)(long fd, void *statbuf) {} + +POST_SYSCALL(newfstat)(long res, long fd, void *statbuf) { + if (res >= 0) { + if (statbuf) + POST_WRITE(statbuf, struct_kernel_stat_sz); + } +} + +# if !SANITIZER_ANDROID +PRE_SYSCALL(ustat)(long dev, void *ubuf) {} + +POST_SYSCALL(ustat)(long res, long dev, void *ubuf) { + if (res >= 0) { + if (ubuf) + POST_WRITE(ubuf, struct_ustat_sz); + } +} +# endif // !SANITIZER_ANDROID + +PRE_SYSCALL(stat64)(const void *filename, void *statbuf) { + if (filename) + PRE_READ(filename, + __sanitizer::internal_strlen((const char *)filename) + 1); +} + +POST_SYSCALL(stat64)(long res, const void *filename, void *statbuf) { + if (res >= 0) { + if (statbuf) + POST_WRITE(statbuf, struct_kernel_stat64_sz); + } +} + +PRE_SYSCALL(fstat64)(long fd, void *statbuf) {} + +POST_SYSCALL(fstat64)(long res, long fd, void *statbuf) { + if (res >= 0) { + if (statbuf) + POST_WRITE(statbuf, struct_kernel_stat64_sz); + } +} + +PRE_SYSCALL(lstat64)(const void *filename, void *statbuf) { + if (filename) + PRE_READ(filename, + __sanitizer::internal_strlen((const char *)filename) + 1); +} + +POST_SYSCALL(lstat64)(long res, const void *filename, void *statbuf) { + if (res >= 0) { + if (statbuf) + POST_WRITE(statbuf, struct_kernel_stat64_sz); + } +} + +PRE_SYSCALL(setxattr) +(const void *path, const void *name, const void *value, long size, long flags) { + if (path) + PRE_READ(path, __sanitizer::internal_strlen((const char *)path) + 1); + if (name) + PRE_READ(name, __sanitizer::internal_strlen((const char *)name) + 1); + if (value) + PRE_READ(value, size); +} + +POST_SYSCALL(setxattr) +(long res, const void *path, const void *name, const void *value, long size, + long flags) {} + +PRE_SYSCALL(lsetxattr) +(const void *path, const void *name, const void *value, long size, long flags) { + if (path) + PRE_READ(path, __sanitizer::internal_strlen((const char *)path) + 1); + if (name) + PRE_READ(name, __sanitizer::internal_strlen((const char *)name) + 1); + if (value) + PRE_READ(value, size); +} + +POST_SYSCALL(lsetxattr) +(long res, const void *path, const void *name, const void *value, long size, + long flags) {} + +PRE_SYSCALL(fsetxattr) +(long fd, const void *name, const void *value, long size, long flags) { + if (name) + PRE_READ(name, __sanitizer::internal_strlen((const char *)name) + 1); + if (value) + PRE_READ(value, size); +} + +POST_SYSCALL(fsetxattr) +(long res, long fd, const void *name, const void *value, long size, + long flags) {} + +PRE_SYSCALL(getxattr) +(const void *path, const void *name, void *value, long size) { + if (path) + PRE_READ(path, __sanitizer::internal_strlen((const char *)path) + 1); + if (name) + PRE_READ(name, __sanitizer::internal_strlen((const char *)name) + 1); +} + +POST_SYSCALL(getxattr) +(long res, const void *path, const void *name, void *value, long size) { + if (size && res > 0) { + if (value) + POST_WRITE(value, res); + } +} + +PRE_SYSCALL(lgetxattr) +(const void *path, const void *name, void *value, long size) { + if (path) + PRE_READ(path, __sanitizer::internal_strlen((const char *)path) + 1); + if (name) + PRE_READ(name, __sanitizer::internal_strlen((const char *)name) + 1); +} + +POST_SYSCALL(lgetxattr) +(long res, const void *path, const void *name, void *value, long size) { + if (size && res > 0) { + if (value) + POST_WRITE(value, res); + } +} + +PRE_SYSCALL(fgetxattr)(long fd, const void *name, void *value, long size) { + if (name) + PRE_READ(name, __sanitizer::internal_strlen((const char *)name) + 1); +} + +POST_SYSCALL(fgetxattr) +(long res, long fd, const void *name, void *value, long size) { + if (size && res > 0) { + if (value) + POST_WRITE(value, res); + } +} + +PRE_SYSCALL(listxattr)(const void *path, void *list, long size) { + if (path) + PRE_READ(path, __sanitizer::internal_strlen((const char *)path) + 1); +} + +POST_SYSCALL(listxattr)(long res, const void *path, void *list, long size) { + if (size && res > 0) { + if (list) + POST_WRITE(list, res); + } +} + +PRE_SYSCALL(llistxattr)(const void *path, void *list, long size) { + if (path) + PRE_READ(path, __sanitizer::internal_strlen((const char *)path) + 1); +} + +POST_SYSCALL(llistxattr)(long res, const void *path, void *list, long size) { + if (size && res > 0) { + if (list) + POST_WRITE(list, res); + } +} + +PRE_SYSCALL(flistxattr)(long fd, void *list, long size) {} + +POST_SYSCALL(flistxattr)(long res, long fd, void *list, long size) { + if (size && res > 0) { + if (list) + POST_WRITE(list, res); + } +} + +PRE_SYSCALL(removexattr)(const void *path, const void *name) { + if (path) + PRE_READ(path, __sanitizer::internal_strlen((const char *)path) + 1); + if (name) + PRE_READ(name, __sanitizer::internal_strlen((const char *)name) + 1); +} + +POST_SYSCALL(removexattr)(long res, const void *path, const void *name) {} + +PRE_SYSCALL(lremovexattr)(const void *path, const void *name) { + if (path) + PRE_READ(path, __sanitizer::internal_strlen((const char *)path) + 1); + if (name) + PRE_READ(name, __sanitizer::internal_strlen((const char *)name) + 1); +} + +POST_SYSCALL(lremovexattr)(long res, const void *path, const void *name) {} + +PRE_SYSCALL(fremovexattr)(long fd, const void *name) { + if (name) + PRE_READ(name, __sanitizer::internal_strlen((const char *)name) + 1); +} + +POST_SYSCALL(fremovexattr)(long res, long fd, const void *name) {} + +PRE_SYSCALL(brk)(long brk) {} + +POST_SYSCALL(brk)(long res, long brk) {} + +PRE_SYSCALL(mprotect)(long start, long len, long prot) {} + +POST_SYSCALL(mprotect)(long res, long start, long len, long prot) {} + +PRE_SYSCALL(mremap) +(long addr, long old_len, long new_len, long flags, long new_addr) {} + +POST_SYSCALL(mremap) +(long res, long addr, long old_len, long new_len, long flags, long new_addr) {} + +PRE_SYSCALL(remap_file_pages) +(long start, long size, long prot, long pgoff, long flags) {} + +POST_SYSCALL(remap_file_pages) +(long res, long start, long size, long prot, long pgoff, long flags) {} + +PRE_SYSCALL(msync)(long start, long len, long flags) {} + +POST_SYSCALL(msync)(long res, long start, long len, long flags) {} + +PRE_SYSCALL(munmap)(long addr, long len) {} + +POST_SYSCALL(munmap)(long res, long addr, long len) {} + +PRE_SYSCALL(mlock)(long start, long len) {} + +POST_SYSCALL(mlock)(long res, long start, long len) {} + +PRE_SYSCALL(munlock)(long start, long len) {} + +POST_SYSCALL(munlock)(long res, long start, long len) {} + +PRE_SYSCALL(mlockall)(long flags) {} + +POST_SYSCALL(mlockall)(long res, long flags) {} + +PRE_SYSCALL(munlockall)() {} + +POST_SYSCALL(munlockall)(long res) {} + +PRE_SYSCALL(madvise)(long start, long len, long behavior) {} + +POST_SYSCALL(madvise)(long res, long start, long len, long behavior) {} + +PRE_SYSCALL(mincore)(long start, long len, void *vec) {} + +POST_SYSCALL(mincore)(long res, long start, long len, void *vec) { + if (res >= 0) { + if (vec) { + POST_WRITE(vec, (len + GetPageSizeCached() - 1) / GetPageSizeCached()); + } + } +} + +PRE_SYSCALL(pivot_root)(const void *new_root, const void *put_old) { + if (new_root) + PRE_READ(new_root, + __sanitizer::internal_strlen((const char *)new_root) + 1); + if (put_old) + PRE_READ(put_old, __sanitizer::internal_strlen((const char *)put_old) + 1); +} + +POST_SYSCALL(pivot_root)(long res, const void *new_root, const void *put_old) {} + +PRE_SYSCALL(chroot)(const void *filename) { + if (filename) + PRE_READ(filename, + __sanitizer::internal_strlen((const char *)filename) + 1); +} + +POST_SYSCALL(chroot)(long res, const void *filename) {} + +PRE_SYSCALL(mknod)(const void *filename, long mode, long dev) { + if (filename) + PRE_READ(filename, + __sanitizer::internal_strlen((const char *)filename) + 1); +} + +POST_SYSCALL(mknod)(long res, const void *filename, long mode, long dev) {} + +PRE_SYSCALL(link)(const void *oldname, const void *newname) { + if (oldname) + PRE_READ(oldname, __sanitizer::internal_strlen((const char *)oldname) + 1); + if (newname) + PRE_READ(newname, __sanitizer::internal_strlen((const char *)newname) + 1); +} + +POST_SYSCALL(link)(long res, const void *oldname, const void *newname) {} + +PRE_SYSCALL(symlink)(const void *old, const void *new_) { + if (old) + PRE_READ(old, __sanitizer::internal_strlen((const char *)old) + 1); + if (new_) + PRE_READ(new_, __sanitizer::internal_strlen((const char *)new_) + 1); +} + +POST_SYSCALL(symlink)(long res, const void *old, const void *new_) {} + +PRE_SYSCALL(unlink)(const void *pathname) { + if (pathname) + PRE_READ(pathname, + __sanitizer::internal_strlen((const char *)pathname) + 1); +} + +POST_SYSCALL(unlink)(long res, const void *pathname) {} + +PRE_SYSCALL(rename)(const void *oldname, const void *newname) { + if (oldname) + PRE_READ(oldname, __sanitizer::internal_strlen((const char *)oldname) + 1); + if (newname) + PRE_READ(newname, __sanitizer::internal_strlen((const char *)newname) + 1); +} + +POST_SYSCALL(rename)(long res, const void *oldname, const void *newname) {} + +PRE_SYSCALL(chmod)(const void *filename, long mode) { + if (filename) + PRE_READ(filename, + __sanitizer::internal_strlen((const char *)filename) + 1); +} + +POST_SYSCALL(chmod)(long res, const void *filename, long mode) {} + +PRE_SYSCALL(fchmod)(long fd, long mode) {} + +POST_SYSCALL(fchmod)(long res, long fd, long mode) {} + +PRE_SYSCALL(fcntl)(long fd, long cmd, long arg) {} + +POST_SYSCALL(fcntl)(long res, long fd, long cmd, long arg) {} + +PRE_SYSCALL(fcntl64)(long fd, long cmd, long arg) {} + +POST_SYSCALL(fcntl64)(long res, long fd, long cmd, long arg) {} + +PRE_SYSCALL(pipe)(void *fildes) {} + +POST_SYSCALL(pipe)(long res, void *fildes) { + if (res >= 0) + if (fildes) + POST_WRITE(fildes, sizeof(int) * 2); +} + +PRE_SYSCALL(pipe2)(void *fildes, long flags) {} + +POST_SYSCALL(pipe2)(long res, void *fildes, long flags) { + if (res >= 0) + if (fildes) + POST_WRITE(fildes, sizeof(int) * 2); +} + +PRE_SYSCALL(dup)(long fildes) {} + +POST_SYSCALL(dup)(long res, long fildes) {} + +PRE_SYSCALL(dup2)(long oldfd, long newfd) {} + +POST_SYSCALL(dup2)(long res, long oldfd, long newfd) {} + +PRE_SYSCALL(dup3)(long oldfd, long newfd, long flags) {} + +POST_SYSCALL(dup3)(long res, long oldfd, long newfd, long flags) {} + +PRE_SYSCALL(ioperm)(long from, long num, long on) {} + +POST_SYSCALL(ioperm)(long res, long from, long num, long on) {} + +PRE_SYSCALL(ioctl)(long fd, long cmd, long arg) {} + +POST_SYSCALL(ioctl)(long res, long fd, long cmd, long arg) {} + +PRE_SYSCALL(flock)(long fd, long cmd) {} + +POST_SYSCALL(flock)(long res, long fd, long cmd) {} + +PRE_SYSCALL(io_setup)(long nr_reqs, void **ctx) { + if (ctx) + PRE_WRITE(ctx, sizeof(*ctx)); +} + +POST_SYSCALL(io_setup)(long res, long nr_reqs, void **ctx) { + if (res >= 0) { + if (ctx) + POST_WRITE(ctx, sizeof(*ctx)); + // (*ctx) is actually a pointer to a kernel mapped page, and there are + // people out there who are crazy enough to peek into that page's 32-byte + // header. + if (*ctx) + POST_WRITE(*ctx, 32); + } +} + +PRE_SYSCALL(io_destroy)(long ctx) {} + +POST_SYSCALL(io_destroy)(long res, long ctx) {} + +PRE_SYSCALL(io_getevents) +(long ctx_id, long min_nr, long nr, __sanitizer_io_event *ioevpp, + void *timeout) { + if (timeout) + PRE_READ(timeout, struct_timespec_sz); +} + +POST_SYSCALL(io_getevents) +(long res, long ctx_id, long min_nr, long nr, __sanitizer_io_event *ioevpp, + void *timeout) { + if (res >= 0) { + if (ioevpp) + POST_WRITE(ioevpp, res * sizeof(*ioevpp)); + if (timeout) + POST_WRITE(timeout, struct_timespec_sz); + } + for (long i = 0; i < res; i++) { + // We synchronize io_submit -> io_getevents/io_cancel using the + // user-provided data context. Data is not necessary a pointer, it can be + // an int, 0 or whatever; acquire/release will correctly handle this. + // This scheme can lead to false negatives, e.g. when all operations + // synchronize on 0. But there does not seem to be a better solution + // (except wrapping all operations in own context, which is unreliable). + // We can not reliably extract fildes in io_getevents. + COMMON_SYSCALL_ACQUIRE((void *)ioevpp[i].data); + } +} + +PRE_SYSCALL(io_submit)(long ctx_id, long nr, __sanitizer_iocb **iocbpp) { + for (long i = 0; i < nr; ++i) { + uptr op = iocbpp[i]->aio_lio_opcode; + void *data = (void *)iocbpp[i]->aio_data; + void *buf = (void *)iocbpp[i]->aio_buf; + uptr len = (uptr)iocbpp[i]->aio_nbytes; + if (op == iocb_cmd_pwrite && buf && len) { + PRE_READ(buf, len); + } else if (op == iocb_cmd_pread && buf && len) { + POST_WRITE(buf, len); + } else if (op == iocb_cmd_pwritev) { + __sanitizer_iovec *iovec = (__sanitizer_iovec *)buf; + for (uptr v = 0; v < len; v++) + PRE_READ(iovec[v].iov_base, iovec[v].iov_len); + } else if (op == iocb_cmd_preadv) { + __sanitizer_iovec *iovec = (__sanitizer_iovec *)buf; + for (uptr v = 0; v < len; v++) + POST_WRITE(iovec[v].iov_base, iovec[v].iov_len); + } + // See comment in io_getevents. + COMMON_SYSCALL_RELEASE(data); + } +} + +POST_SYSCALL(io_submit) +(long res, long ctx_id, long nr, __sanitizer_iocb **iocbpp) {} + +PRE_SYSCALL(io_cancel) +(long ctx_id, __sanitizer_iocb *iocb, __sanitizer_io_event *result) {} + +POST_SYSCALL(io_cancel) +(long res, long ctx_id, __sanitizer_iocb *iocb, __sanitizer_io_event *result) { + if (res == 0) { + if (result) { + // See comment in io_getevents. + COMMON_SYSCALL_ACQUIRE((void *)result->data); + POST_WRITE(result, sizeof(*result)); + } + if (iocb) + POST_WRITE(iocb, sizeof(*iocb)); + } +} + +PRE_SYSCALL(sendfile)(long out_fd, long in_fd, void *offset, long count) {} + +POST_SYSCALL(sendfile) +(long res, long out_fd, long in_fd, __sanitizer___kernel_off_t *offset, + long count) { + if (res >= 0) { + if (offset) + POST_WRITE(offset, sizeof(*offset)); + } +} + +PRE_SYSCALL(sendfile64)(long out_fd, long in_fd, void *offset, long count) {} + +POST_SYSCALL(sendfile64) +(long res, long out_fd, long in_fd, __sanitizer___kernel_loff_t *offset, + long count) { + if (res >= 0) { + if (offset) + POST_WRITE(offset, sizeof(*offset)); + } +} + +PRE_SYSCALL(readlink)(const void *path, void *buf, long bufsiz) { + if (path) + PRE_READ(path, __sanitizer::internal_strlen((const char *)path) + 1); +} + +POST_SYSCALL(readlink)(long res, const void *path, void *buf, long bufsiz) { + if (res >= 0) { + if (buf) + POST_WRITE(buf, __sanitizer::internal_strlen((const char *)buf) + 1); + } +} + +PRE_SYSCALL(creat)(const void *pathname, long mode) { + if (pathname) + PRE_READ(pathname, + __sanitizer::internal_strlen((const char *)pathname) + 1); +} + +POST_SYSCALL(creat)(long res, const void *pathname, long mode) {} + +PRE_SYSCALL(open)(const void *filename, long flags, long mode) { + if (filename) + PRE_READ(filename, + __sanitizer::internal_strlen((const char *)filename) + 1); +} + +POST_SYSCALL(open)(long res, const void *filename, long flags, long mode) {} + +PRE_SYSCALL(close)(long fd) { COMMON_SYSCALL_FD_CLOSE((int)fd); } + +POST_SYSCALL(close)(long res, long fd) {} + +PRE_SYSCALL(access)(const void *filename, long mode) { + if (filename) + PRE_READ(filename, + __sanitizer::internal_strlen((const char *)filename) + 1); +} + +POST_SYSCALL(access)(long res, const void *filename, long mode) {} + +PRE_SYSCALL(vhangup)() {} + +POST_SYSCALL(vhangup)(long res) {} + +PRE_SYSCALL(chown)(const void *filename, long user, long group) { + if (filename) + PRE_READ(filename, + __sanitizer::internal_strlen((const char *)filename) + 1); +} + +POST_SYSCALL(chown)(long res, const void *filename, long user, long group) {} + +PRE_SYSCALL(lchown)(const void *filename, long user, long group) { + if (filename) + PRE_READ(filename, + __sanitizer::internal_strlen((const char *)filename) + 1); +} + +POST_SYSCALL(lchown)(long res, const void *filename, long user, long group) {} + +PRE_SYSCALL(fchown)(long fd, long user, long group) {} + +POST_SYSCALL(fchown)(long res, long fd, long user, long group) {} + +# if SANITIZER_USES_UID16_SYSCALLS +PRE_SYSCALL(chown16)(const void *filename, long user, long group) { + if (filename) + PRE_READ(filename, + __sanitizer::internal_strlen((const char *)filename) + 1); +} + +POST_SYSCALL(chown16)(long res, const void *filename, long user, long group) {} + +PRE_SYSCALL(lchown16)(const void *filename, long user, long group) { + if (filename) + PRE_READ(filename, + __sanitizer::internal_strlen((const char *)filename) + 1); +} + +POST_SYSCALL(lchown16)(long res, const void *filename, long user, long group) {} + +PRE_SYSCALL(fchown16)(long fd, long user, long group) {} + +POST_SYSCALL(fchown16)(long res, long fd, long user, long group) {} + +PRE_SYSCALL(setregid16)(long rgid, long egid) {} + +POST_SYSCALL(setregid16)(long res, long rgid, long egid) {} + +PRE_SYSCALL(setgid16)(long gid) {} + +POST_SYSCALL(setgid16)(long res, long gid) {} + +PRE_SYSCALL(setreuid16)(long ruid, long euid) {} + +POST_SYSCALL(setreuid16)(long res, long ruid, long euid) {} + +PRE_SYSCALL(setuid16)(long uid) {} + +POST_SYSCALL(setuid16)(long res, long uid) {} + +PRE_SYSCALL(setresuid16)(long ruid, long euid, long suid) {} + +POST_SYSCALL(setresuid16)(long res, long ruid, long euid, long suid) {} + +PRE_SYSCALL(getresuid16)(void *ruid, void *euid, void *suid) {} + +POST_SYSCALL(getresuid16) +(long res, __sanitizer___kernel_old_uid_t *ruid, + __sanitizer___kernel_old_uid_t *euid, __sanitizer___kernel_old_uid_t *suid) { + if (res >= 0) { + if (ruid) + POST_WRITE(ruid, sizeof(*ruid)); + if (euid) + POST_WRITE(euid, sizeof(*euid)); + if (suid) + POST_WRITE(suid, sizeof(*suid)); + } +} + +PRE_SYSCALL(setresgid16)(long rgid, long egid, long sgid) {} + +POST_SYSCALL(setresgid16)(long res, long rgid, long egid, long sgid) {} + +PRE_SYSCALL(getresgid16)(void *rgid, void *egid, void *sgid) {} + +POST_SYSCALL(getresgid16) +(long res, __sanitizer___kernel_old_gid_t *rgid, + __sanitizer___kernel_old_gid_t *egid, __sanitizer___kernel_old_gid_t *sgid) { + if (res >= 0) { + if (rgid) + POST_WRITE(rgid, sizeof(*rgid)); + if (egid) + POST_WRITE(egid, sizeof(*egid)); + if (sgid) + POST_WRITE(sgid, sizeof(*sgid)); + } +} + +PRE_SYSCALL(setfsuid16)(long uid) {} + +POST_SYSCALL(setfsuid16)(long res, long uid) {} + +PRE_SYSCALL(setfsgid16)(long gid) {} + +POST_SYSCALL(setfsgid16)(long res, long gid) {} + +PRE_SYSCALL(getgroups16) +(long gidsetsize, __sanitizer___kernel_old_gid_t *grouplist) {} + +POST_SYSCALL(getgroups16) +(long res, long gidsetsize, __sanitizer___kernel_old_gid_t *grouplist) { + if (res >= 0) { + if (grouplist) + POST_WRITE(grouplist, res * sizeof(*grouplist)); + } +} + +PRE_SYSCALL(setgroups16) +(long gidsetsize, __sanitizer___kernel_old_gid_t *grouplist) { + if (grouplist) + POST_WRITE(grouplist, gidsetsize * sizeof(*grouplist)); +} + +POST_SYSCALL(setgroups16) +(long res, long gidsetsize, __sanitizer___kernel_old_gid_t *grouplist) {} + +PRE_SYSCALL(getuid16)() {} + +POST_SYSCALL(getuid16)(long res) {} + +PRE_SYSCALL(geteuid16)() {} + +POST_SYSCALL(geteuid16)(long res) {} + +PRE_SYSCALL(getgid16)() {} + +POST_SYSCALL(getgid16)(long res) {} + +PRE_SYSCALL(getegid16)() {} + +POST_SYSCALL(getegid16)(long res) {} +# endif // SANITIZER_USES_UID16_SYSCALLS + +PRE_SYSCALL(utime)(void *filename, void *times) {} + +POST_SYSCALL(utime)(long res, void *filename, void *times) { + if (res >= 0) { + if (filename) + POST_WRITE(filename, + __sanitizer::internal_strlen((const char *)filename) + 1); + if (times) + POST_WRITE(times, struct_utimbuf_sz); + } +} + +PRE_SYSCALL(utimes)(void *filename, void *utimes) {} + +POST_SYSCALL(utimes)(long res, void *filename, void *utimes) { + if (res >= 0) { + if (filename) + POST_WRITE(filename, + __sanitizer::internal_strlen((const char *)filename) + 1); + if (utimes) + POST_WRITE(utimes, timeval_sz); + } +} + +PRE_SYSCALL(lseek)(long fd, long offset, long origin) {} + +POST_SYSCALL(lseek)(long res, long fd, long offset, long origin) {} + +PRE_SYSCALL(llseek) +(long fd, long offset_high, long offset_low, void *result, long origin) {} + +POST_SYSCALL(llseek) +(long res, long fd, long offset_high, long offset_low, void *result, + long origin) { + if (res >= 0) { + if (result) + POST_WRITE(result, sizeof(long long)); + } +} + +PRE_SYSCALL(readv)(long fd, const __sanitizer_iovec *vec, long vlen) {} + +POST_SYSCALL(readv) +(long res, long fd, const __sanitizer_iovec *vec, long vlen) { + if (res >= 0) { + if (vec) + kernel_write_iovec(vec, vlen, res); + } +} + +PRE_SYSCALL(write)(long fd, const void *buf, long count) { + if (buf) + PRE_READ(buf, count); +} + +POST_SYSCALL(write)(long res, long fd, const void *buf, long count) {} + +PRE_SYSCALL(writev)(long fd, const __sanitizer_iovec *vec, long vlen) {} + +POST_SYSCALL(writev) +(long res, long fd, const __sanitizer_iovec *vec, long vlen) { + if (res >= 0) { + if (vec) + kernel_read_iovec(vec, vlen, res); + } +} + +# ifdef _LP64 +PRE_SYSCALL(pread64)(long fd, void *buf, long count, long pos) {} + +POST_SYSCALL(pread64)(long res, long fd, void *buf, long count, long pos) { + if (res >= 0) { + if (buf) + POST_WRITE(buf, res); + } +} + +PRE_SYSCALL(pwrite64)(long fd, const void *buf, long count, long pos) { + if (buf) + PRE_READ(buf, count); +} + +POST_SYSCALL(pwrite64) +(long res, long fd, const void *buf, long count, long pos) {} +# else +PRE_SYSCALL(pread64)(long fd, void *buf, long count, long pos0, long pos1) {} + +POST_SYSCALL(pread64) +(long res, long fd, void *buf, long count, long pos0, long pos1) { + if (res >= 0) { + if (buf) + POST_WRITE(buf, res); + } +} + +PRE_SYSCALL(pwrite64) +(long fd, const void *buf, long count, long pos0, long pos1) { + if (buf) + PRE_READ(buf, count); +} + +POST_SYSCALL(pwrite64) +(long res, long fd, const void *buf, long count, long pos0, long pos1) {} +# endif + +PRE_SYSCALL(preadv) +(long fd, const __sanitizer_iovec *vec, long vlen, long pos_l, long pos_h) {} + +POST_SYSCALL(preadv) +(long res, long fd, const __sanitizer_iovec *vec, long vlen, long pos_l, + long pos_h) { + if (res >= 0) { + if (vec) + kernel_write_iovec(vec, vlen, res); + } +} + +PRE_SYSCALL(pwritev) +(long fd, const __sanitizer_iovec *vec, long vlen, long pos_l, long pos_h) {} + +POST_SYSCALL(pwritev) +(long res, long fd, const __sanitizer_iovec *vec, long vlen, long pos_l, + long pos_h) { + if (res >= 0) { + if (vec) + kernel_read_iovec(vec, vlen, res); + } +} + +PRE_SYSCALL(getcwd)(void *buf, long size) {} + +POST_SYSCALL(getcwd)(long res, void *buf, long size) { + if (res >= 0) { + if (buf) + POST_WRITE(buf, __sanitizer::internal_strlen((const char *)buf) + 1); + } +} + +PRE_SYSCALL(mkdir)(const void *pathname, long mode) { + if (pathname) + PRE_READ(pathname, + __sanitizer::internal_strlen((const char *)pathname) + 1); +} + +POST_SYSCALL(mkdir)(long res, const void *pathname, long mode) {} + +PRE_SYSCALL(chdir)(const void *filename) { + if (filename) + PRE_READ(filename, + __sanitizer::internal_strlen((const char *)filename) + 1); +} + +POST_SYSCALL(chdir)(long res, const void *filename) {} + +PRE_SYSCALL(fchdir)(long fd) {} + +POST_SYSCALL(fchdir)(long res, long fd) {} + +PRE_SYSCALL(rmdir)(const void *pathname) { + if (pathname) + PRE_READ(pathname, + __sanitizer::internal_strlen((const char *)pathname) + 1); +} + +POST_SYSCALL(rmdir)(long res, const void *pathname) {} + +PRE_SYSCALL(lookup_dcookie)(u64 cookie64, void *buf, long len) {} + +POST_SYSCALL(lookup_dcookie)(long res, u64 cookie64, void *buf, long len) { + if (res >= 0) { + if (buf) + POST_WRITE(buf, __sanitizer::internal_strlen((const char *)buf) + 1); + } +} + +PRE_SYSCALL(quotactl)(long cmd, const void *special, long id, void *addr) { + if (special) + PRE_READ(special, __sanitizer::internal_strlen((const char *)special) + 1); +} + +POST_SYSCALL(quotactl) +(long res, long cmd, const void *special, long id, void *addr) {} + +PRE_SYSCALL(getdents)(long fd, void *dirent, long count) {} + +POST_SYSCALL(getdents)(long res, long fd, void *dirent, long count) { + if (res >= 0) { + if (dirent) + POST_WRITE(dirent, res); + } +} + +PRE_SYSCALL(getdents64)(long fd, void *dirent, long count) {} + +POST_SYSCALL(getdents64)(long res, long fd, void *dirent, long count) { + if (res >= 0) { + if (dirent) + POST_WRITE(dirent, res); + } +} + +PRE_SYSCALL(setsockopt) +(long fd, long level, long optname, void *optval, long optlen) {} + +POST_SYSCALL(setsockopt) +(long res, long fd, long level, long optname, void *optval, long optlen) { + if (res >= 0) { + if (optval) + POST_WRITE(optval, + __sanitizer::internal_strlen((const char *)optval) + 1); + } +} + +PRE_SYSCALL(getsockopt) +(long fd, long level, long optname, void *optval, void *optlen) {} + +POST_SYSCALL(getsockopt) +(long res, long fd, long level, long optname, void *optval, void *optlen) { + if (res >= 0) { + if (optval) + POST_WRITE(optval, + __sanitizer::internal_strlen((const char *)optval) + 1); + if (optlen) + POST_WRITE(optlen, sizeof(int)); + } +} + +PRE_SYSCALL(bind)(long arg0, sanitizer_kernel_sockaddr *arg1, long arg2) {} + +POST_SYSCALL(bind) +(long res, long arg0, sanitizer_kernel_sockaddr *arg1, long arg2) { + if (res >= 0) { + if (arg1) + POST_WRITE(arg1, sizeof(*arg1)); + } +} + +PRE_SYSCALL(connect)(long arg0, sanitizer_kernel_sockaddr *arg1, long arg2) {} + +POST_SYSCALL(connect) +(long res, long arg0, sanitizer_kernel_sockaddr *arg1, long arg2) { + if (res >= 0) { + if (arg1) + POST_WRITE(arg1, sizeof(*arg1)); + } +} + +PRE_SYSCALL(accept)(long arg0, sanitizer_kernel_sockaddr *arg1, void *arg2) {} + +POST_SYSCALL(accept) +(long res, long arg0, sanitizer_kernel_sockaddr *arg1, void *arg2) { + if (res >= 0) { + if (arg1) + POST_WRITE(arg1, sizeof(*arg1)); + if (arg2) + POST_WRITE(arg2, sizeof(unsigned)); + } +} + +PRE_SYSCALL(accept4) +(long arg0, sanitizer_kernel_sockaddr *arg1, void *arg2, long arg3) {} + +POST_SYSCALL(accept4) +(long res, long arg0, sanitizer_kernel_sockaddr *arg1, void *arg2, long arg3) { + if (res >= 0) { + if (arg1) + POST_WRITE(arg1, sizeof(*arg1)); + if (arg2) + POST_WRITE(arg2, sizeof(unsigned)); + } +} + +PRE_SYSCALL(getsockname) +(long arg0, sanitizer_kernel_sockaddr *arg1, void *arg2) {} + +POST_SYSCALL(getsockname) +(long res, long arg0, sanitizer_kernel_sockaddr *arg1, void *arg2) { + if (res >= 0) { + if (arg1) + POST_WRITE(arg1, sizeof(*arg1)); + if (arg2) + POST_WRITE(arg2, sizeof(unsigned)); + } +} + +PRE_SYSCALL(getpeername) +(long arg0, sanitizer_kernel_sockaddr *arg1, void *arg2) {} + +POST_SYSCALL(getpeername) +(long res, long arg0, sanitizer_kernel_sockaddr *arg1, void *arg2) { + if (res >= 0) { + if (arg1) + POST_WRITE(arg1, sizeof(*arg1)); + if (arg2) + POST_WRITE(arg2, sizeof(unsigned)); + } +} + +PRE_SYSCALL(send)(long arg0, void *arg1, long arg2, long arg3) {} + +POST_SYSCALL(send)(long res, long arg0, void *arg1, long arg2, long arg3) { + if (res) { + if (arg1) + POST_READ(arg1, res); + } +} + +PRE_SYSCALL(sendto) +(long arg0, void *arg1, long arg2, long arg3, sanitizer_kernel_sockaddr *arg4, + long arg5) {} + +POST_SYSCALL(sendto) +(long res, long arg0, void *arg1, long arg2, long arg3, + sanitizer_kernel_sockaddr *arg4, long arg5) { + if (res >= 0) { + if (arg1) + POST_READ(arg1, res); + if (arg4) + POST_WRITE(arg4, sizeof(*arg4)); + } +} + +PRE_SYSCALL(sendmsg)(long fd, void *msg, long flags) {} + +POST_SYSCALL(sendmsg)(long res, long fd, void *msg, long flags) { + // FIXME: POST_READ +} + +PRE_SYSCALL(sendmmsg)(long fd, void *msg, long vlen, long flags) {} + +POST_SYSCALL(sendmmsg)(long res, long fd, void *msg, long vlen, long flags) { + // FIXME: POST_READ +} + +PRE_SYSCALL(recv)(long arg0, void *buf, long len, long flags) {} + +POST_SYSCALL(recv)(long res, void *buf, long len, long flags) { + if (res >= 0) { + if (buf) + POST_WRITE(buf, res); + } +} + +PRE_SYSCALL(recvfrom) +(long arg0, void *buf, long len, long flags, sanitizer_kernel_sockaddr *arg4, + void *arg5) {} + +POST_SYSCALL(recvfrom) +(long res, long arg0, void *buf, long len, long flags, + sanitizer_kernel_sockaddr *arg4, void *arg5) { + if (res >= 0) { + if (buf) + POST_WRITE(buf, res); + if (arg4) + POST_WRITE(arg4, sizeof(*arg4)); + if (arg5) + POST_WRITE(arg5, sizeof(int)); + } +} + +PRE_SYSCALL(socket)(long arg0, long arg1, long arg2) {} + +POST_SYSCALL(socket)(long res, long arg0, long arg1, long arg2) {} + +PRE_SYSCALL(socketpair)(long arg0, long arg1, long arg2, int *sv) {} + +POST_SYSCALL(socketpair)(long res, long arg0, long arg1, long arg2, int *sv) { + if (res >= 0) + if (sv) + POST_WRITE(sv, sizeof(int) * 2); +} + +PRE_SYSCALL(socketcall)(long call, void *args) {} + +POST_SYSCALL(socketcall)(long res, long call, void *args) { + if (res >= 0) { + if (args) + POST_WRITE(args, sizeof(long)); + } +} + +PRE_SYSCALL(listen)(long arg0, long arg1) {} + +POST_SYSCALL(listen)(long res, long arg0, long arg1) {} + +PRE_SYSCALL(poll)(void *ufds, long nfds, long timeout) {} + +POST_SYSCALL(poll) +(long res, __sanitizer_pollfd *ufds, long nfds, long timeout) { + if (res >= 0) { + if (ufds) + POST_WRITE(ufds, nfds * sizeof(*ufds)); + } +} + +PRE_SYSCALL(select) +(long n, __sanitizer___kernel_fd_set *inp, __sanitizer___kernel_fd_set *outp, + __sanitizer___kernel_fd_set *exp, void *tvp) {} + +POST_SYSCALL(select) +(long res, long n, __sanitizer___kernel_fd_set *inp, + __sanitizer___kernel_fd_set *outp, __sanitizer___kernel_fd_set *exp, + void *tvp) { + if (res >= 0) { + if (inp) + POST_WRITE(inp, sizeof(*inp)); + if (outp) + POST_WRITE(outp, sizeof(*outp)); + if (exp) + POST_WRITE(exp, sizeof(*exp)); + if (tvp) + POST_WRITE(tvp, timeval_sz); + } +} + +PRE_SYSCALL(old_select)(void *arg) {} + +POST_SYSCALL(old_select)(long res, void *arg) {} + +PRE_SYSCALL(epoll_create)(long size) {} + +POST_SYSCALL(epoll_create)(long res, long size) {} + +PRE_SYSCALL(epoll_create1)(long flags) {} + +POST_SYSCALL(epoll_create1)(long res, long flags) {} + +PRE_SYSCALL(epoll_ctl)(long epfd, long op, long fd, void *event) {} + +POST_SYSCALL(epoll_ctl)(long res, long epfd, long op, long fd, void *event) { + if (res >= 0) { + if (event) + POST_WRITE(event, struct_epoll_event_sz); + } +} + +PRE_SYSCALL(epoll_wait) +(long epfd, void *events, long maxevents, long timeout) {} + +POST_SYSCALL(epoll_wait) +(long res, long epfd, void *events, long maxevents, long timeout) { + if (res >= 0) { + if (events) + POST_WRITE(events, res * struct_epoll_event_sz); + } +} + +PRE_SYSCALL(epoll_pwait) +(long epfd, void *events, long maxevents, long timeout, + const kernel_sigset_t *sigmask, long sigsetsize) { + if (sigmask) + PRE_READ(sigmask, sigsetsize); +} + +POST_SYSCALL(epoll_pwait) +(long res, long epfd, void *events, long maxevents, long timeout, + const void *sigmask, long sigsetsize) { + if (res >= 0) { + if (events) + POST_WRITE(events, res * struct_epoll_event_sz); + } +} + +PRE_SYSCALL(epoll_pwait2) +(long epfd, void *events, long maxevents, + const sanitizer_kernel_timespec *timeout, const kernel_sigset_t *sigmask, + long sigsetsize) { + if (timeout) + PRE_READ(timeout, sizeof(timeout)); + if (sigmask) + PRE_READ(sigmask, sigsetsize); +} + +POST_SYSCALL(epoll_pwait2) +(long res, long epfd, void *events, long maxevents, + const sanitizer_kernel_timespec *timeout, const void *sigmask, + long sigsetsize) { + if (res >= 0) { + if (events) + POST_WRITE(events, res * struct_epoll_event_sz); + } +} + +PRE_SYSCALL(gethostname)(void *name, long len) {} + +POST_SYSCALL(gethostname)(long res, void *name, long len) { + if (res >= 0) { + if (name) + POST_WRITE(name, __sanitizer::internal_strlen((const char *)name) + 1); + } +} + +PRE_SYSCALL(sethostname)(void *name, long len) {} + +POST_SYSCALL(sethostname)(long res, void *name, long len) { + if (res >= 0) { + if (name) + POST_WRITE(name, __sanitizer::internal_strlen((const char *)name) + 1); + } +} + +PRE_SYSCALL(setdomainname)(void *name, long len) {} + +POST_SYSCALL(setdomainname)(long res, void *name, long len) { + if (res >= 0) { + if (name) + POST_WRITE(name, __sanitizer::internal_strlen((const char *)name) + 1); + } +} + +PRE_SYSCALL(newuname)(void *name) {} + +POST_SYSCALL(newuname)(long res, void *name) { + if (res >= 0) { + if (name) + POST_WRITE(name, struct_new_utsname_sz); + } +} + +PRE_SYSCALL(uname)(void *arg0) {} + +POST_SYSCALL(uname)(long res, void *arg0) { + if (res >= 0) { + if (arg0) + POST_WRITE(arg0, struct_old_utsname_sz); + } +} + +PRE_SYSCALL(olduname)(void *arg0) {} + +POST_SYSCALL(olduname)(long res, void *arg0) { + if (res >= 0) { + if (arg0) + POST_WRITE(arg0, struct_oldold_utsname_sz); + } +} + +PRE_SYSCALL(getrlimit)(long resource, void *rlim) {} + +POST_SYSCALL(getrlimit)(long res, long resource, void *rlim) { + if (res >= 0) { + if (rlim) + POST_WRITE(rlim, struct_rlimit_sz); + } +} + +PRE_SYSCALL(old_getrlimit)(long resource, void *rlim) {} + +POST_SYSCALL(old_getrlimit)(long res, long resource, void *rlim) { + if (res >= 0) { + if (rlim) + POST_WRITE(rlim, struct_rlimit_sz); + } +} + +PRE_SYSCALL(setrlimit)(long resource, void *rlim) {} + +POST_SYSCALL(setrlimit)(long res, long resource, void *rlim) { + if (res >= 0) { + if (rlim) + POST_WRITE(rlim, struct_rlimit_sz); + } +} + +# if !SANITIZER_ANDROID +PRE_SYSCALL(prlimit64) +(long pid, long resource, const void *new_rlim, void *old_rlim) { + if (new_rlim) + PRE_READ(new_rlim, struct_rlimit64_sz); +} + +POST_SYSCALL(prlimit64) +(long res, long pid, long resource, const void *new_rlim, void *old_rlim) { + if (res >= 0) { + if (old_rlim) + POST_WRITE(old_rlim, struct_rlimit64_sz); + } +} +# endif + +PRE_SYSCALL(getrusage)(long who, void *ru) {} + +POST_SYSCALL(getrusage)(long res, long who, void *ru) { + if (res >= 0) { + if (ru) + POST_WRITE(ru, struct_rusage_sz); + } +} + +PRE_SYSCALL(umask)(long mask) {} + +POST_SYSCALL(umask)(long res, long mask) {} + +PRE_SYSCALL(msgget)(long key, long msgflg) {} + +POST_SYSCALL(msgget)(long res, long key, long msgflg) {} + +PRE_SYSCALL(msgsnd)(long msqid, void *msgp, long msgsz, long msgflg) { + if (msgp) + PRE_READ(msgp, msgsz); +} + +POST_SYSCALL(msgsnd) +(long res, long msqid, void *msgp, long msgsz, long msgflg) {} + +PRE_SYSCALL(msgrcv) +(long msqid, void *msgp, long msgsz, long msgtyp, long msgflg) {} + +POST_SYSCALL(msgrcv) +(long res, long msqid, void *msgp, long msgsz, long msgtyp, long msgflg) { + if (res >= 0) { + if (msgp) + POST_WRITE(msgp, res); + } +} + +# if !SANITIZER_ANDROID +PRE_SYSCALL(msgctl)(long msqid, long cmd, void *buf) {} + +POST_SYSCALL(msgctl)(long res, long msqid, long cmd, void *buf) { + if (res >= 0) { + if (buf) + POST_WRITE(buf, struct_msqid_ds_sz); + } +} +# endif + +PRE_SYSCALL(semget)(long key, long nsems, long semflg) {} + +POST_SYSCALL(semget)(long res, long key, long nsems, long semflg) {} + +PRE_SYSCALL(semop)(long semid, void *sops, long nsops) {} + +POST_SYSCALL(semop)(long res, long semid, void *sops, long nsops) {} + +PRE_SYSCALL(semctl)(long semid, long semnum, long cmd, void *arg) {} + +POST_SYSCALL(semctl)(long res, long semid, long semnum, long cmd, void *arg) {} + +PRE_SYSCALL(semtimedop) +(long semid, void *sops, long nsops, const void *timeout) { + if (timeout) + PRE_READ(timeout, struct_timespec_sz); +} + +POST_SYSCALL(semtimedop) +(long res, long semid, void *sops, long nsops, const void *timeout) {} + +PRE_SYSCALL(shmat)(long shmid, void *shmaddr, long shmflg) {} + +POST_SYSCALL(shmat)(long res, long shmid, void *shmaddr, long shmflg) { + if (res >= 0) { + if (shmaddr) + POST_WRITE(shmaddr, + __sanitizer::internal_strlen((const char *)shmaddr) + 1); + } +} + +PRE_SYSCALL(shmget)(long key, long size, long flag) {} + +POST_SYSCALL(shmget)(long res, long key, long size, long flag) {} + +PRE_SYSCALL(shmdt)(void *shmaddr) {} + +POST_SYSCALL(shmdt)(long res, void *shmaddr) { + if (res >= 0) { + if (shmaddr) + POST_WRITE(shmaddr, + __sanitizer::internal_strlen((const char *)shmaddr) + 1); + } +} + +PRE_SYSCALL(ipc) +(long call, long first, long second, long third, void *ptr, long fifth) {} + +POST_SYSCALL(ipc) +(long res, long call, long first, long second, long third, void *ptr, + long fifth) {} + +# if !SANITIZER_ANDROID +PRE_SYSCALL(shmctl)(long shmid, long cmd, void *buf) {} + +POST_SYSCALL(shmctl)(long res, long shmid, long cmd, void *buf) { + if (res >= 0) { + if (buf) + POST_WRITE(buf, sizeof(__sanitizer_shmid_ds)); + } +} + +PRE_SYSCALL(mq_open)(const void *name, long oflag, long mode, void *attr) { + if (name) + PRE_READ(name, __sanitizer::internal_strlen((const char *)name) + 1); +} + +POST_SYSCALL(mq_open) +(long res, const void *name, long oflag, long mode, void *attr) { + if (res >= 0) { + if (attr) + POST_WRITE(attr, struct_mq_attr_sz); + } +} + +PRE_SYSCALL(mq_unlink)(const void *name) { + if (name) + PRE_READ(name, __sanitizer::internal_strlen((const char *)name) + 1); +} + +POST_SYSCALL(mq_unlink)(long res, const void *name) {} + +PRE_SYSCALL(mq_timedsend) +(long mqdes, const void *msg_ptr, long msg_len, long msg_prio, + const void *abs_timeout) { + if (msg_ptr) + PRE_READ(msg_ptr, msg_len); + if (abs_timeout) + PRE_READ(abs_timeout, struct_timespec_sz); +} + +POST_SYSCALL(mq_timedsend) +(long res, long mqdes, const void *msg_ptr, long msg_len, long msg_prio, + const void *abs_timeout) {} + +PRE_SYSCALL(mq_timedreceive) +(long mqdes, void *msg_ptr, long msg_len, void *msg_prio, + const void *abs_timeout) { + if (abs_timeout) + PRE_READ(abs_timeout, struct_timespec_sz); +} + +POST_SYSCALL(mq_timedreceive) +(long res, long mqdes, void *msg_ptr, long msg_len, int *msg_prio, + const void *abs_timeout) { + if (res >= 0) { + if (msg_ptr) + POST_WRITE(msg_ptr, res); + if (msg_prio) + POST_WRITE(msg_prio, sizeof(*msg_prio)); + } +} + +PRE_SYSCALL(mq_notify)(long mqdes, const void *notification) { + if (notification) + PRE_READ(notification, struct_sigevent_sz); +} + +POST_SYSCALL(mq_notify)(long res, long mqdes, const void *notification) {} + +PRE_SYSCALL(mq_getsetattr)(long mqdes, const void *mqstat, void *omqstat) { + if (mqstat) + PRE_READ(mqstat, struct_mq_attr_sz); +} + +POST_SYSCALL(mq_getsetattr) +(long res, long mqdes, const void *mqstat, void *omqstat) { + if (res >= 0) { + if (omqstat) + POST_WRITE(omqstat, struct_mq_attr_sz); + } +} +# endif // SANITIZER_ANDROID + +PRE_SYSCALL(pciconfig_iobase)(long which, long bus, long devfn) {} + +POST_SYSCALL(pciconfig_iobase)(long res, long which, long bus, long devfn) {} + +PRE_SYSCALL(pciconfig_read) +(long bus, long dfn, long off, long len, void *buf) {} + +POST_SYSCALL(pciconfig_read) +(long res, long bus, long dfn, long off, long len, void *buf) {} + +PRE_SYSCALL(pciconfig_write) +(long bus, long dfn, long off, long len, void *buf) {} + +POST_SYSCALL(pciconfig_write) +(long res, long bus, long dfn, long off, long len, void *buf) {} + +PRE_SYSCALL(swapon)(const void *specialfile, long swap_flags) { + if (specialfile) + PRE_READ(specialfile, + __sanitizer::internal_strlen((const char *)specialfile) + 1); +} + +POST_SYSCALL(swapon)(long res, const void *specialfile, long swap_flags) {} + +PRE_SYSCALL(swapoff)(const void *specialfile) { + if (specialfile) + PRE_READ(specialfile, + __sanitizer::internal_strlen((const char *)specialfile) + 1); +} + +POST_SYSCALL(swapoff)(long res, const void *specialfile) {} + +PRE_SYSCALL(sysctl)(__sanitizer___sysctl_args *args) { + if (args) { + if (args->name) + PRE_READ(args->name, args->nlen * sizeof(*args->name)); + if (args->newval) + PRE_READ(args->name, args->newlen); + } +} + +POST_SYSCALL(sysctl)(long res, __sanitizer___sysctl_args *args) { + if (res >= 0) { + if (args && args->oldval && args->oldlenp) { + POST_WRITE(args->oldlenp, sizeof(*args->oldlenp)); + POST_WRITE(args->oldval, *args->oldlenp); + } + } +} + +PRE_SYSCALL(sysinfo)(void *info) {} + +POST_SYSCALL(sysinfo)(long res, void *info) { + if (res >= 0) { + if (info) + POST_WRITE(info, struct_sysinfo_sz); + } +} + +PRE_SYSCALL(sysfs)(long option, long arg1, long arg2) {} + +POST_SYSCALL(sysfs)(long res, long option, long arg1, long arg2) {} + +PRE_SYSCALL(syslog)(long type, void *buf, long len) {} + +POST_SYSCALL(syslog)(long res, long type, void *buf, long len) { + if (res >= 0) { + if (buf) + POST_WRITE(buf, __sanitizer::internal_strlen((const char *)buf) + 1); + } +} + +PRE_SYSCALL(uselib)(const void *library) { + if (library) + PRE_READ(library, __sanitizer::internal_strlen((const char *)library) + 1); +} + +POST_SYSCALL(uselib)(long res, const void *library) {} + +PRE_SYSCALL(ni_syscall)() {} + +POST_SYSCALL(ni_syscall)(long res) {} + +PRE_SYSCALL(ptrace)(long request, long pid, long addr, long data) { +# if !SANITIZER_ANDROID && \ + (defined(__i386) || defined(__x86_64) || defined(__mips64) || \ + defined(__powerpc64__) || defined(__aarch64__) || defined(__s390__) || \ + SANITIZER_RISCV64) + if (data) { + if (request == ptrace_setregs) { + PRE_READ((void *)data, struct_user_regs_struct_sz); + } else if (request == ptrace_setfpregs) { + PRE_READ((void *)data, struct_user_fpregs_struct_sz); + } else if (request == ptrace_setfpxregs) { + PRE_READ((void *)data, struct_user_fpxregs_struct_sz); + } else if (request == ptrace_setsiginfo) { + PRE_READ((void *)data, siginfo_t_sz); + } else if (request == ptrace_setregset) { + __sanitizer_iovec *iov = (__sanitizer_iovec *)data; + PRE_READ(iov->iov_base, iov->iov_len); + } + } +# endif +} + +POST_SYSCALL(ptrace)(long res, long request, long pid, long addr, long data) { +# if !SANITIZER_ANDROID && \ + (defined(__i386) || defined(__x86_64) || defined(__mips64) || \ + defined(__powerpc64__) || defined(__aarch64__) || defined(__s390__) || \ + SANITIZER_RISCV64) + if (res >= 0 && data) { + // Note that this is different from the interceptor in + // sanitizer_common_interceptors.inc. + // PEEK* requests return resulting values through data pointer. + if (request == ptrace_getregs) { + POST_WRITE((void *)data, struct_user_regs_struct_sz); + } else if (request == ptrace_getfpregs) { + POST_WRITE((void *)data, struct_user_fpregs_struct_sz); + } else if (request == ptrace_getfpxregs) { + POST_WRITE((void *)data, struct_user_fpxregs_struct_sz); + } else if (request == ptrace_getsiginfo) { + POST_WRITE((void *)data, siginfo_t_sz); + } else if (request == ptrace_getregset) { + __sanitizer_iovec *iov = (__sanitizer_iovec *)data; + POST_WRITE(iov->iov_base, iov->iov_len); + } else if (request == ptrace_peekdata || request == ptrace_peektext || + request == ptrace_peekuser) { + POST_WRITE((void *)data, sizeof(void *)); + } + } +# endif +} + +PRE_SYSCALL(add_key) +(const void *_type, const void *_description, const void *_payload, long plen, + long destringid) { + if (_type) + PRE_READ(_type, __sanitizer::internal_strlen((const char *)_type) + 1); + if (_description) + PRE_READ(_description, + __sanitizer::internal_strlen((const char *)_description) + 1); +} + +POST_SYSCALL(add_key) +(long res, const void *_type, const void *_description, const void *_payload, + long plen, long destringid) {} + +PRE_SYSCALL(request_key) +(const void *_type, const void *_description, const void *_callout_info, + long destringid) { + if (_type) + PRE_READ(_type, __sanitizer::internal_strlen((const char *)_type) + 1); + if (_description) + PRE_READ(_description, + __sanitizer::internal_strlen((const char *)_description) + 1); + if (_callout_info) + PRE_READ(_callout_info, + __sanitizer::internal_strlen((const char *)_callout_info) + 1); +} + +POST_SYSCALL(request_key) +(long res, const void *_type, const void *_description, + const void *_callout_info, long destringid) {} + +PRE_SYSCALL(keyctl)(long cmd, long arg2, long arg3, long arg4, long arg5) {} + +POST_SYSCALL(keyctl) +(long res, long cmd, long arg2, long arg3, long arg4, long arg5) {} + +PRE_SYSCALL(ioprio_set)(long which, long who, long ioprio) {} + +POST_SYSCALL(ioprio_set)(long res, long which, long who, long ioprio) {} + +PRE_SYSCALL(ioprio_get)(long which, long who) {} + +POST_SYSCALL(ioprio_get)(long res, long which, long who) {} + +PRE_SYSCALL(set_mempolicy)(long mode, void *nmask, long maxnode) {} + +POST_SYSCALL(set_mempolicy)(long res, long mode, void *nmask, long maxnode) { + if (res >= 0) { + if (nmask) + POST_WRITE(nmask, sizeof(long)); + } +} + +PRE_SYSCALL(migrate_pages) +(long pid, long maxnode, const void *from, const void *to) { + if (from) + PRE_READ(from, sizeof(long)); + if (to) + PRE_READ(to, sizeof(long)); +} + +POST_SYSCALL(migrate_pages) +(long res, long pid, long maxnode, const void *from, const void *to) {} + +PRE_SYSCALL(move_pages) +(long pid, long nr_pages, const void **pages, const int *nodes, int *status, + long flags) { + if (pages) + PRE_READ(pages, nr_pages * sizeof(*pages)); + if (nodes) + PRE_READ(nodes, nr_pages * sizeof(*nodes)); +} + +POST_SYSCALL(move_pages) +(long res, long pid, long nr_pages, const void **pages, const int *nodes, + int *status, long flags) { + if (res >= 0) { + if (status) + POST_WRITE(status, nr_pages * sizeof(*status)); + } +} + +PRE_SYSCALL(mbind) +(long start, long len, long mode, void *nmask, long maxnode, long flags) {} + +POST_SYSCALL(mbind) +(long res, long start, long len, long mode, void *nmask, long maxnode, + long flags) { + if (res >= 0) { + if (nmask) + POST_WRITE(nmask, sizeof(long)); + } +} + +PRE_SYSCALL(get_mempolicy) +(void *policy, void *nmask, long maxnode, long addr, long flags) {} + +POST_SYSCALL(get_mempolicy) +(long res, void *policy, void *nmask, long maxnode, long addr, long flags) { + if (res >= 0) { + if (policy) + POST_WRITE(policy, sizeof(int)); + if (nmask) + POST_WRITE(nmask, sizeof(long)); + } +} + +PRE_SYSCALL(inotify_init)() {} + +POST_SYSCALL(inotify_init)(long res) {} + +PRE_SYSCALL(inotify_init1)(long flags) {} + +POST_SYSCALL(inotify_init1)(long res, long flags) {} + +PRE_SYSCALL(inotify_add_watch)(long fd, const void *path, long mask) { + if (path) + PRE_READ(path, __sanitizer::internal_strlen((const char *)path) + 1); +} + +POST_SYSCALL(inotify_add_watch) +(long res, long fd, const void *path, long mask) {} + +PRE_SYSCALL(inotify_rm_watch)(long fd, long wd) {} + +POST_SYSCALL(inotify_rm_watch)(long res, long fd, long wd) {} + +PRE_SYSCALL(spu_run)(long fd, void *unpc, void *ustatus) {} + +POST_SYSCALL(spu_run)(long res, long fd, unsigned *unpc, unsigned *ustatus) { + if (res >= 0) { + if (unpc) + POST_WRITE(unpc, sizeof(*unpc)); + if (ustatus) + POST_WRITE(ustatus, sizeof(*ustatus)); + } +} + +PRE_SYSCALL(spu_create)(const void *name, long flags, long mode, long fd) { + if (name) + PRE_READ(name, __sanitizer::internal_strlen((const char *)name) + 1); +} + +POST_SYSCALL(spu_create) +(long res, const void *name, long flags, long mode, long fd) {} + +PRE_SYSCALL(mknodat)(long dfd, const void *filename, long mode, long dev) { + if (filename) + PRE_READ(filename, + __sanitizer::internal_strlen((const char *)filename) + 1); +} + +POST_SYSCALL(mknodat) +(long res, long dfd, const void *filename, long mode, long dev) {} + +PRE_SYSCALL(mkdirat)(long dfd, const void *pathname, long mode) { + if (pathname) + PRE_READ(pathname, + __sanitizer::internal_strlen((const char *)pathname) + 1); +} + +POST_SYSCALL(mkdirat)(long res, long dfd, const void *pathname, long mode) {} + +PRE_SYSCALL(unlinkat)(long dfd, const void *pathname, long flag) { + if (pathname) + PRE_READ(pathname, + __sanitizer::internal_strlen((const char *)pathname) + 1); +} + +POST_SYSCALL(unlinkat)(long res, long dfd, const void *pathname, long flag) {} + +PRE_SYSCALL(symlinkat)(const void *oldname, long newdfd, const void *newname) { + if (oldname) + PRE_READ(oldname, __sanitizer::internal_strlen((const char *)oldname) + 1); + if (newname) + PRE_READ(newname, __sanitizer::internal_strlen((const char *)newname) + 1); +} + +POST_SYSCALL(symlinkat) +(long res, const void *oldname, long newdfd, const void *newname) {} + +PRE_SYSCALL(linkat) +(long olddfd, const void *oldname, long newdfd, const void *newname, + long flags) { + if (oldname) + PRE_READ(oldname, __sanitizer::internal_strlen((const char *)oldname) + 1); + if (newname) + PRE_READ(newname, __sanitizer::internal_strlen((const char *)newname) + 1); +} + +POST_SYSCALL(linkat) +(long res, long olddfd, const void *oldname, long newdfd, const void *newname, + long flags) {} + +PRE_SYSCALL(renameat) +(long olddfd, const void *oldname, long newdfd, const void *newname) { + if (oldname) + PRE_READ(oldname, __sanitizer::internal_strlen((const char *)oldname) + 1); + if (newname) + PRE_READ(newname, __sanitizer::internal_strlen((const char *)newname) + 1); +} + +POST_SYSCALL(renameat) +(long res, long olddfd, const void *oldname, long newdfd, const void *newname) { +} + +PRE_SYSCALL(futimesat)(long dfd, const void *filename, void *utimes) { + if (filename) + PRE_READ(filename, + __sanitizer::internal_strlen((const char *)filename) + 1); +} + +POST_SYSCALL(futimesat) +(long res, long dfd, const void *filename, void *utimes) { + if (res >= 0) { + if (utimes) + POST_WRITE(utimes, timeval_sz); + } +} + +PRE_SYSCALL(faccessat)(long dfd, const void *filename, long mode) { + if (filename) + PRE_READ(filename, + __sanitizer::internal_strlen((const char *)filename) + 1); +} + +POST_SYSCALL(faccessat)(long res, long dfd, const void *filename, long mode) {} + +PRE_SYSCALL(fchmodat)(long dfd, const void *filename, long mode) { + if (filename) + PRE_READ(filename, + __sanitizer::internal_strlen((const char *)filename) + 1); +} + +POST_SYSCALL(fchmodat)(long res, long dfd, const void *filename, long mode) {} + +PRE_SYSCALL(fchownat) +(long dfd, const void *filename, long user, long group, long flag) { + if (filename) + PRE_READ(filename, + __sanitizer::internal_strlen((const char *)filename) + 1); +} + +POST_SYSCALL(fchownat) +(long res, long dfd, const void *filename, long user, long group, long flag) {} + +PRE_SYSCALL(openat)(long dfd, const void *filename, long flags, long mode) { + if (filename) + PRE_READ(filename, + __sanitizer::internal_strlen((const char *)filename) + 1); +} + +POST_SYSCALL(openat) +(long res, long dfd, const void *filename, long flags, long mode) {} + +PRE_SYSCALL(newfstatat) +(long dfd, const void *filename, void *statbuf, long flag) { + if (filename) + PRE_READ(filename, + __sanitizer::internal_strlen((const char *)filename) + 1); +} + +POST_SYSCALL(newfstatat) +(long res, long dfd, const void *filename, void *statbuf, long flag) { + if (res >= 0) { + if (statbuf) + POST_WRITE(statbuf, struct_kernel_stat_sz); + } +} + +PRE_SYSCALL(fstatat64) +(long dfd, const void *filename, void *statbuf, long flag) { + if (filename) + PRE_READ(filename, + __sanitizer::internal_strlen((const char *)filename) + 1); +} + +POST_SYSCALL(fstatat64) +(long res, long dfd, const void *filename, void *statbuf, long flag) { + if (res >= 0) { + if (statbuf) + POST_WRITE(statbuf, struct_kernel_stat64_sz); + } +} + +PRE_SYSCALL(readlinkat)(long dfd, const void *path, void *buf, long bufsiz) { + if (path) + PRE_READ(path, __sanitizer::internal_strlen((const char *)path) + 1); +} + +POST_SYSCALL(readlinkat) +(long res, long dfd, const void *path, void *buf, long bufsiz) { + if (res >= 0) { + if (buf) + POST_WRITE(buf, __sanitizer::internal_strlen((const char *)buf) + 1); + } +} + +PRE_SYSCALL(utimensat) +(long dfd, const void *filename, void *utimes, long flags) { + if (filename) + PRE_READ(filename, + __sanitizer::internal_strlen((const char *)filename) + 1); +} + +POST_SYSCALL(utimensat) +(long res, long dfd, const void *filename, void *utimes, long flags) { + if (res >= 0) { + if (utimes) + POST_WRITE(utimes, struct_timespec_sz); + } +} + +PRE_SYSCALL(unshare)(long unshare_flags) {} + +POST_SYSCALL(unshare)(long res, long unshare_flags) {} + +PRE_SYSCALL(splice) +(long fd_in, void *off_in, long fd_out, void *off_out, long len, long flags) {} + +POST_SYSCALL(splice) +(long res, long fd_in, void *off_in, long fd_out, void *off_out, long len, + long flags) { + if (res >= 0) { + if (off_in) + POST_WRITE(off_in, sizeof(long long)); + if (off_out) + POST_WRITE(off_out, sizeof(long long)); + } +} + +PRE_SYSCALL(vmsplice) +(long fd, const __sanitizer_iovec *iov, long nr_segs, long flags) {} + +POST_SYSCALL(vmsplice) +(long res, long fd, const __sanitizer_iovec *iov, long nr_segs, long flags) { + if (res >= 0) { + if (iov) + kernel_read_iovec(iov, nr_segs, res); + } +} + +PRE_SYSCALL(tee)(long fdin, long fdout, long len, long flags) {} + +POST_SYSCALL(tee)(long res, long fdin, long fdout, long len, long flags) {} + +PRE_SYSCALL(get_robust_list)(long pid, void *head_ptr, void *len_ptr) {} + +POST_SYSCALL(get_robust_list) +(long res, long pid, void *head_ptr, void *len_ptr) {} + +PRE_SYSCALL(set_robust_list)(void *head, long len) {} + +POST_SYSCALL(set_robust_list)(long res, void *head, long len) {} + +PRE_SYSCALL(getcpu)(void *cpu, void *node, void *cache) {} + +POST_SYSCALL(getcpu)(long res, void *cpu, void *node, void *cache) { + if (res >= 0) { + if (cpu) + POST_WRITE(cpu, sizeof(unsigned)); + if (node) + POST_WRITE(node, sizeof(unsigned)); + // The third argument to this system call is nowadays unused. + } +} + +PRE_SYSCALL(signalfd)(long ufd, void *user_mask, long sizemask) {} + +POST_SYSCALL(signalfd) +(long res, long ufd, kernel_sigset_t *user_mask, long sizemask) { + if (res >= 0) { + if (user_mask) + POST_WRITE(user_mask, sizemask); + } +} + +PRE_SYSCALL(signalfd4)(long ufd, void *user_mask, long sizemask, long flags) {} + +POST_SYSCALL(signalfd4) +(long res, long ufd, kernel_sigset_t *user_mask, long sizemask, long flags) { + if (res >= 0) { + if (user_mask) + POST_WRITE(user_mask, sizemask); + } +} + +PRE_SYSCALL(timerfd_create)(long clockid, long flags) {} + +POST_SYSCALL(timerfd_create)(long res, long clockid, long flags) {} + +PRE_SYSCALL(timerfd_settime) +(long ufd, long flags, const void *utmr, void *otmr) { + if (utmr) + PRE_READ(utmr, struct_itimerspec_sz); +} + +POST_SYSCALL(timerfd_settime) +(long res, long ufd, long flags, const void *utmr, void *otmr) { + if (res >= 0) { + if (otmr) + POST_WRITE(otmr, struct_itimerspec_sz); + } +} + +PRE_SYSCALL(timerfd_gettime)(long ufd, void *otmr) {} + +POST_SYSCALL(timerfd_gettime)(long res, long ufd, void *otmr) { + if (res >= 0) { + if (otmr) + POST_WRITE(otmr, struct_itimerspec_sz); + } +} + +PRE_SYSCALL(eventfd)(long count) {} + +POST_SYSCALL(eventfd)(long res, long count) {} + +PRE_SYSCALL(eventfd2)(long count, long flags) {} + +POST_SYSCALL(eventfd2)(long res, long count, long flags) {} + +PRE_SYSCALL(old_readdir)(long arg0, void *arg1, long arg2) {} + +POST_SYSCALL(old_readdir)(long res, long arg0, void *arg1, long arg2) { + // Missing definition of 'struct old_linux_dirent'. +} + +PRE_SYSCALL(pselect6) +(long arg0, __sanitizer___kernel_fd_set *arg1, + __sanitizer___kernel_fd_set *arg2, __sanitizer___kernel_fd_set *arg3, + void *arg4, void *arg5) {} + +POST_SYSCALL(pselect6) +(long res, long arg0, __sanitizer___kernel_fd_set *arg1, + __sanitizer___kernel_fd_set *arg2, __sanitizer___kernel_fd_set *arg3, + void *arg4, void *arg5) { + if (res >= 0) { + if (arg1) + POST_WRITE(arg1, sizeof(*arg1)); + if (arg2) + POST_WRITE(arg2, sizeof(*arg2)); + if (arg3) + POST_WRITE(arg3, sizeof(*arg3)); + if (arg4) + POST_WRITE(arg4, struct_timespec_sz); + } +} + +PRE_SYSCALL(ppoll) +(__sanitizer_pollfd *arg0, long arg1, void *arg2, const kernel_sigset_t *arg3, + long arg4) { + if (arg3) + PRE_READ(arg3, arg4); +} + +POST_SYSCALL(ppoll) +(long res, __sanitizer_pollfd *arg0, long arg1, void *arg2, const void *arg3, + long arg4) { + if (res >= 0) { + if (arg0) + POST_WRITE(arg0, sizeof(*arg0)); + if (arg2) + POST_WRITE(arg2, struct_timespec_sz); + } +} + +PRE_SYSCALL(syncfs)(long fd) {} + +POST_SYSCALL(syncfs)(long res, long fd) {} + +PRE_SYSCALL(perf_event_open) +(__sanitizer_perf_event_attr *attr_uptr, long pid, long cpu, long group_fd, + long flags) { + if (attr_uptr) + PRE_READ(attr_uptr, attr_uptr->size); +} + +POST_SYSCALL(perf_event_open) +(long res, __sanitizer_perf_event_attr *attr_uptr, long pid, long cpu, + long group_fd, long flags) {} + +PRE_SYSCALL(mmap_pgoff) +(long addr, long len, long prot, long flags, long fd, long pgoff) {} + +POST_SYSCALL(mmap_pgoff) +(long res, long addr, long len, long prot, long flags, long fd, long pgoff) {} + +PRE_SYSCALL(old_mmap)(void *arg) {} + +POST_SYSCALL(old_mmap)(long res, void *arg) {} + +PRE_SYSCALL(name_to_handle_at) +(long dfd, const void *name, void *handle, void *mnt_id, long flag) {} + +POST_SYSCALL(name_to_handle_at) +(long res, long dfd, const void *name, void *handle, void *mnt_id, long flag) {} + +PRE_SYSCALL(open_by_handle_at)(long mountdirfd, void *handle, long flags) {} + +POST_SYSCALL(open_by_handle_at) +(long res, long mountdirfd, void *handle, long flags) {} + +PRE_SYSCALL(setns)(long fd, long nstype) {} + +POST_SYSCALL(setns)(long res, long fd, long nstype) {} + +PRE_SYSCALL(process_vm_readv) +(long pid, const __sanitizer_iovec *lvec, long liovcnt, const void *rvec, + long riovcnt, long flags) {} + +POST_SYSCALL(process_vm_readv) +(long res, long pid, const __sanitizer_iovec *lvec, long liovcnt, + const void *rvec, long riovcnt, long flags) { + if (res >= 0) { + if (lvec) + kernel_write_iovec(lvec, liovcnt, res); + } +} + +PRE_SYSCALL(process_vm_writev) +(long pid, const __sanitizer_iovec *lvec, long liovcnt, const void *rvec, + long riovcnt, long flags) {} + +POST_SYSCALL(process_vm_writev) +(long res, long pid, const __sanitizer_iovec *lvec, long liovcnt, + const void *rvec, long riovcnt, long flags) { + if (res >= 0) { + if (lvec) + kernel_read_iovec(lvec, liovcnt, res); + } +} + +PRE_SYSCALL(fork)() { COMMON_SYSCALL_PRE_FORK(); } + +POST_SYSCALL(fork)(long res) { COMMON_SYSCALL_POST_FORK(res); } + +PRE_SYSCALL(vfork)() { COMMON_SYSCALL_PRE_FORK(); } + +POST_SYSCALL(vfork)(long res) { COMMON_SYSCALL_POST_FORK(res); } + +PRE_SYSCALL(sigaction) +(long signum, const __sanitizer_kernel_sigaction_t *act, + __sanitizer_kernel_sigaction_t *oldact) { + if (act) { + PRE_READ(&act->sigaction, sizeof(act->sigaction)); + PRE_READ(&act->sa_flags, sizeof(act->sa_flags)); + PRE_READ(&act->sa_mask, sizeof(act->sa_mask)); + } +} + +POST_SYSCALL(sigaction) +(long res, long signum, const __sanitizer_kernel_sigaction_t *act, + __sanitizer_kernel_sigaction_t *oldact) { + if (res >= 0 && oldact) + POST_WRITE(oldact, sizeof(*oldact)); +} + +PRE_SYSCALL(rt_sigaction) +(long signum, const __sanitizer_kernel_sigaction_t *act, + __sanitizer_kernel_sigaction_t *oldact, SIZE_T sz) { + if (act) { + PRE_READ(&act->sigaction, sizeof(act->sigaction)); + PRE_READ(&act->sa_flags, sizeof(act->sa_flags)); + PRE_READ(&act->sa_mask, sz); + } +} + +POST_SYSCALL(rt_sigaction) +(long res, long signum, const __sanitizer_kernel_sigaction_t *act, + __sanitizer_kernel_sigaction_t *oldact, SIZE_T sz) { + if (res >= 0 && oldact) { + SIZE_T oldact_sz = ((char *)&oldact->sa_mask) - ((char *)oldact) + sz; + POST_WRITE(oldact, oldact_sz); + } +} + +PRE_SYSCALL(getrandom)(void *buf, uptr count, long flags) { + if (buf) { + PRE_WRITE(buf, count); + } +} + +POST_SYSCALL(getrandom)(long res, void *buf, uptr count, long flags) { + if (res > 0 && buf) { + POST_WRITE(buf, res); + } +} + +PRE_SYSCALL(sigaltstack)(const void *ss, void *oss) { + if (ss != nullptr) { + PRE_READ(ss, struct_stack_t_sz); + } + if (oss != nullptr) { + PRE_WRITE(oss, struct_stack_t_sz); + } +} + +POST_SYSCALL(sigaltstack)(long res, void *ss, void *oss) { + if (res == 0) { + if (oss != nullptr) { + POST_WRITE(oss, struct_stack_t_sz); + } + } +} +} // extern "C" + +# undef PRE_SYSCALL +# undef PRE_READ +# undef PRE_WRITE +# undef POST_SYSCALL +# undef POST_READ +# undef POST_WRITE + +#endif // SANITIZER_LINUX diff --git a/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_coverage_fuchsia.cpp b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_coverage_fuchsia.cpp new file mode 100644 index 0000000000..be1c47f24e --- /dev/null +++ b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_coverage_fuchsia.cpp @@ -0,0 +1,253 @@ +//===-- sanitizer_coverage_fuchsia.cpp ------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// Sanitizer Coverage Controller for Trace PC Guard, Fuchsia-specific version. +// +// This Fuchsia-specific implementation uses the same basic scheme and the +// same simple '.sancov' file format as the generic implementation. The +// difference is that we just produce a single blob of output for the whole +// program, not a separate one per DSO. We do not sort the PC table and do +// not prune the zeros, so the resulting file is always as large as it +// would be to report 100% coverage. Implicit tracing information about +// the address ranges of DSOs allows offline tools to split the one big +// blob into separate files that the 'sancov' tool can understand. +// +// Unlike the traditional implementation that uses an atexit hook to write +// out data files at the end, the results on Fuchsia do not go into a file +// per se. The 'coverage_dir' option is ignored. Instead, they are stored +// directly into a shared memory object (a Zircon VMO). At exit, that VMO +// is handed over to a system service that's responsible for getting the +// data out to somewhere that it can be fed into the sancov tool (where and +// how is not our problem). + +#include "sanitizer_platform.h" +#if SANITIZER_FUCHSIA +#error #include <zircon/process.h> +#error #include <zircon/sanitizer.h> +#error #include <zircon/syscalls.h> + +#include "sanitizer_atomic.h" +#include "sanitizer_common.h" +#include "sanitizer_internal_defs.h" +#include "sanitizer_symbolizer_fuchsia.h" + +using namespace __sanitizer; + +namespace __sancov { +namespace { + +// TODO(mcgrathr): Move the constant into a header shared with other impls. +constexpr u64 Magic64 = 0xC0BFFFFFFFFFFF64ULL; +static_assert(SANITIZER_WORDSIZE == 64, "Fuchsia is always LP64"); + +constexpr const char kSancovSinkName[] = "sancov"; + +// Collects trace-pc guard coverage. +// This class relies on zero-initialization. +class TracePcGuardController final { + public: + constexpr TracePcGuardController() {} + + // For each PC location being tracked, there is a u32 reserved in global + // data called the "guard". At startup, we assign each guard slot a + // unique index into the big results array. Later during runtime, the + // first call to TracePcGuard (below) will store the corresponding PC at + // that index in the array. (Each later call with the same guard slot is + // presumed to be from the same PC.) Then it clears the guard slot back + // to zero, which tells the compiler not to bother calling in again. At + // the end of the run, we have a big array where each element is either + // zero or is a tracked PC location that was hit in the trace. + + // This is called from global constructors. Each translation unit has a + // contiguous array of guard slots, and a constructor that calls here + // with the bounds of its array. Those constructors are allowed to call + // here more than once for the same array. Usually all of these + // constructors run in the initial thread, but it's possible that a + // dlopen call on a secondary thread will run constructors that get here. + void InitTracePcGuard(u32 *start, u32 *end) { + if (end > start && *start == 0 && common_flags()->coverage) { + // Complete the setup before filling in any guards with indices. + // This avoids the possibility of code called from Setup reentering + // TracePcGuard. + u32 idx = Setup(end - start); + for (u32 *p = start; p < end; ++p) { + *p = idx++; + } + } + } + + void TracePcGuard(u32 *guard, uptr pc) { + atomic_uint32_t *guard_ptr = reinterpret_cast<atomic_uint32_t *>(guard); + u32 idx = atomic_exchange(guard_ptr, 0, memory_order_relaxed); + if (idx > 0) + array_[idx] = pc; + } + + void Dump() { + Lock locked(&setup_lock_); + if (array_) { + CHECK_NE(vmo_, ZX_HANDLE_INVALID); + + // Publish the VMO to the system, where it can be collected and + // analyzed after this process exits. This always consumes the VMO + // handle. Any failure is just logged and not indicated to us. + __sanitizer_publish_data(kSancovSinkName, vmo_); + vmo_ = ZX_HANDLE_INVALID; + + // This will route to __sanitizer_log_write, which will ensure that + // information about shared libraries is written out. This message + // uses the `dumpfile` symbolizer markup element to highlight the + // dump. See the explanation for this in: + // https://fuchsia.googlesource.com/zircon/+/master/docs/symbolizer_markup.md + Printf("SanitizerCoverage: " FORMAT_DUMPFILE " with up to %u PCs\n", + kSancovSinkName, vmo_name_, next_index_ - 1); + } + } + + private: + // We map in the largest possible view into the VMO: one word + // for every possible 32-bit index value. This avoids the need + // to change the mapping when increasing the size of the VMO. + // We can always spare the 32G of address space. + static constexpr size_t MappingSize = sizeof(uptr) << 32; + + Mutex setup_lock_; + uptr *array_ = nullptr; + u32 next_index_ = 0; + zx_handle_t vmo_ = {}; + char vmo_name_[ZX_MAX_NAME_LEN] = {}; + + size_t DataSize() const { return next_index_ * sizeof(uintptr_t); } + + u32 Setup(u32 num_guards) { + Lock locked(&setup_lock_); + DCHECK(common_flags()->coverage); + + if (next_index_ == 0) { + CHECK_EQ(vmo_, ZX_HANDLE_INVALID); + CHECK_EQ(array_, nullptr); + + // The first sample goes at [1] to reserve [0] for the magic number. + next_index_ = 1 + num_guards; + + zx_status_t status = _zx_vmo_create(DataSize(), ZX_VMO_RESIZABLE, &vmo_); + CHECK_EQ(status, ZX_OK); + + // Give the VMO a name including our process KOID so it's easy to spot. + internal_snprintf(vmo_name_, sizeof(vmo_name_), "%s.%zu", kSancovSinkName, + internal_getpid()); + _zx_object_set_property(vmo_, ZX_PROP_NAME, vmo_name_, + internal_strlen(vmo_name_)); + uint64_t size = DataSize(); + status = _zx_object_set_property(vmo_, ZX_PROP_VMO_CONTENT_SIZE, &size, + sizeof(size)); + CHECK_EQ(status, ZX_OK); + + // Map the largest possible view we might need into the VMO. Later + // we might need to increase the VMO's size before we can use larger + // indices, but we'll never move the mapping address so we don't have + // any multi-thread synchronization issues with that. + uintptr_t mapping; + status = + _zx_vmar_map(_zx_vmar_root_self(), ZX_VM_PERM_READ | ZX_VM_PERM_WRITE, + 0, vmo_, 0, MappingSize, &mapping); + CHECK_EQ(status, ZX_OK); + + // Hereafter other threads are free to start storing into + // elements [1, next_index_) of the big array. + array_ = reinterpret_cast<uptr *>(mapping); + + // Store the magic number. + // Hereafter, the VMO serves as the contents of the '.sancov' file. + array_[0] = Magic64; + + return 1; + } else { + // The VMO is already mapped in, but it's not big enough to use the + // new indices. So increase the size to cover the new maximum index. + + CHECK_NE(vmo_, ZX_HANDLE_INVALID); + CHECK_NE(array_, nullptr); + + uint32_t first_index = next_index_; + next_index_ += num_guards; + + zx_status_t status = _zx_vmo_set_size(vmo_, DataSize()); + CHECK_EQ(status, ZX_OK); + uint64_t size = DataSize(); + status = _zx_object_set_property(vmo_, ZX_PROP_VMO_CONTENT_SIZE, &size, + sizeof(size)); + CHECK_EQ(status, ZX_OK); + + return first_index; + } + } +}; + +static TracePcGuardController pc_guard_controller; + +} // namespace +} // namespace __sancov + +namespace __sanitizer { +void InitializeCoverage(bool enabled, const char *dir) { + CHECK_EQ(enabled, common_flags()->coverage); + CHECK_EQ(dir, common_flags()->coverage_dir); + + static bool coverage_enabled = false; + if (!coverage_enabled) { + coverage_enabled = enabled; + Atexit(__sanitizer_cov_dump); + AddDieCallback(__sanitizer_cov_dump); + } +} +} // namespace __sanitizer + +extern "C" { +SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_dump_coverage(const uptr *pcs, + uptr len) { + UNIMPLEMENTED(); +} + +SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_pc_guard, u32 *guard) { + if (!*guard) + return; + __sancov::pc_guard_controller.TracePcGuard(guard, GET_CALLER_PC() - 1); +} + +SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_pc_guard_init, + u32 *start, u32 *end) { + if (start == end || *start) + return; + __sancov::pc_guard_controller.InitTracePcGuard(start, end); +} + +SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_dump_trace_pc_guard_coverage() { + __sancov::pc_guard_controller.Dump(); +} +SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_cov_dump() { + __sanitizer_dump_trace_pc_guard_coverage(); +} +// Default empty implementations (weak). Users should redefine them. +SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_cmp, void) {} +SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_cmp1, void) {} +SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_cmp2, void) {} +SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_cmp4, void) {} +SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_cmp8, void) {} +SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_const_cmp1, void) {} +SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_const_cmp2, void) {} +SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_const_cmp4, void) {} +SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_const_cmp8, void) {} +SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_switch, void) {} +SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_div4, void) {} +SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_div8, void) {} +SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_gep, void) {} +SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_pc_indir, void) {} +} // extern "C" + +#endif // !SANITIZER_FUCHSIA diff --git a/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_coverage_interface.inc b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_coverage_interface.inc new file mode 100644 index 0000000000..d7ab0c3d98 --- /dev/null +++ b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_coverage_interface.inc @@ -0,0 +1,33 @@ +//===-- sanitizer_coverage_interface.inc ----------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// Sanitizer Coverage interface list. +//===----------------------------------------------------------------------===// +INTERFACE_FUNCTION(__sanitizer_cov_dump) +INTERFACE_FUNCTION(__sanitizer_cov_reset) +INTERFACE_FUNCTION(__sanitizer_dump_coverage) +INTERFACE_FUNCTION(__sanitizer_dump_trace_pc_guard_coverage) +INTERFACE_WEAK_FUNCTION(__sancov_default_options) +INTERFACE_WEAK_FUNCTION(__sanitizer_cov_trace_cmp) +INTERFACE_WEAK_FUNCTION(__sanitizer_cov_trace_cmp1) +INTERFACE_WEAK_FUNCTION(__sanitizer_cov_trace_cmp2) +INTERFACE_WEAK_FUNCTION(__sanitizer_cov_trace_cmp4) +INTERFACE_WEAK_FUNCTION(__sanitizer_cov_trace_cmp8) +INTERFACE_WEAK_FUNCTION(__sanitizer_cov_trace_const_cmp1) +INTERFACE_WEAK_FUNCTION(__sanitizer_cov_trace_const_cmp2) +INTERFACE_WEAK_FUNCTION(__sanitizer_cov_trace_const_cmp4) +INTERFACE_WEAK_FUNCTION(__sanitizer_cov_trace_const_cmp8) +INTERFACE_WEAK_FUNCTION(__sanitizer_cov_trace_div4) +INTERFACE_WEAK_FUNCTION(__sanitizer_cov_trace_div8) +INTERFACE_WEAK_FUNCTION(__sanitizer_cov_trace_gep) +INTERFACE_WEAK_FUNCTION(__sanitizer_cov_trace_pc_guard) +INTERFACE_WEAK_FUNCTION(__sanitizer_cov_trace_pc_guard_init) +INTERFACE_WEAK_FUNCTION(__sanitizer_cov_trace_pc_indir) +INTERFACE_WEAK_FUNCTION(__sanitizer_cov_trace_switch) +INTERFACE_WEAK_FUNCTION(__sanitizer_cov_8bit_counters_init) +INTERFACE_WEAK_FUNCTION(__sanitizer_cov_bool_flag_init) +INTERFACE_WEAK_FUNCTION(__sanitizer_cov_pcs_init) diff --git a/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_coverage_libcdep_new.cpp b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_coverage_libcdep_new.cpp new file mode 100644 index 0000000000..56220df2ac --- /dev/null +++ b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_coverage_libcdep_new.cpp @@ -0,0 +1,276 @@ +//===-- sanitizer_coverage_libcdep_new.cpp --------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// Sanitizer Coverage Controller for Trace PC Guard. + +#include "sanitizer_platform.h" + +#if !SANITIZER_FUCHSIA +#include "sancov_flags.h" +#include "sanitizer_allocator_internal.h" +#include "sanitizer_atomic.h" +#include "sanitizer_common.h" +#include "sanitizer_file.h" + +using namespace __sanitizer; + +using AddressRange = LoadedModule::AddressRange; + +namespace __sancov { +namespace { + +static const u64 Magic64 = 0xC0BFFFFFFFFFFF64ULL; +static const u64 Magic32 = 0xC0BFFFFFFFFFFF32ULL; +static const u64 Magic = SANITIZER_WORDSIZE == 64 ? Magic64 : Magic32; + +static fd_t OpenFile(const char* path) { + error_t err; + fd_t fd = OpenFile(path, WrOnly, &err); + if (fd == kInvalidFd) + Report("SanitizerCoverage: failed to open %s for writing (reason: %d)\n", + path, err); + return fd; +} + +static void GetCoverageFilename(char* path, const char* name, + const char* extension) { + CHECK(name); + internal_snprintf(path, kMaxPathLength, "%s/%s.%zd.%s", + common_flags()->coverage_dir, name, internal_getpid(), + extension); +} + +static void WriteModuleCoverage(char* file_path, const char* module_name, + const uptr* pcs, uptr len) { + GetCoverageFilename(file_path, StripModuleName(module_name), "sancov"); + fd_t fd = OpenFile(file_path); + WriteToFile(fd, &Magic, sizeof(Magic)); + WriteToFile(fd, pcs, len * sizeof(*pcs)); + CloseFile(fd); + Printf("SanitizerCoverage: %s: %zd PCs written\n", file_path, len); +} + +static void SanitizerDumpCoverage(const uptr* unsorted_pcs, uptr len) { + if (!len) return; + + char* file_path = static_cast<char*>(InternalAlloc(kMaxPathLength)); + char* module_name = static_cast<char*>(InternalAlloc(kMaxPathLength)); + uptr* pcs = static_cast<uptr*>(InternalAlloc(len * sizeof(uptr))); + + internal_memcpy(pcs, unsorted_pcs, len * sizeof(uptr)); + Sort(pcs, len); + + bool module_found = false; + uptr last_base = 0; + uptr module_start_idx = 0; + + for (uptr i = 0; i < len; ++i) { + const uptr pc = pcs[i]; + if (!pc) continue; + + if (!__sanitizer_get_module_and_offset_for_pc(pc, nullptr, 0, &pcs[i])) { + Printf("ERROR: unknown pc 0x%zx (may happen if dlclose is used)\n", pc); + continue; + } + uptr module_base = pc - pcs[i]; + + if (module_base != last_base || !module_found) { + if (module_found) { + WriteModuleCoverage(file_path, module_name, &pcs[module_start_idx], + i - module_start_idx); + } + + last_base = module_base; + module_start_idx = i; + module_found = true; + __sanitizer_get_module_and_offset_for_pc(pc, module_name, kMaxPathLength, + &pcs[i]); + } + } + + if (module_found) { + WriteModuleCoverage(file_path, module_name, &pcs[module_start_idx], + len - module_start_idx); + } + + InternalFree(file_path); + InternalFree(module_name); + InternalFree(pcs); +} + +// Collects trace-pc guard coverage. +// This class relies on zero-initialization. +class TracePcGuardController { + public: + void Initialize() { + CHECK(!initialized); + + initialized = true; + InitializeSancovFlags(); + + pc_vector.Initialize(0); + } + + void InitTracePcGuard(u32* start, u32* end) { + if (!initialized) Initialize(); + CHECK(!*start); + CHECK_NE(start, end); + + u32 i = pc_vector.size(); + for (u32* p = start; p < end; p++) *p = ++i; + pc_vector.resize(i); + } + + void TracePcGuard(u32* guard, uptr pc) { + u32 idx = *guard; + if (!idx) return; + // we start indices from 1. + atomic_uintptr_t* pc_ptr = + reinterpret_cast<atomic_uintptr_t*>(&pc_vector[idx - 1]); + if (atomic_load(pc_ptr, memory_order_relaxed) == 0) + atomic_store(pc_ptr, pc, memory_order_relaxed); + } + + void Reset() { + internal_memset(&pc_vector[0], 0, sizeof(pc_vector[0]) * pc_vector.size()); + } + + void Dump() { + if (!initialized || !common_flags()->coverage) return; + __sanitizer_dump_coverage(pc_vector.data(), pc_vector.size()); + } + + private: + bool initialized; + InternalMmapVectorNoCtor<uptr> pc_vector; +}; + +static TracePcGuardController pc_guard_controller; + +// A basic default implementation of callbacks for +// -fsanitize-coverage=inline-8bit-counters,pc-table. +// Use TOOL_OPTIONS (UBSAN_OPTIONS, etc) to dump the coverage data: +// * cov_8bit_counters_out=PATH to dump the 8bit counters. +// * cov_pcs_out=PATH to dump the pc table. +// +// Most users will still need to define their own callbacks for greater +// flexibility. +namespace SingletonCounterCoverage { + +static char *counters_beg, *counters_end; +static const uptr *pcs_beg, *pcs_end; + +static void DumpCoverage() { + const char* file_path = common_flags()->cov_8bit_counters_out; + if (file_path && internal_strlen(file_path)) { + fd_t fd = OpenFile(file_path); + FileCloser file_closer(fd); + uptr size = counters_end - counters_beg; + WriteToFile(fd, counters_beg, size); + if (common_flags()->verbosity) + __sanitizer::Printf("cov_8bit_counters_out: written %zd bytes to %s\n", + size, file_path); + } + file_path = common_flags()->cov_pcs_out; + if (file_path && internal_strlen(file_path)) { + fd_t fd = OpenFile(file_path); + FileCloser file_closer(fd); + uptr size = (pcs_end - pcs_beg) * sizeof(uptr); + WriteToFile(fd, pcs_beg, size); + if (common_flags()->verbosity) + __sanitizer::Printf("cov_pcs_out: written %zd bytes to %s\n", size, + file_path); + } +} + +static void Cov8bitCountersInit(char* beg, char* end) { + counters_beg = beg; + counters_end = end; + Atexit(DumpCoverage); +} + +static void CovPcsInit(const uptr* beg, const uptr* end) { + pcs_beg = beg; + pcs_end = end; +} + +} // namespace SingletonCounterCoverage + +} // namespace +} // namespace __sancov + +namespace __sanitizer { +void InitializeCoverage(bool enabled, const char *dir) { + static bool coverage_enabled = false; + if (coverage_enabled) + return; // May happen if two sanitizer enable coverage in the same process. + coverage_enabled = enabled; + Atexit(__sanitizer_cov_dump); + AddDieCallback(__sanitizer_cov_dump); +} +} // namespace __sanitizer + +extern "C" { +SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_dump_coverage(const uptr* pcs, + uptr len) { + return __sancov::SanitizerDumpCoverage(pcs, len); +} + +SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_pc_guard, u32* guard) { + if (!*guard) return; + __sancov::pc_guard_controller.TracePcGuard(guard, GET_CALLER_PC() - 1); +} + +SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_pc_guard_init, + u32* start, u32* end) { + if (start == end || *start) return; + __sancov::pc_guard_controller.InitTracePcGuard(start, end); +} + +SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_dump_trace_pc_guard_coverage() { + __sancov::pc_guard_controller.Dump(); +} +SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_cov_dump() { + __sanitizer_dump_trace_pc_guard_coverage(); +} +SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_cov_reset() { + __sancov::pc_guard_controller.Reset(); +} +// Default implementations (weak). +// Either empty or very simple. +// Most users should redefine them. +SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_cmp, void) {} +SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_cmp1, void) {} +SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_cmp2, void) {} +SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_cmp4, void) {} +SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_cmp8, void) {} +SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_const_cmp1, void) {} +SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_const_cmp2, void) {} +SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_const_cmp4, void) {} +SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_const_cmp8, void) {} +SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_switch, void) {} +SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_div4, void) {} +SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_div8, void) {} +SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_gep, void) {} +SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_pc_indir, void) {} +SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_8bit_counters_init, + char* start, char* end) { + __sancov::SingletonCounterCoverage::Cov8bitCountersInit(start, end); +} +SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_bool_flag_init, void) {} +SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_pcs_init, const uptr* beg, + const uptr* end) { + __sancov::SingletonCounterCoverage::CovPcsInit(beg, end); +} +} // extern "C" +// Weak definition for code instrumented with -fsanitize-coverage=stack-depth +// and later linked with code containing a strong definition. +// E.g., -fsanitize=fuzzer-no-link +SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE +SANITIZER_TLS_INITIAL_EXEC_ATTRIBUTE uptr __sancov_lowest_stack; + +#endif // !SANITIZER_FUCHSIA diff --git a/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_coverage_win_sections.cpp b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_coverage_win_sections.cpp new file mode 100644 index 0000000000..e7d6563393 --- /dev/null +++ b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_coverage_win_sections.cpp @@ -0,0 +1,67 @@ +//===-- sanitizer_coverage_win_sections.cpp -------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file defines delimiters for Sanitizer Coverage's section. It contains +// Windows specific tricks to coax the linker into giving us the start and stop +// addresses of a section, as ELF linkers can do, to get the size of certain +// arrays. According to https://msdn.microsoft.com/en-us/library/7977wcck.aspx +// sections with the same name before "$" are sorted alphabetically by the +// string that comes after "$" and merged into one section. We take advantage +// of this by putting data we want the size of into the middle (M) of a section, +// by using the letter "M" after "$". We get the start of this data (ie: +// __start_section_name) by making the start variable come at the start of the +// section (using the letter A after "$"). We do the same to get the end of the +// data by using the letter "Z" after "$" to make the end variable come after +// the data. Note that because of our technique the address of the start +// variable is actually the address of data that comes before our middle +// section. We also need to prevent the linker from adding any padding. Each +// technique we use for this is explained in the comments below. +//===----------------------------------------------------------------------===// + +#include "sanitizer_platform.h" +#if SANITIZER_WINDOWS +#include <stdint.h> + +extern "C" { +// Use uint64_t so the linker won't need to add any padding if it tries to word +// align the start of the 8-bit counters array. The array will always start 8 +// bytes after __start_sancov_cntrs. +#pragma section(".SCOV$CA", read, write) +__declspec(allocate(".SCOV$CA")) uint64_t __start___sancov_cntrs = 0; + +// Even though we said not to align __stop__sancov_cntrs (using the "align" +// declspec), MSVC's linker may try to align the section, .SCOV$CZ, containing +// it. This can cause a mismatch between the number of PCs and counters since +// each PCTable element is 8 bytes (unlike counters which are 1 byte) so no +// padding would be added to align .SCOVP$Z, However, if .SCOV$CZ section is 1 +// byte, the linker won't try to align it on an 8-byte boundary, so use a +// uint8_t for __stop_sancov_cntrs. +#pragma section(".SCOV$CZ", read, write) +__declspec(allocate(".SCOV$CZ")) __declspec(align(1)) uint8_t + __stop___sancov_cntrs = 0; + +#pragma section(".SCOV$GA", read, write) +__declspec(allocate(".SCOV$GA")) uint64_t __start___sancov_guards = 0; +#pragma section(".SCOV$GZ", read, write) +__declspec(allocate(".SCOV$GZ")) __declspec(align(1)) uint8_t + __stop___sancov_guards = 0; + +// The guard array and counter array should both be merged into the .data +// section to reduce the number of PE sections. However, because PCTable is +// constant it should be merged with the .rdata section. +#pragma comment(linker, "/MERGE:.SCOV=.data") + +#pragma section(".SCOVP$A", read) +__declspec(allocate(".SCOVP$A")) uint64_t __start___sancov_pcs = 0; +#pragma section(".SCOVP$Z", read) +__declspec(allocate(".SCOVP$Z")) __declspec(align(1)) uint8_t + __stop___sancov_pcs = 0; + +#pragma comment(linker, "/MERGE:.SCOVP=.rdata") +} +#endif // SANITIZER_WINDOWS diff --git a/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_dbghelp.h b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_dbghelp.h new file mode 100644 index 0000000000..00a5399800 --- /dev/null +++ b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_dbghelp.h @@ -0,0 +1,41 @@ +//===-- sanitizer_dbghelp.h ------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// Wrappers for lazy loaded dbghelp.dll. Provides function pointers and a +// callback to initialize them. +// +//===----------------------------------------------------------------------===// + +#ifndef SANITIZER_SYMBOLIZER_WIN_H +#define SANITIZER_SYMBOLIZER_WIN_H + +#if !SANITIZER_WINDOWS +#error "sanitizer_dbghelp.h is a Windows-only header" +#endif + +#define WIN32_LEAN_AND_MEAN +#include <windows.h> +#include <dbghelp.h> + +namespace __sanitizer { + +extern decltype(::StackWalk64) *StackWalk64; +extern decltype(::SymCleanup) *SymCleanup; +extern decltype(::SymFromAddr) *SymFromAddr; +extern decltype(::SymFunctionTableAccess64) *SymFunctionTableAccess64; +extern decltype(::SymGetLineFromAddr64) *SymGetLineFromAddr64; +extern decltype(::SymGetModuleBase64) *SymGetModuleBase64; +extern decltype(::SymGetSearchPathW) *SymGetSearchPathW; +extern decltype(::SymInitialize) *SymInitialize; +extern decltype(::SymSetOptions) *SymSetOptions; +extern decltype(::SymSetSearchPathW) *SymSetSearchPathW; +extern decltype(::UnDecorateSymbolName) *UnDecorateSymbolName; + +} // namespace __sanitizer + +#endif // SANITIZER_SYMBOLIZER_WIN_H diff --git a/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_deadlock_detector.h b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_deadlock_detector.h new file mode 100644 index 0000000000..0749f633b4 --- /dev/null +++ b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_deadlock_detector.h @@ -0,0 +1,410 @@ +//===-- sanitizer_deadlock_detector.h ---------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file is a part of Sanitizer runtime. +// The deadlock detector maintains a directed graph of lock acquisitions. +// When a lock event happens, the detector checks if the locks already held by +// the current thread are reachable from the newly acquired lock. +// +// The detector can handle only a fixed amount of simultaneously live locks +// (a lock is alive if it has been locked at least once and has not been +// destroyed). When the maximal number of locks is reached the entire graph +// is flushed and the new lock epoch is started. The node ids from the old +// epochs can not be used with any of the detector methods except for +// nodeBelongsToCurrentEpoch(). +// +// FIXME: this is work in progress, nothing really works yet. +// +//===----------------------------------------------------------------------===// + +#ifndef SANITIZER_DEADLOCK_DETECTOR_H +#define SANITIZER_DEADLOCK_DETECTOR_H + +#include "sanitizer_bvgraph.h" +#include "sanitizer_common.h" + +namespace __sanitizer { + +// Thread-local state for DeadlockDetector. +// It contains the locks currently held by the owning thread. +template <class BV> +class DeadlockDetectorTLS { + public: + // No CTOR. + void clear() { + bv_.clear(); + epoch_ = 0; + n_recursive_locks = 0; + n_all_locks_ = 0; + } + + bool empty() const { return bv_.empty(); } + + void ensureCurrentEpoch(uptr current_epoch) { + if (epoch_ == current_epoch) return; + bv_.clear(); + epoch_ = current_epoch; + n_recursive_locks = 0; + n_all_locks_ = 0; + } + + uptr getEpoch() const { return epoch_; } + + // Returns true if this is the first (non-recursive) acquisition of this lock. + bool addLock(uptr lock_id, uptr current_epoch, u32 stk) { + CHECK_EQ(epoch_, current_epoch); + if (!bv_.setBit(lock_id)) { + // The lock is already held by this thread, it must be recursive. + CHECK_LT(n_recursive_locks, ARRAY_SIZE(recursive_locks)); + recursive_locks[n_recursive_locks++] = lock_id; + return false; + } + CHECK_LT(n_all_locks_, ARRAY_SIZE(all_locks_with_contexts_)); + // lock_id < BV::kSize, can cast to a smaller int. + u32 lock_id_short = static_cast<u32>(lock_id); + LockWithContext l = {lock_id_short, stk}; + all_locks_with_contexts_[n_all_locks_++] = l; + return true; + } + + void removeLock(uptr lock_id) { + if (n_recursive_locks) { + for (sptr i = n_recursive_locks - 1; i >= 0; i--) { + if (recursive_locks[i] == lock_id) { + n_recursive_locks--; + Swap(recursive_locks[i], recursive_locks[n_recursive_locks]); + return; + } + } + } + if (!bv_.clearBit(lock_id)) + return; // probably addLock happened before flush + if (n_all_locks_) { + for (sptr i = n_all_locks_ - 1; i >= 0; i--) { + if (all_locks_with_contexts_[i].lock == static_cast<u32>(lock_id)) { + Swap(all_locks_with_contexts_[i], + all_locks_with_contexts_[n_all_locks_ - 1]); + n_all_locks_--; + break; + } + } + } + } + + u32 findLockContext(uptr lock_id) { + for (uptr i = 0; i < n_all_locks_; i++) + if (all_locks_with_contexts_[i].lock == static_cast<u32>(lock_id)) + return all_locks_with_contexts_[i].stk; + return 0; + } + + const BV &getLocks(uptr current_epoch) const { + CHECK_EQ(epoch_, current_epoch); + return bv_; + } + + uptr getNumLocks() const { return n_all_locks_; } + uptr getLock(uptr idx) const { return all_locks_with_contexts_[idx].lock; } + + private: + BV bv_; + uptr epoch_; + uptr recursive_locks[64]; + uptr n_recursive_locks; + struct LockWithContext { + u32 lock; + u32 stk; + }; + LockWithContext all_locks_with_contexts_[64]; + uptr n_all_locks_; +}; + +// DeadlockDetector. +// For deadlock detection to work we need one global DeadlockDetector object +// and one DeadlockDetectorTLS object per evey thread. +// This class is not thread safe, all concurrent accesses should be guarded +// by an external lock. +// Most of the methods of this class are not thread-safe (i.e. should +// be protected by an external lock) unless explicitly told otherwise. +template <class BV> +class DeadlockDetector { + public: + typedef BV BitVector; + + uptr size() const { return g_.size(); } + + // No CTOR. + void clear() { + current_epoch_ = 0; + available_nodes_.clear(); + recycled_nodes_.clear(); + g_.clear(); + n_edges_ = 0; + } + + // Allocate new deadlock detector node. + // If we are out of available nodes first try to recycle some. + // If there is nothing to recycle, flush the graph and increment the epoch. + // Associate 'data' (opaque user's object) with the new node. + uptr newNode(uptr data) { + if (!available_nodes_.empty()) + return getAvailableNode(data); + if (!recycled_nodes_.empty()) { + for (sptr i = n_edges_ - 1; i >= 0; i--) { + if (recycled_nodes_.getBit(edges_[i].from) || + recycled_nodes_.getBit(edges_[i].to)) { + Swap(edges_[i], edges_[n_edges_ - 1]); + n_edges_--; + } + } + CHECK(available_nodes_.empty()); + // removeEdgesFrom was called in removeNode. + g_.removeEdgesTo(recycled_nodes_); + available_nodes_.setUnion(recycled_nodes_); + recycled_nodes_.clear(); + return getAvailableNode(data); + } + // We are out of vacant nodes. Flush and increment the current_epoch_. + current_epoch_ += size(); + recycled_nodes_.clear(); + available_nodes_.setAll(); + g_.clear(); + n_edges_ = 0; + return getAvailableNode(data); + } + + // Get data associated with the node created by newNode(). + uptr getData(uptr node) const { return data_[nodeToIndex(node)]; } + + bool nodeBelongsToCurrentEpoch(uptr node) { + return node && (node / size() * size()) == current_epoch_; + } + + void removeNode(uptr node) { + uptr idx = nodeToIndex(node); + CHECK(!available_nodes_.getBit(idx)); + CHECK(recycled_nodes_.setBit(idx)); + g_.removeEdgesFrom(idx); + } + + void ensureCurrentEpoch(DeadlockDetectorTLS<BV> *dtls) { + dtls->ensureCurrentEpoch(current_epoch_); + } + + // Returns true if there is a cycle in the graph after this lock event. + // Ideally should be called before the lock is acquired so that we can + // report a deadlock before a real deadlock happens. + bool onLockBefore(DeadlockDetectorTLS<BV> *dtls, uptr cur_node) { + ensureCurrentEpoch(dtls); + uptr cur_idx = nodeToIndex(cur_node); + return g_.isReachable(cur_idx, dtls->getLocks(current_epoch_)); + } + + u32 findLockContext(DeadlockDetectorTLS<BV> *dtls, uptr node) { + return dtls->findLockContext(nodeToIndex(node)); + } + + // Add cur_node to the set of locks held currently by dtls. + void onLockAfter(DeadlockDetectorTLS<BV> *dtls, uptr cur_node, u32 stk = 0) { + ensureCurrentEpoch(dtls); + uptr cur_idx = nodeToIndex(cur_node); + dtls->addLock(cur_idx, current_epoch_, stk); + } + + // Experimental *racy* fast path function. + // Returns true if all edges from the currently held locks to cur_node exist. + bool hasAllEdges(DeadlockDetectorTLS<BV> *dtls, uptr cur_node) { + uptr local_epoch = dtls->getEpoch(); + // Read from current_epoch_ is racy. + if (cur_node && local_epoch == current_epoch_ && + local_epoch == nodeToEpoch(cur_node)) { + uptr cur_idx = nodeToIndexUnchecked(cur_node); + for (uptr i = 0, n = dtls->getNumLocks(); i < n; i++) { + if (!g_.hasEdge(dtls->getLock(i), cur_idx)) + return false; + } + return true; + } + return false; + } + + // Adds edges from currently held locks to cur_node, + // returns the number of added edges, and puts the sources of added edges + // into added_edges[]. + // Should be called before onLockAfter. + uptr addEdges(DeadlockDetectorTLS<BV> *dtls, uptr cur_node, u32 stk, + int unique_tid) { + ensureCurrentEpoch(dtls); + uptr cur_idx = nodeToIndex(cur_node); + uptr added_edges[40]; + uptr n_added_edges = g_.addEdges(dtls->getLocks(current_epoch_), cur_idx, + added_edges, ARRAY_SIZE(added_edges)); + for (uptr i = 0; i < n_added_edges; i++) { + if (n_edges_ < ARRAY_SIZE(edges_)) { + Edge e = {(u16)added_edges[i], (u16)cur_idx, + dtls->findLockContext(added_edges[i]), stk, + unique_tid}; + edges_[n_edges_++] = e; + } + } + return n_added_edges; + } + + bool findEdge(uptr from_node, uptr to_node, u32 *stk_from, u32 *stk_to, + int *unique_tid) { + uptr from_idx = nodeToIndex(from_node); + uptr to_idx = nodeToIndex(to_node); + for (uptr i = 0; i < n_edges_; i++) { + if (edges_[i].from == from_idx && edges_[i].to == to_idx) { + *stk_from = edges_[i].stk_from; + *stk_to = edges_[i].stk_to; + *unique_tid = edges_[i].unique_tid; + return true; + } + } + return false; + } + + // Test-only function. Handles the before/after lock events, + // returns true if there is a cycle. + bool onLock(DeadlockDetectorTLS<BV> *dtls, uptr cur_node, u32 stk = 0) { + ensureCurrentEpoch(dtls); + bool is_reachable = !isHeld(dtls, cur_node) && onLockBefore(dtls, cur_node); + addEdges(dtls, cur_node, stk, 0); + onLockAfter(dtls, cur_node, stk); + return is_reachable; + } + + // Handles the try_lock event, returns false. + // When a try_lock event happens (i.e. a try_lock call succeeds) we need + // to add this lock to the currently held locks, but we should not try to + // change the lock graph or to detect a cycle. We may want to investigate + // whether a more aggressive strategy is possible for try_lock. + bool onTryLock(DeadlockDetectorTLS<BV> *dtls, uptr cur_node, u32 stk = 0) { + ensureCurrentEpoch(dtls); + uptr cur_idx = nodeToIndex(cur_node); + dtls->addLock(cur_idx, current_epoch_, stk); + return false; + } + + // Returns true iff dtls is empty (no locks are currently held) and we can + // add the node to the currently held locks w/o changing the global state. + // This operation is thread-safe as it only touches the dtls. + bool onFirstLock(DeadlockDetectorTLS<BV> *dtls, uptr node, u32 stk = 0) { + if (!dtls->empty()) return false; + if (dtls->getEpoch() && dtls->getEpoch() == nodeToEpoch(node)) { + dtls->addLock(nodeToIndexUnchecked(node), nodeToEpoch(node), stk); + return true; + } + return false; + } + + // Finds a path between the lock 'cur_node' (currently not held in dtls) + // and some currently held lock, returns the length of the path + // or 0 on failure. + uptr findPathToLock(DeadlockDetectorTLS<BV> *dtls, uptr cur_node, uptr *path, + uptr path_size) { + tmp_bv_.copyFrom(dtls->getLocks(current_epoch_)); + uptr idx = nodeToIndex(cur_node); + CHECK(!tmp_bv_.getBit(idx)); + uptr res = g_.findShortestPath(idx, tmp_bv_, path, path_size); + for (uptr i = 0; i < res; i++) + path[i] = indexToNode(path[i]); + if (res) + CHECK_EQ(path[0], cur_node); + return res; + } + + // Handle the unlock event. + // This operation is thread-safe as it only touches the dtls. + void onUnlock(DeadlockDetectorTLS<BV> *dtls, uptr node) { + if (dtls->getEpoch() == nodeToEpoch(node)) + dtls->removeLock(nodeToIndexUnchecked(node)); + } + + // Tries to handle the lock event w/o writing to global state. + // Returns true on success. + // This operation is thread-safe as it only touches the dtls + // (modulo racy nature of hasAllEdges). + bool onLockFast(DeadlockDetectorTLS<BV> *dtls, uptr node, u32 stk = 0) { + if (hasAllEdges(dtls, node)) { + dtls->addLock(nodeToIndexUnchecked(node), nodeToEpoch(node), stk); + return true; + } + return false; + } + + bool isHeld(DeadlockDetectorTLS<BV> *dtls, uptr node) const { + return dtls->getLocks(current_epoch_).getBit(nodeToIndex(node)); + } + + uptr testOnlyGetEpoch() const { return current_epoch_; } + bool testOnlyHasEdge(uptr l1, uptr l2) { + return g_.hasEdge(nodeToIndex(l1), nodeToIndex(l2)); + } + // idx1 and idx2 are raw indices to g_, not lock IDs. + bool testOnlyHasEdgeRaw(uptr idx1, uptr idx2) { + return g_.hasEdge(idx1, idx2); + } + + void Print() { + for (uptr from = 0; from < size(); from++) + for (uptr to = 0; to < size(); to++) + if (g_.hasEdge(from, to)) + Printf(" %zx => %zx\n", from, to); + } + + private: + void check_idx(uptr idx) const { CHECK_LT(idx, size()); } + + void check_node(uptr node) const { + CHECK_GE(node, size()); + CHECK_EQ(current_epoch_, nodeToEpoch(node)); + } + + uptr indexToNode(uptr idx) const { + check_idx(idx); + return idx + current_epoch_; + } + + uptr nodeToIndexUnchecked(uptr node) const { return node % size(); } + + uptr nodeToIndex(uptr node) const { + check_node(node); + return nodeToIndexUnchecked(node); + } + + uptr nodeToEpoch(uptr node) const { return node / size() * size(); } + + uptr getAvailableNode(uptr data) { + uptr idx = available_nodes_.getAndClearFirstOne(); + data_[idx] = data; + return indexToNode(idx); + } + + struct Edge { + u16 from; + u16 to; + u32 stk_from; + u32 stk_to; + int unique_tid; + }; + + uptr current_epoch_; + BV available_nodes_; + BV recycled_nodes_; + BV tmp_bv_; + BVGraph<BV> g_; + uptr data_[BV::kSize]; + Edge edges_[BV::kSize * 32]; + uptr n_edges_; +}; + +} // namespace __sanitizer + +#endif // SANITIZER_DEADLOCK_DETECTOR_H diff --git a/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_deadlock_detector1.cpp b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_deadlock_detector1.cpp new file mode 100644 index 0000000000..ccb7065b07 --- /dev/null +++ b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_deadlock_detector1.cpp @@ -0,0 +1,194 @@ +//===-- sanitizer_deadlock_detector1.cpp ----------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// Deadlock detector implementation based on NxN adjacency bit matrix. +// +//===----------------------------------------------------------------------===// + +#include "sanitizer_deadlock_detector_interface.h" +#include "sanitizer_deadlock_detector.h" +#include "sanitizer_allocator_internal.h" +#include "sanitizer_placement_new.h" +#include "sanitizer_mutex.h" + +#if SANITIZER_DEADLOCK_DETECTOR_VERSION == 1 + +namespace __sanitizer { + +typedef TwoLevelBitVector<> DDBV; // DeadlockDetector's bit vector. + +struct DDPhysicalThread { +}; + +struct DDLogicalThread { + u64 ctx; + DeadlockDetectorTLS<DDBV> dd; + DDReport rep; + bool report_pending; +}; + +struct DD final : public DDetector { + SpinMutex mtx; + DeadlockDetector<DDBV> dd; + DDFlags flags; + + explicit DD(const DDFlags *flags); + + DDPhysicalThread *CreatePhysicalThread() override; + void DestroyPhysicalThread(DDPhysicalThread *pt) override; + + DDLogicalThread *CreateLogicalThread(u64 ctx) override; + void DestroyLogicalThread(DDLogicalThread *lt) override; + + void MutexInit(DDCallback *cb, DDMutex *m) override; + void MutexBeforeLock(DDCallback *cb, DDMutex *m, bool wlock) override; + void MutexAfterLock(DDCallback *cb, DDMutex *m, bool wlock, + bool trylock) override; + void MutexBeforeUnlock(DDCallback *cb, DDMutex *m, bool wlock) override; + void MutexDestroy(DDCallback *cb, DDMutex *m) override; + + DDReport *GetReport(DDCallback *cb) override; + + void MutexEnsureID(DDLogicalThread *lt, DDMutex *m); + void ReportDeadlock(DDCallback *cb, DDMutex *m); +}; + +DDetector *DDetector::Create(const DDFlags *flags) { + (void)flags; + void *mem = MmapOrDie(sizeof(DD), "deadlock detector"); + return new(mem) DD(flags); +} + +DD::DD(const DDFlags *flags) + : flags(*flags) { + dd.clear(); +} + +DDPhysicalThread* DD::CreatePhysicalThread() { + return nullptr; +} + +void DD::DestroyPhysicalThread(DDPhysicalThread *pt) { +} + +DDLogicalThread* DD::CreateLogicalThread(u64 ctx) { + DDLogicalThread *lt = (DDLogicalThread*)InternalAlloc(sizeof(*lt)); + lt->ctx = ctx; + lt->dd.clear(); + lt->report_pending = false; + return lt; +} + +void DD::DestroyLogicalThread(DDLogicalThread *lt) { + lt->~DDLogicalThread(); + InternalFree(lt); +} + +void DD::MutexInit(DDCallback *cb, DDMutex *m) { + m->id = 0; + m->stk = cb->Unwind(); +} + +void DD::MutexEnsureID(DDLogicalThread *lt, DDMutex *m) { + if (!dd.nodeBelongsToCurrentEpoch(m->id)) + m->id = dd.newNode(reinterpret_cast<uptr>(m)); + dd.ensureCurrentEpoch(<->dd); +} + +void DD::MutexBeforeLock(DDCallback *cb, + DDMutex *m, bool wlock) { + DDLogicalThread *lt = cb->lt; + if (lt->dd.empty()) return; // This will be the first lock held by lt. + if (dd.hasAllEdges(<->dd, m->id)) return; // We already have all edges. + SpinMutexLock lk(&mtx); + MutexEnsureID(lt, m); + if (dd.isHeld(<->dd, m->id)) + return; // FIXME: allow this only for recursive locks. + if (dd.onLockBefore(<->dd, m->id)) { + // Actually add this edge now so that we have all the stack traces. + dd.addEdges(<->dd, m->id, cb->Unwind(), cb->UniqueTid()); + ReportDeadlock(cb, m); + } +} + +void DD::ReportDeadlock(DDCallback *cb, DDMutex *m) { + DDLogicalThread *lt = cb->lt; + uptr path[20]; + uptr len = dd.findPathToLock(<->dd, m->id, path, ARRAY_SIZE(path)); + if (len == 0U) { + // A cycle of 20+ locks? Well, that's a bit odd... + Printf("WARNING: too long mutex cycle found\n"); + return; + } + CHECK_EQ(m->id, path[0]); + lt->report_pending = true; + len = Min<uptr>(len, DDReport::kMaxLoopSize); + DDReport *rep = <->rep; + rep->n = len; + for (uptr i = 0; i < len; i++) { + uptr from = path[i]; + uptr to = path[(i + 1) % len]; + DDMutex *m0 = (DDMutex*)dd.getData(from); + DDMutex *m1 = (DDMutex*)dd.getData(to); + + u32 stk_from = 0, stk_to = 0; + int unique_tid = 0; + dd.findEdge(from, to, &stk_from, &stk_to, &unique_tid); + // Printf("Edge: %zd=>%zd: %u/%u T%d\n", from, to, stk_from, stk_to, + // unique_tid); + rep->loop[i].thr_ctx = unique_tid; + rep->loop[i].mtx_ctx0 = m0->ctx; + rep->loop[i].mtx_ctx1 = m1->ctx; + rep->loop[i].stk[0] = stk_to; + rep->loop[i].stk[1] = stk_from; + } +} + +void DD::MutexAfterLock(DDCallback *cb, DDMutex *m, bool wlock, bool trylock) { + DDLogicalThread *lt = cb->lt; + u32 stk = 0; + if (flags.second_deadlock_stack) + stk = cb->Unwind(); + // Printf("T%p MutexLock: %zx stk %u\n", lt, m->id, stk); + if (dd.onFirstLock(<->dd, m->id, stk)) + return; + if (dd.onLockFast(<->dd, m->id, stk)) + return; + + SpinMutexLock lk(&mtx); + MutexEnsureID(lt, m); + if (wlock) // Only a recursive rlock may be held. + CHECK(!dd.isHeld(<->dd, m->id)); + if (!trylock) + dd.addEdges(<->dd, m->id, stk ? stk : cb->Unwind(), cb->UniqueTid()); + dd.onLockAfter(<->dd, m->id, stk); +} + +void DD::MutexBeforeUnlock(DDCallback *cb, DDMutex *m, bool wlock) { + // Printf("T%p MutexUnLock: %zx\n", cb->lt, m->id); + dd.onUnlock(&cb->lt->dd, m->id); +} + +void DD::MutexDestroy(DDCallback *cb, + DDMutex *m) { + if (!m->id) return; + SpinMutexLock lk(&mtx); + if (dd.nodeBelongsToCurrentEpoch(m->id)) + dd.removeNode(m->id); + m->id = 0; +} + +DDReport *DD::GetReport(DDCallback *cb) { + if (!cb->lt->report_pending) + return nullptr; + cb->lt->report_pending = false; + return &cb->lt->rep; +} + +} // namespace __sanitizer +#endif // #if SANITIZER_DEADLOCK_DETECTOR_VERSION == 1 diff --git a/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_deadlock_detector2.cpp b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_deadlock_detector2.cpp new file mode 100644 index 0000000000..1fbbbcccfa --- /dev/null +++ b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_deadlock_detector2.cpp @@ -0,0 +1,421 @@ +//===-- sanitizer_deadlock_detector2.cpp ----------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// Deadlock detector implementation based on adjacency lists. +// +//===----------------------------------------------------------------------===// + +#include "sanitizer_deadlock_detector_interface.h" +#include "sanitizer_common.h" +#include "sanitizer_allocator_internal.h" +#include "sanitizer_placement_new.h" +#include "sanitizer_mutex.h" + +#if SANITIZER_DEADLOCK_DETECTOR_VERSION == 2 + +namespace __sanitizer { + +const int kMaxNesting = 64; +const u32 kNoId = -1; +const u32 kEndId = -2; +const int kMaxLink = 8; +const int kL1Size = 1024; +const int kL2Size = 1024; +const int kMaxMutex = kL1Size * kL2Size; + +struct Id { + u32 id; + u32 seq; + + explicit Id(u32 id = 0, u32 seq = 0) + : id(id) + , seq(seq) { + } +}; + +struct Link { + u32 id; + u32 seq; + u32 tid; + u32 stk0; + u32 stk1; + + explicit Link(u32 id = 0, u32 seq = 0, u32 tid = 0, u32 s0 = 0, u32 s1 = 0) + : id(id) + , seq(seq) + , tid(tid) + , stk0(s0) + , stk1(s1) { + } +}; + +struct DDPhysicalThread { + DDReport rep; + bool report_pending; + bool visited[kMaxMutex]; + Link pending[kMaxMutex]; + Link path[kMaxMutex]; +}; + +struct ThreadMutex { + u32 id; + u32 stk; +}; + +struct DDLogicalThread { + u64 ctx; + ThreadMutex locked[kMaxNesting]; + int nlocked; +}; + +struct MutexState { + StaticSpinMutex mtx; + u32 seq; + int nlink; + Link link[kMaxLink]; +}; + +struct DD final : public DDetector { + explicit DD(const DDFlags *flags); + + DDPhysicalThread* CreatePhysicalThread(); + void DestroyPhysicalThread(DDPhysicalThread *pt); + + DDLogicalThread* CreateLogicalThread(u64 ctx); + void DestroyLogicalThread(DDLogicalThread *lt); + + void MutexInit(DDCallback *cb, DDMutex *m); + void MutexBeforeLock(DDCallback *cb, DDMutex *m, bool wlock); + void MutexAfterLock(DDCallback *cb, DDMutex *m, bool wlock, + bool trylock); + void MutexBeforeUnlock(DDCallback *cb, DDMutex *m, bool wlock); + void MutexDestroy(DDCallback *cb, DDMutex *m); + + DDReport *GetReport(DDCallback *cb); + + void CycleCheck(DDPhysicalThread *pt, DDLogicalThread *lt, DDMutex *mtx); + void Report(DDPhysicalThread *pt, DDLogicalThread *lt, int npath); + u32 allocateId(DDCallback *cb); + MutexState *getMutex(u32 id); + u32 getMutexId(MutexState *m); + + DDFlags flags; + + MutexState *mutex[kL1Size]; + + SpinMutex mtx; + InternalMmapVector<u32> free_id; + int id_gen = 0; +}; + +DDetector *DDetector::Create(const DDFlags *flags) { + (void)flags; + void *mem = MmapOrDie(sizeof(DD), "deadlock detector"); + return new(mem) DD(flags); +} + +DD::DD(const DDFlags *flags) : flags(*flags) { free_id.reserve(1024); } + +DDPhysicalThread* DD::CreatePhysicalThread() { + DDPhysicalThread *pt = (DDPhysicalThread*)MmapOrDie(sizeof(DDPhysicalThread), + "deadlock detector (physical thread)"); + return pt; +} + +void DD::DestroyPhysicalThread(DDPhysicalThread *pt) { + pt->~DDPhysicalThread(); + UnmapOrDie(pt, sizeof(DDPhysicalThread)); +} + +DDLogicalThread* DD::CreateLogicalThread(u64 ctx) { + DDLogicalThread *lt = (DDLogicalThread*)InternalAlloc( + sizeof(DDLogicalThread)); + lt->ctx = ctx; + lt->nlocked = 0; + return lt; +} + +void DD::DestroyLogicalThread(DDLogicalThread *lt) { + lt->~DDLogicalThread(); + InternalFree(lt); +} + +void DD::MutexInit(DDCallback *cb, DDMutex *m) { + VPrintf(2, "#%llu: DD::MutexInit(%p)\n", cb->lt->ctx, m); + m->id = kNoId; + m->recursion = 0; + atomic_store(&m->owner, 0, memory_order_relaxed); +} + +MutexState *DD::getMutex(u32 id) { return &mutex[id / kL2Size][id % kL2Size]; } + +u32 DD::getMutexId(MutexState *m) { + for (int i = 0; i < kL1Size; i++) { + MutexState *tab = mutex[i]; + if (tab == 0) + break; + if (m >= tab && m < tab + kL2Size) + return i * kL2Size + (m - tab); + } + return -1; +} + +u32 DD::allocateId(DDCallback *cb) { + u32 id = -1; + SpinMutexLock l(&mtx); + if (free_id.size() > 0) { + id = free_id.back(); + free_id.pop_back(); + } else { + CHECK_LT(id_gen, kMaxMutex); + if ((id_gen % kL2Size) == 0) { + mutex[id_gen / kL2Size] = (MutexState *)MmapOrDie( + kL2Size * sizeof(MutexState), "deadlock detector (mutex table)"); + } + id = id_gen++; + } + CHECK_LE(id, kMaxMutex); + VPrintf(3, "#%llu: DD::allocateId assign id %d\n", cb->lt->ctx, id); + return id; +} + +void DD::MutexBeforeLock(DDCallback *cb, DDMutex *m, bool wlock) { + VPrintf(2, "#%llu: DD::MutexBeforeLock(%p, wlock=%d) nlocked=%d\n", + cb->lt->ctx, m, wlock, cb->lt->nlocked); + DDPhysicalThread *pt = cb->pt; + DDLogicalThread *lt = cb->lt; + + uptr owner = atomic_load(&m->owner, memory_order_relaxed); + if (owner == (uptr)cb->lt) { + VPrintf(3, "#%llu: DD::MutexBeforeLock recursive\n", + cb->lt->ctx); + return; + } + + CHECK_LE(lt->nlocked, kMaxNesting); + + // FIXME(dvyukov): don't allocate id if lt->nlocked == 0? + if (m->id == kNoId) + m->id = allocateId(cb); + + ThreadMutex *tm = <->locked[lt->nlocked++]; + tm->id = m->id; + if (flags.second_deadlock_stack) + tm->stk = cb->Unwind(); + if (lt->nlocked == 1) { + VPrintf(3, "#%llu: DD::MutexBeforeLock first mutex\n", + cb->lt->ctx); + return; + } + + bool added = false; + MutexState *mtx = getMutex(m->id); + for (int i = 0; i < lt->nlocked - 1; i++) { + u32 id1 = lt->locked[i].id; + u32 stk1 = lt->locked[i].stk; + MutexState *mtx1 = getMutex(id1); + SpinMutexLock l(&mtx1->mtx); + if (mtx1->nlink == kMaxLink) { + // FIXME(dvyukov): check stale links + continue; + } + int li = 0; + for (; li < mtx1->nlink; li++) { + Link *link = &mtx1->link[li]; + if (link->id == m->id) { + if (link->seq != mtx->seq) { + link->seq = mtx->seq; + link->tid = lt->ctx; + link->stk0 = stk1; + link->stk1 = cb->Unwind(); + added = true; + VPrintf(3, "#%llu: DD::MutexBeforeLock added %d->%d link\n", + cb->lt->ctx, getMutexId(mtx1), m->id); + } + break; + } + } + if (li == mtx1->nlink) { + // FIXME(dvyukov): check stale links + Link *link = &mtx1->link[mtx1->nlink++]; + link->id = m->id; + link->seq = mtx->seq; + link->tid = lt->ctx; + link->stk0 = stk1; + link->stk1 = cb->Unwind(); + added = true; + VPrintf(3, "#%llu: DD::MutexBeforeLock added %d->%d link\n", + cb->lt->ctx, getMutexId(mtx1), m->id); + } + } + + if (!added || mtx->nlink == 0) { + VPrintf(3, "#%llu: DD::MutexBeforeLock don't check\n", + cb->lt->ctx); + return; + } + + CycleCheck(pt, lt, m); +} + +void DD::MutexAfterLock(DDCallback *cb, DDMutex *m, bool wlock, + bool trylock) { + VPrintf(2, "#%llu: DD::MutexAfterLock(%p, wlock=%d, try=%d) nlocked=%d\n", + cb->lt->ctx, m, wlock, trylock, cb->lt->nlocked); + DDLogicalThread *lt = cb->lt; + + uptr owner = atomic_load(&m->owner, memory_order_relaxed); + if (owner == (uptr)cb->lt) { + VPrintf(3, "#%llu: DD::MutexAfterLock recursive\n", cb->lt->ctx); + CHECK(wlock); + m->recursion++; + return; + } + CHECK_EQ(owner, 0); + if (wlock) { + VPrintf(3, "#%llu: DD::MutexAfterLock set owner\n", cb->lt->ctx); + CHECK_EQ(m->recursion, 0); + m->recursion = 1; + atomic_store(&m->owner, (uptr)cb->lt, memory_order_relaxed); + } + + if (!trylock) + return; + + CHECK_LE(lt->nlocked, kMaxNesting); + if (m->id == kNoId) + m->id = allocateId(cb); + ThreadMutex *tm = <->locked[lt->nlocked++]; + tm->id = m->id; + if (flags.second_deadlock_stack) + tm->stk = cb->Unwind(); +} + +void DD::MutexBeforeUnlock(DDCallback *cb, DDMutex *m, bool wlock) { + VPrintf(2, "#%llu: DD::MutexBeforeUnlock(%p, wlock=%d) nlocked=%d\n", + cb->lt->ctx, m, wlock, cb->lt->nlocked); + DDLogicalThread *lt = cb->lt; + + uptr owner = atomic_load(&m->owner, memory_order_relaxed); + if (owner == (uptr)cb->lt) { + VPrintf(3, "#%llu: DD::MutexBeforeUnlock recursive\n", cb->lt->ctx); + if (--m->recursion > 0) + return; + VPrintf(3, "#%llu: DD::MutexBeforeUnlock reset owner\n", cb->lt->ctx); + atomic_store(&m->owner, 0, memory_order_relaxed); + } + CHECK_NE(m->id, kNoId); + int last = lt->nlocked - 1; + for (int i = last; i >= 0; i--) { + if (cb->lt->locked[i].id == m->id) { + lt->locked[i] = lt->locked[last]; + lt->nlocked--; + break; + } + } +} + +void DD::MutexDestroy(DDCallback *cb, DDMutex *m) { + VPrintf(2, "#%llu: DD::MutexDestroy(%p)\n", + cb->lt->ctx, m); + DDLogicalThread *lt = cb->lt; + + if (m->id == kNoId) + return; + + // Remove the mutex from lt->locked if there. + int last = lt->nlocked - 1; + for (int i = last; i >= 0; i--) { + if (lt->locked[i].id == m->id) { + lt->locked[i] = lt->locked[last]; + lt->nlocked--; + break; + } + } + + // Clear and invalidate the mutex descriptor. + { + MutexState *mtx = getMutex(m->id); + SpinMutexLock l(&mtx->mtx); + mtx->seq++; + mtx->nlink = 0; + } + + // Return id to cache. + { + SpinMutexLock l(&mtx); + free_id.push_back(m->id); + } +} + +void DD::CycleCheck(DDPhysicalThread *pt, DDLogicalThread *lt, + DDMutex *m) { + internal_memset(pt->visited, 0, sizeof(pt->visited)); + int npath = 0; + int npending = 0; + { + MutexState *mtx = getMutex(m->id); + SpinMutexLock l(&mtx->mtx); + for (int li = 0; li < mtx->nlink; li++) + pt->pending[npending++] = mtx->link[li]; + } + while (npending > 0) { + Link link = pt->pending[--npending]; + if (link.id == kEndId) { + npath--; + continue; + } + if (pt->visited[link.id]) + continue; + MutexState *mtx1 = getMutex(link.id); + SpinMutexLock l(&mtx1->mtx); + if (mtx1->seq != link.seq) + continue; + pt->visited[link.id] = true; + if (mtx1->nlink == 0) + continue; + pt->path[npath++] = link; + pt->pending[npending++] = Link(kEndId); + if (link.id == m->id) + return Report(pt, lt, npath); // Bingo! + for (int li = 0; li < mtx1->nlink; li++) { + Link *link1 = &mtx1->link[li]; + // MutexState *mtx2 = getMutex(link->id); + // FIXME(dvyukov): fast seq check + // FIXME(dvyukov): fast nlink != 0 check + // FIXME(dvyukov): fast pending check? + // FIXME(dvyukov): npending can be larger than kMaxMutex + pt->pending[npending++] = *link1; + } + } +} + +void DD::Report(DDPhysicalThread *pt, DDLogicalThread *lt, int npath) { + DDReport *rep = &pt->rep; + rep->n = npath; + for (int i = 0; i < npath; i++) { + Link *link = &pt->path[i]; + Link *link0 = &pt->path[i ? i - 1 : npath - 1]; + rep->loop[i].thr_ctx = link->tid; + rep->loop[i].mtx_ctx0 = link0->id; + rep->loop[i].mtx_ctx1 = link->id; + rep->loop[i].stk[0] = flags.second_deadlock_stack ? link->stk0 : 0; + rep->loop[i].stk[1] = link->stk1; + } + pt->report_pending = true; +} + +DDReport *DD::GetReport(DDCallback *cb) { + if (!cb->pt->report_pending) + return 0; + cb->pt->report_pending = false; + return &cb->pt->rep; +} + +} // namespace __sanitizer +#endif // #if SANITIZER_DEADLOCK_DETECTOR_VERSION == 2 diff --git a/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_deadlock_detector_interface.h b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_deadlock_detector_interface.h new file mode 100644 index 0000000000..7f461c98ba --- /dev/null +++ b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_deadlock_detector_interface.h @@ -0,0 +1,98 @@ +//===-- sanitizer_deadlock_detector_interface.h -----------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file is a part of Sanitizer runtime. +// Abstract deadlock detector interface. +// FIXME: this is work in progress, nothing really works yet. +// +//===----------------------------------------------------------------------===// + +#ifndef SANITIZER_DEADLOCK_DETECTOR_INTERFACE_H +#define SANITIZER_DEADLOCK_DETECTOR_INTERFACE_H + +#ifndef SANITIZER_DEADLOCK_DETECTOR_VERSION +# define SANITIZER_DEADLOCK_DETECTOR_VERSION 1 +#endif + +#include "sanitizer_internal_defs.h" +#include "sanitizer_atomic.h" + +namespace __sanitizer { + +// dd - deadlock detector. +// lt - logical (user) thread. +// pt - physical (OS) thread. + +struct DDPhysicalThread; +struct DDLogicalThread; + +struct DDMutex { +#if SANITIZER_DEADLOCK_DETECTOR_VERSION == 1 + uptr id; + u32 stk; // creation stack +#elif SANITIZER_DEADLOCK_DETECTOR_VERSION == 2 + u32 id; + u32 recursion; + atomic_uintptr_t owner; +#else +# error "BAD SANITIZER_DEADLOCK_DETECTOR_VERSION" +#endif + u64 ctx; +}; + +struct DDFlags { + bool second_deadlock_stack; +}; + +struct DDReport { + enum { kMaxLoopSize = 20 }; + int n; // number of entries in loop + struct { + u64 thr_ctx; // user thread context + u64 mtx_ctx0; // user mutex context, start of the edge + u64 mtx_ctx1; // user mutex context, end of the edge + u32 stk[2]; // stack ids for the edge + } loop[kMaxLoopSize]; +}; + +struct DDCallback { + DDPhysicalThread *pt; + DDLogicalThread *lt; + + virtual u32 Unwind() { return 0; } + virtual int UniqueTid() { return 0; } + + protected: + ~DDCallback() {} +}; + +struct DDetector { + static DDetector *Create(const DDFlags *flags); + + virtual DDPhysicalThread* CreatePhysicalThread() { return nullptr; } + virtual void DestroyPhysicalThread(DDPhysicalThread *pt) {} + + virtual DDLogicalThread* CreateLogicalThread(u64 ctx) { return nullptr; } + virtual void DestroyLogicalThread(DDLogicalThread *lt) {} + + virtual void MutexInit(DDCallback *cb, DDMutex *m) {} + virtual void MutexBeforeLock(DDCallback *cb, DDMutex *m, bool wlock) {} + virtual void MutexAfterLock(DDCallback *cb, DDMutex *m, bool wlock, + bool trylock) {} + virtual void MutexBeforeUnlock(DDCallback *cb, DDMutex *m, bool wlock) {} + virtual void MutexDestroy(DDCallback *cb, DDMutex *m) {} + + virtual DDReport *GetReport(DDCallback *cb) { return nullptr; } + + protected: + ~DDetector() {} +}; + +} // namespace __sanitizer + +#endif // SANITIZER_DEADLOCK_DETECTOR_INTERFACE_H diff --git a/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_dense_map.h b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_dense_map.h new file mode 100644 index 0000000000..046d77dddc --- /dev/null +++ b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_dense_map.h @@ -0,0 +1,705 @@ +//===- sanitizer_dense_map.h - Dense probed hash table ----------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This is fork of llvm/ADT/DenseMap.h class with the following changes: +// * Use mmap to allocate. +// * No iterators. +// * Does not shrink. +// +//===----------------------------------------------------------------------===// + +#ifndef SANITIZER_DENSE_MAP_H +#define SANITIZER_DENSE_MAP_H + +#include "sanitizer_common.h" +#include "sanitizer_dense_map_info.h" +#include "sanitizer_internal_defs.h" +#include "sanitizer_type_traits.h" + +namespace __sanitizer { + +template <typename DerivedT, typename KeyT, typename ValueT, typename KeyInfoT, + typename BucketT> +class DenseMapBase { + public: + using size_type = unsigned; + using key_type = KeyT; + using mapped_type = ValueT; + using value_type = BucketT; + + WARN_UNUSED_RESULT bool empty() const { return getNumEntries() == 0; } + unsigned size() const { return getNumEntries(); } + + /// Grow the densemap so that it can contain at least \p NumEntries items + /// before resizing again. + void reserve(size_type NumEntries) { + auto NumBuckets = getMinBucketToReserveForEntries(NumEntries); + if (NumBuckets > getNumBuckets()) + grow(NumBuckets); + } + + void clear() { + if (getNumEntries() == 0 && getNumTombstones() == 0) + return; + + const KeyT EmptyKey = getEmptyKey(), TombstoneKey = getTombstoneKey(); + if (__sanitizer::is_trivially_destructible<ValueT>::value) { + // Use a simpler loop when values don't need destruction. + for (BucketT *P = getBuckets(), *E = getBucketsEnd(); P != E; ++P) + P->getFirst() = EmptyKey; + } else { + unsigned NumEntries = getNumEntries(); + for (BucketT *P = getBuckets(), *E = getBucketsEnd(); P != E; ++P) { + if (!KeyInfoT::isEqual(P->getFirst(), EmptyKey)) { + if (!KeyInfoT::isEqual(P->getFirst(), TombstoneKey)) { + P->getSecond().~ValueT(); + --NumEntries; + } + P->getFirst() = EmptyKey; + } + } + CHECK_EQ(NumEntries, 0); + } + setNumEntries(0); + setNumTombstones(0); + } + + /// Return 1 if the specified key is in the map, 0 otherwise. + size_type count(const KeyT &Key) const { + const BucketT *TheBucket; + return LookupBucketFor(Key, TheBucket) ? 1 : 0; + } + + value_type *find(const KeyT &Key) { + BucketT *TheBucket; + if (LookupBucketFor(Key, TheBucket)) + return TheBucket; + return nullptr; + } + const value_type *find(const KeyT &Key) const { + const BucketT *TheBucket; + if (LookupBucketFor(Key, TheBucket)) + return TheBucket; + return nullptr; + } + + /// Alternate version of find() which allows a different, and possibly + /// less expensive, key type. + /// The DenseMapInfo is responsible for supplying methods + /// getHashValue(LookupKeyT) and isEqual(LookupKeyT, KeyT) for each key + /// type used. + template <class LookupKeyT> + value_type *find_as(const LookupKeyT &Key) { + BucketT *TheBucket; + if (LookupBucketFor(Key, TheBucket)) + return TheBucket; + return nullptr; + } + template <class LookupKeyT> + const value_type *find_as(const LookupKeyT &Key) const { + const BucketT *TheBucket; + if (LookupBucketFor(Key, TheBucket)) + return TheBucket; + return nullptr; + } + + /// lookup - Return the entry for the specified key, or a default + /// constructed value if no such entry exists. + ValueT lookup(const KeyT &Key) const { + const BucketT *TheBucket; + if (LookupBucketFor(Key, TheBucket)) + return TheBucket->getSecond(); + return ValueT(); + } + + // Inserts key,value pair into the map if the key isn't already in the map. + // If the key is already in the map, it returns false and doesn't update the + // value. + detail::DenseMapPair<value_type *, bool> insert(const value_type &KV) { + return try_emplace(KV.first, KV.second); + } + + // Inserts key,value pair into the map if the key isn't already in the map. + // If the key is already in the map, it returns false and doesn't update the + // value. + detail::DenseMapPair<value_type *, bool> insert(value_type &&KV) { + return try_emplace(__sanitizer::move(KV.first), + __sanitizer::move(KV.second)); + } + + // Inserts key,value pair into the map if the key isn't already in the map. + // The value is constructed in-place if the key is not in the map, otherwise + // it is not moved. + template <typename... Ts> + detail::DenseMapPair<value_type *, bool> try_emplace(KeyT &&Key, + Ts &&...Args) { + BucketT *TheBucket; + if (LookupBucketFor(Key, TheBucket)) + return {TheBucket, false}; // Already in map. + + // Otherwise, insert the new element. + TheBucket = InsertIntoBucket(TheBucket, __sanitizer::move(Key), + __sanitizer::forward<Ts>(Args)...); + return {TheBucket, true}; + } + + // Inserts key,value pair into the map if the key isn't already in the map. + // The value is constructed in-place if the key is not in the map, otherwise + // it is not moved. + template <typename... Ts> + detail::DenseMapPair<value_type *, bool> try_emplace(const KeyT &Key, + Ts &&...Args) { + BucketT *TheBucket; + if (LookupBucketFor(Key, TheBucket)) + return {TheBucket, false}; // Already in map. + + // Otherwise, insert the new element. + TheBucket = + InsertIntoBucket(TheBucket, Key, __sanitizer::forward<Ts>(Args)...); + return {TheBucket, true}; + } + + /// Alternate version of insert() which allows a different, and possibly + /// less expensive, key type. + /// The DenseMapInfo is responsible for supplying methods + /// getHashValue(LookupKeyT) and isEqual(LookupKeyT, KeyT) for each key + /// type used. + template <typename LookupKeyT> + detail::DenseMapPair<value_type *, bool> insert_as(value_type &&KV, + const LookupKeyT &Val) { + BucketT *TheBucket; + if (LookupBucketFor(Val, TheBucket)) + return {TheBucket, false}; // Already in map. + + // Otherwise, insert the new element. + TheBucket = + InsertIntoBucketWithLookup(TheBucket, __sanitizer::move(KV.first), + __sanitizer::move(KV.second), Val); + return {TheBucket, true}; + } + + bool erase(const KeyT &Val) { + BucketT *TheBucket; + if (!LookupBucketFor(Val, TheBucket)) + return false; // not in map. + + TheBucket->getSecond().~ValueT(); + TheBucket->getFirst() = getTombstoneKey(); + decrementNumEntries(); + incrementNumTombstones(); + return true; + } + + void erase(value_type *I) { + CHECK_NE(I, nullptr); + BucketT *TheBucket = &*I; + TheBucket->getSecond().~ValueT(); + TheBucket->getFirst() = getTombstoneKey(); + decrementNumEntries(); + incrementNumTombstones(); + } + + value_type &FindAndConstruct(const KeyT &Key) { + BucketT *TheBucket; + if (LookupBucketFor(Key, TheBucket)) + return *TheBucket; + + return *InsertIntoBucket(TheBucket, Key); + } + + ValueT &operator[](const KeyT &Key) { return FindAndConstruct(Key).second; } + + value_type &FindAndConstruct(KeyT &&Key) { + BucketT *TheBucket; + if (LookupBucketFor(Key, TheBucket)) + return *TheBucket; + + return *InsertIntoBucket(TheBucket, __sanitizer::move(Key)); + } + + ValueT &operator[](KeyT &&Key) { + return FindAndConstruct(__sanitizer::move(Key)).second; + } + + /// Iterate over active entries of the container. + /// + /// Function can return fast to stop the process. + template <class Fn> + void forEach(Fn fn) { + const KeyT EmptyKey = getEmptyKey(), TombstoneKey = getTombstoneKey(); + for (auto *P = getBuckets(), *E = getBucketsEnd(); P != E; ++P) { + const KeyT K = P->getFirst(); + if (!KeyInfoT::isEqual(K, EmptyKey) && + !KeyInfoT::isEqual(K, TombstoneKey)) { + if (!fn(*P)) + return; + } + } + } + + template <class Fn> + void forEach(Fn fn) const { + const_cast<DenseMapBase *>(this)->forEach( + [&](const value_type &KV) { return fn(KV); }); + } + + protected: + DenseMapBase() = default; + + void destroyAll() { + if (getNumBuckets() == 0) // Nothing to do. + return; + + const KeyT EmptyKey = getEmptyKey(), TombstoneKey = getTombstoneKey(); + for (BucketT *P = getBuckets(), *E = getBucketsEnd(); P != E; ++P) { + if (!KeyInfoT::isEqual(P->getFirst(), EmptyKey) && + !KeyInfoT::isEqual(P->getFirst(), TombstoneKey)) + P->getSecond().~ValueT(); + P->getFirst().~KeyT(); + } + } + + void initEmpty() { + setNumEntries(0); + setNumTombstones(0); + + CHECK_EQ((getNumBuckets() & (getNumBuckets() - 1)), 0); + const KeyT EmptyKey = getEmptyKey(); + for (BucketT *B = getBuckets(), *E = getBucketsEnd(); B != E; ++B) + ::new (&B->getFirst()) KeyT(EmptyKey); + } + + /// Returns the number of buckets to allocate to ensure that the DenseMap can + /// accommodate \p NumEntries without need to grow(). + unsigned getMinBucketToReserveForEntries(unsigned NumEntries) { + // Ensure that "NumEntries * 4 < NumBuckets * 3" + if (NumEntries == 0) + return 0; + // +1 is required because of the strict equality. + // For example if NumEntries is 48, we need to return 401. + return RoundUpToPowerOfTwo((NumEntries * 4 / 3 + 1) + /* NextPowerOf2 */ 1); + } + + void moveFromOldBuckets(BucketT *OldBucketsBegin, BucketT *OldBucketsEnd) { + initEmpty(); + + // Insert all the old elements. + const KeyT EmptyKey = getEmptyKey(); + const KeyT TombstoneKey = getTombstoneKey(); + for (BucketT *B = OldBucketsBegin, *E = OldBucketsEnd; B != E; ++B) { + if (!KeyInfoT::isEqual(B->getFirst(), EmptyKey) && + !KeyInfoT::isEqual(B->getFirst(), TombstoneKey)) { + // Insert the key/value into the new table. + BucketT *DestBucket; + bool FoundVal = LookupBucketFor(B->getFirst(), DestBucket); + (void)FoundVal; // silence warning. + CHECK(!FoundVal); + DestBucket->getFirst() = __sanitizer::move(B->getFirst()); + ::new (&DestBucket->getSecond()) + ValueT(__sanitizer::move(B->getSecond())); + incrementNumEntries(); + + // Free the value. + B->getSecond().~ValueT(); + } + B->getFirst().~KeyT(); + } + } + + template <typename OtherBaseT> + void copyFrom( + const DenseMapBase<OtherBaseT, KeyT, ValueT, KeyInfoT, BucketT> &other) { + CHECK_NE(&other, this); + CHECK_EQ(getNumBuckets(), other.getNumBuckets()); + + setNumEntries(other.getNumEntries()); + setNumTombstones(other.getNumTombstones()); + + if (__sanitizer::is_trivially_copyable<KeyT>::value && + __sanitizer::is_trivially_copyable<ValueT>::value) + internal_memcpy(reinterpret_cast<void *>(getBuckets()), + other.getBuckets(), getNumBuckets() * sizeof(BucketT)); + else + for (uptr i = 0; i < getNumBuckets(); ++i) { + ::new (&getBuckets()[i].getFirst()) + KeyT(other.getBuckets()[i].getFirst()); + if (!KeyInfoT::isEqual(getBuckets()[i].getFirst(), getEmptyKey()) && + !KeyInfoT::isEqual(getBuckets()[i].getFirst(), getTombstoneKey())) + ::new (&getBuckets()[i].getSecond()) + ValueT(other.getBuckets()[i].getSecond()); + } + } + + static unsigned getHashValue(const KeyT &Val) { + return KeyInfoT::getHashValue(Val); + } + + template <typename LookupKeyT> + static unsigned getHashValue(const LookupKeyT &Val) { + return KeyInfoT::getHashValue(Val); + } + + static const KeyT getEmptyKey() { return KeyInfoT::getEmptyKey(); } + + static const KeyT getTombstoneKey() { return KeyInfoT::getTombstoneKey(); } + + private: + unsigned getNumEntries() const { + return static_cast<const DerivedT *>(this)->getNumEntries(); + } + + void setNumEntries(unsigned Num) { + static_cast<DerivedT *>(this)->setNumEntries(Num); + } + + void incrementNumEntries() { setNumEntries(getNumEntries() + 1); } + + void decrementNumEntries() { setNumEntries(getNumEntries() - 1); } + + unsigned getNumTombstones() const { + return static_cast<const DerivedT *>(this)->getNumTombstones(); + } + + void setNumTombstones(unsigned Num) { + static_cast<DerivedT *>(this)->setNumTombstones(Num); + } + + void incrementNumTombstones() { setNumTombstones(getNumTombstones() + 1); } + + void decrementNumTombstones() { setNumTombstones(getNumTombstones() - 1); } + + const BucketT *getBuckets() const { + return static_cast<const DerivedT *>(this)->getBuckets(); + } + + BucketT *getBuckets() { return static_cast<DerivedT *>(this)->getBuckets(); } + + unsigned getNumBuckets() const { + return static_cast<const DerivedT *>(this)->getNumBuckets(); + } + + BucketT *getBucketsEnd() { return getBuckets() + getNumBuckets(); } + + const BucketT *getBucketsEnd() const { + return getBuckets() + getNumBuckets(); + } + + void grow(unsigned AtLeast) { static_cast<DerivedT *>(this)->grow(AtLeast); } + + template <typename KeyArg, typename... ValueArgs> + BucketT *InsertIntoBucket(BucketT *TheBucket, KeyArg &&Key, + ValueArgs &&...Values) { + TheBucket = InsertIntoBucketImpl(Key, Key, TheBucket); + + TheBucket->getFirst() = __sanitizer::forward<KeyArg>(Key); + ::new (&TheBucket->getSecond()) + ValueT(__sanitizer::forward<ValueArgs>(Values)...); + return TheBucket; + } + + template <typename LookupKeyT> + BucketT *InsertIntoBucketWithLookup(BucketT *TheBucket, KeyT &&Key, + ValueT &&Value, LookupKeyT &Lookup) { + TheBucket = InsertIntoBucketImpl(Key, Lookup, TheBucket); + + TheBucket->getFirst() = __sanitizer::move(Key); + ::new (&TheBucket->getSecond()) ValueT(__sanitizer::move(Value)); + return TheBucket; + } + + template <typename LookupKeyT> + BucketT *InsertIntoBucketImpl(const KeyT &Key, const LookupKeyT &Lookup, + BucketT *TheBucket) { + // If the load of the hash table is more than 3/4, or if fewer than 1/8 of + // the buckets are empty (meaning that many are filled with tombstones), + // grow the table. + // + // The later case is tricky. For example, if we had one empty bucket with + // tons of tombstones, failing lookups (e.g. for insertion) would have to + // probe almost the entire table until it found the empty bucket. If the + // table completely filled with tombstones, no lookup would ever succeed, + // causing infinite loops in lookup. + unsigned NewNumEntries = getNumEntries() + 1; + unsigned NumBuckets = getNumBuckets(); + if (UNLIKELY(NewNumEntries * 4 >= NumBuckets * 3)) { + this->grow(NumBuckets * 2); + LookupBucketFor(Lookup, TheBucket); + NumBuckets = getNumBuckets(); + } else if (UNLIKELY(NumBuckets - (NewNumEntries + getNumTombstones()) <= + NumBuckets / 8)) { + this->grow(NumBuckets); + LookupBucketFor(Lookup, TheBucket); + } + CHECK(TheBucket); + + // Only update the state after we've grown our bucket space appropriately + // so that when growing buckets we have self-consistent entry count. + incrementNumEntries(); + + // If we are writing over a tombstone, remember this. + const KeyT EmptyKey = getEmptyKey(); + if (!KeyInfoT::isEqual(TheBucket->getFirst(), EmptyKey)) + decrementNumTombstones(); + + return TheBucket; + } + + /// LookupBucketFor - Lookup the appropriate bucket for Val, returning it in + /// FoundBucket. If the bucket contains the key and a value, this returns + /// true, otherwise it returns a bucket with an empty marker or tombstone and + /// returns false. + template <typename LookupKeyT> + bool LookupBucketFor(const LookupKeyT &Val, + const BucketT *&FoundBucket) const { + const BucketT *BucketsPtr = getBuckets(); + const unsigned NumBuckets = getNumBuckets(); + + if (NumBuckets == 0) { + FoundBucket = nullptr; + return false; + } + + // FoundTombstone - Keep track of whether we find a tombstone while probing. + const BucketT *FoundTombstone = nullptr; + const KeyT EmptyKey = getEmptyKey(); + const KeyT TombstoneKey = getTombstoneKey(); + CHECK(!KeyInfoT::isEqual(Val, EmptyKey)); + CHECK(!KeyInfoT::isEqual(Val, TombstoneKey)); + + unsigned BucketNo = getHashValue(Val) & (NumBuckets - 1); + unsigned ProbeAmt = 1; + while (true) { + const BucketT *ThisBucket = BucketsPtr + BucketNo; + // Found Val's bucket? If so, return it. + if (LIKELY(KeyInfoT::isEqual(Val, ThisBucket->getFirst()))) { + FoundBucket = ThisBucket; + return true; + } + + // If we found an empty bucket, the key doesn't exist in the set. + // Insert it and return the default value. + if (LIKELY(KeyInfoT::isEqual(ThisBucket->getFirst(), EmptyKey))) { + // If we've already seen a tombstone while probing, fill it in instead + // of the empty bucket we eventually probed to. + FoundBucket = FoundTombstone ? FoundTombstone : ThisBucket; + return false; + } + + // If this is a tombstone, remember it. If Val ends up not in the map, we + // prefer to return it than something that would require more probing. + if (KeyInfoT::isEqual(ThisBucket->getFirst(), TombstoneKey) && + !FoundTombstone) + FoundTombstone = ThisBucket; // Remember the first tombstone found. + + // Otherwise, it's a hash collision or a tombstone, continue quadratic + // probing. + BucketNo += ProbeAmt++; + BucketNo &= (NumBuckets - 1); + } + } + + template <typename LookupKeyT> + bool LookupBucketFor(const LookupKeyT &Val, BucketT *&FoundBucket) { + const BucketT *ConstFoundBucket; + bool Result = const_cast<const DenseMapBase *>(this)->LookupBucketFor( + Val, ConstFoundBucket); + FoundBucket = const_cast<BucketT *>(ConstFoundBucket); + return Result; + } + + public: + /// Return the approximate size (in bytes) of the actual map. + /// This is just the raw memory used by DenseMap. + /// If entries are pointers to objects, the size of the referenced objects + /// are not included. + uptr getMemorySize() const { + return RoundUpTo(getNumBuckets() * sizeof(BucketT), GetPageSizeCached()); + } +}; + +/// Equality comparison for DenseMap. +/// +/// Iterates over elements of LHS confirming that each (key, value) pair in LHS +/// is also in RHS, and that no additional pairs are in RHS. +/// Equivalent to N calls to RHS.find and N value comparisons. Amortized +/// complexity is linear, worst case is O(N^2) (if every hash collides). +template <typename DerivedT, typename KeyT, typename ValueT, typename KeyInfoT, + typename BucketT> +bool operator==( + const DenseMapBase<DerivedT, KeyT, ValueT, KeyInfoT, BucketT> &LHS, + const DenseMapBase<DerivedT, KeyT, ValueT, KeyInfoT, BucketT> &RHS) { + if (LHS.size() != RHS.size()) + return false; + + bool R = true; + LHS.forEach( + [&](const typename DenseMapBase<DerivedT, KeyT, ValueT, KeyInfoT, + BucketT>::value_type &KV) -> bool { + const auto *I = RHS.find(KV.first); + if (!I || I->second != KV.second) { + R = false; + return false; + } + return true; + }); + + return R; +} + +/// Inequality comparison for DenseMap. +/// +/// Equivalent to !(LHS == RHS). See operator== for performance notes. +template <typename DerivedT, typename KeyT, typename ValueT, typename KeyInfoT, + typename BucketT> +bool operator!=( + const DenseMapBase<DerivedT, KeyT, ValueT, KeyInfoT, BucketT> &LHS, + const DenseMapBase<DerivedT, KeyT, ValueT, KeyInfoT, BucketT> &RHS) { + return !(LHS == RHS); +} + +template <typename KeyT, typename ValueT, + typename KeyInfoT = DenseMapInfo<KeyT>, + typename BucketT = detail::DenseMapPair<KeyT, ValueT>> +class DenseMap : public DenseMapBase<DenseMap<KeyT, ValueT, KeyInfoT, BucketT>, + KeyT, ValueT, KeyInfoT, BucketT> { + friend class DenseMapBase<DenseMap, KeyT, ValueT, KeyInfoT, BucketT>; + + // Lift some types from the dependent base class into this class for + // simplicity of referring to them. + using BaseT = DenseMapBase<DenseMap, KeyT, ValueT, KeyInfoT, BucketT>; + + BucketT *Buckets = nullptr; + unsigned NumEntries = 0; + unsigned NumTombstones = 0; + unsigned NumBuckets = 0; + + public: + /// Create a DenseMap with an optional \p InitialReserve that guarantee that + /// this number of elements can be inserted in the map without grow() + explicit DenseMap(unsigned InitialReserve) { init(InitialReserve); } + constexpr DenseMap() = default; + + DenseMap(const DenseMap &other) : BaseT() { + init(0); + copyFrom(other); + } + + DenseMap(DenseMap &&other) : BaseT() { + init(0); + swap(other); + } + + ~DenseMap() { + this->destroyAll(); + deallocate_buffer(Buckets, sizeof(BucketT) * NumBuckets); + } + + void swap(DenseMap &RHS) { + Swap(Buckets, RHS.Buckets); + Swap(NumEntries, RHS.NumEntries); + Swap(NumTombstones, RHS.NumTombstones); + Swap(NumBuckets, RHS.NumBuckets); + } + + DenseMap &operator=(const DenseMap &other) { + if (&other != this) + copyFrom(other); + return *this; + } + + DenseMap &operator=(DenseMap &&other) { + this->destroyAll(); + deallocate_buffer(Buckets, sizeof(BucketT) * NumBuckets, alignof(BucketT)); + init(0); + swap(other); + return *this; + } + + void copyFrom(const DenseMap &other) { + this->destroyAll(); + deallocate_buffer(Buckets, sizeof(BucketT) * NumBuckets); + if (allocateBuckets(other.NumBuckets)) { + this->BaseT::copyFrom(other); + } else { + NumEntries = 0; + NumTombstones = 0; + } + } + + void init(unsigned InitNumEntries) { + auto InitBuckets = BaseT::getMinBucketToReserveForEntries(InitNumEntries); + if (allocateBuckets(InitBuckets)) { + this->BaseT::initEmpty(); + } else { + NumEntries = 0; + NumTombstones = 0; + } + } + + void grow(unsigned AtLeast) { + unsigned OldNumBuckets = NumBuckets; + BucketT *OldBuckets = Buckets; + + allocateBuckets(RoundUpToPowerOfTwo(Max<unsigned>(64, AtLeast))); + CHECK(Buckets); + if (!OldBuckets) { + this->BaseT::initEmpty(); + return; + } + + this->moveFromOldBuckets(OldBuckets, OldBuckets + OldNumBuckets); + + // Free the old table. + deallocate_buffer(OldBuckets, sizeof(BucketT) * OldNumBuckets); + } + + private: + unsigned getNumEntries() const { return NumEntries; } + + void setNumEntries(unsigned Num) { NumEntries = Num; } + + unsigned getNumTombstones() const { return NumTombstones; } + + void setNumTombstones(unsigned Num) { NumTombstones = Num; } + + BucketT *getBuckets() const { return Buckets; } + + unsigned getNumBuckets() const { return NumBuckets; } + + bool allocateBuckets(unsigned Num) { + NumBuckets = Num; + if (NumBuckets == 0) { + Buckets = nullptr; + return false; + } + + uptr Size = sizeof(BucketT) * NumBuckets; + if (Size * 2 <= GetPageSizeCached()) { + // We always allocate at least a page, so use entire space. + unsigned Log2 = MostSignificantSetBitIndex(GetPageSizeCached() / Size); + Size <<= Log2; + NumBuckets <<= Log2; + CHECK_EQ(Size, sizeof(BucketT) * NumBuckets); + CHECK_GT(Size * 2, GetPageSizeCached()); + } + Buckets = static_cast<BucketT *>(allocate_buffer(Size)); + return true; + } + + static void *allocate_buffer(uptr Size) { + return MmapOrDie(RoundUpTo(Size, GetPageSizeCached()), "DenseMap"); + } + + static void deallocate_buffer(void *Ptr, uptr Size) { + UnmapOrDie(Ptr, RoundUpTo(Size, GetPageSizeCached())); + } +}; + +} // namespace __sanitizer + +#endif // SANITIZER_DENSE_MAP_H diff --git a/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_dense_map_info.h b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_dense_map_info.h new file mode 100644 index 0000000000..f4640369ae --- /dev/null +++ b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_dense_map_info.h @@ -0,0 +1,282 @@ +//===- sanitizer_dense_map_info.h - Type traits for DenseMap ----*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef SANITIZER_DENSE_MAP_INFO_H +#define SANITIZER_DENSE_MAP_INFO_H + +#include "sanitizer_common.h" +#include "sanitizer_internal_defs.h" +#include "sanitizer_type_traits.h" + +namespace __sanitizer { + +namespace detail { + +/// Simplistic combination of 32-bit hash values into 32-bit hash values. +static constexpr unsigned combineHashValue(unsigned a, unsigned b) { + u64 key = (u64)a << 32 | (u64)b; + key += ~(key << 32); + key ^= (key >> 22); + key += ~(key << 13); + key ^= (key >> 8); + key += (key << 3); + key ^= (key >> 15); + key += ~(key << 27); + key ^= (key >> 31); + return (unsigned)key; +} + +// We extend a pair to allow users to override the bucket type with their own +// implementation without requiring two members. +template <typename KeyT, typename ValueT> +struct DenseMapPair { + KeyT first = {}; + ValueT second = {}; + constexpr DenseMapPair() = default; + constexpr DenseMapPair(const KeyT &f, const ValueT &s) + : first(f), second(s) {} + + template <typename KeyT2, typename ValueT2> + constexpr DenseMapPair(KeyT2 &&f, ValueT2 &&s) + : first(__sanitizer::forward<KeyT2>(f)), + second(__sanitizer::forward<ValueT2>(s)) {} + + constexpr DenseMapPair(const DenseMapPair &other) = default; + constexpr DenseMapPair &operator=(const DenseMapPair &other) = default; + constexpr DenseMapPair(DenseMapPair &&other) = default; + constexpr DenseMapPair &operator=(DenseMapPair &&other) = default; + + KeyT &getFirst() { return first; } + const KeyT &getFirst() const { return first; } + ValueT &getSecond() { return second; } + const ValueT &getSecond() const { return second; } +}; + +} // end namespace detail + +template <typename T> +struct DenseMapInfo { + // static T getEmptyKey(); + // static T getTombstoneKey(); + // static unsigned getHashValue(const T &Val); + // static bool isEqual(const T &LHS, const T &RHS); +}; + +// Provide DenseMapInfo for all pointers. Come up with sentinel pointer values +// that are aligned to alignof(T) bytes, but try to avoid requiring T to be +// complete. This allows clients to instantiate DenseMap<T*, ...> with forward +// declared key types. Assume that no pointer key type requires more than 4096 +// bytes of alignment. +template <typename T> +struct DenseMapInfo<T *> { + // The following should hold, but it would require T to be complete: + // static_assert(alignof(T) <= (1 << Log2MaxAlign), + // "DenseMap does not support pointer keys requiring more than " + // "Log2MaxAlign bits of alignment"); + static constexpr uptr Log2MaxAlign = 12; + + static constexpr T *getEmptyKey() { + uptr Val = static_cast<uptr>(-1); + Val <<= Log2MaxAlign; + return reinterpret_cast<T *>(Val); + } + + static constexpr T *getTombstoneKey() { + uptr Val = static_cast<uptr>(-2); + Val <<= Log2MaxAlign; + return reinterpret_cast<T *>(Val); + } + + static constexpr unsigned getHashValue(const T *PtrVal) { + return (unsigned((uptr)PtrVal) >> 4) ^ (unsigned((uptr)PtrVal) >> 9); + } + + static constexpr bool isEqual(const T *LHS, const T *RHS) { + return LHS == RHS; + } +}; + +// Provide DenseMapInfo for chars. +template <> +struct DenseMapInfo<char> { + static constexpr char getEmptyKey() { return ~0; } + static constexpr char getTombstoneKey() { return ~0 - 1; } + static constexpr unsigned getHashValue(const char &Val) { return Val * 37U; } + + static constexpr bool isEqual(const char &LHS, const char &RHS) { + return LHS == RHS; + } +}; + +// Provide DenseMapInfo for unsigned chars. +template <> +struct DenseMapInfo<unsigned char> { + static constexpr unsigned char getEmptyKey() { return ~0; } + static constexpr unsigned char getTombstoneKey() { return ~0 - 1; } + static constexpr unsigned getHashValue(const unsigned char &Val) { + return Val * 37U; + } + + static constexpr bool isEqual(const unsigned char &LHS, + const unsigned char &RHS) { + return LHS == RHS; + } +}; + +// Provide DenseMapInfo for unsigned shorts. +template <> +struct DenseMapInfo<unsigned short> { + static constexpr unsigned short getEmptyKey() { return 0xFFFF; } + static constexpr unsigned short getTombstoneKey() { return 0xFFFF - 1; } + static constexpr unsigned getHashValue(const unsigned short &Val) { + return Val * 37U; + } + + static constexpr bool isEqual(const unsigned short &LHS, + const unsigned short &RHS) { + return LHS == RHS; + } +}; + +// Provide DenseMapInfo for unsigned ints. +template <> +struct DenseMapInfo<unsigned> { + static constexpr unsigned getEmptyKey() { return ~0U; } + static constexpr unsigned getTombstoneKey() { return ~0U - 1; } + static constexpr unsigned getHashValue(const unsigned &Val) { + return Val * 37U; + } + + static constexpr bool isEqual(const unsigned &LHS, const unsigned &RHS) { + return LHS == RHS; + } +}; + +// Provide DenseMapInfo for unsigned longs. +template <> +struct DenseMapInfo<unsigned long> { + static constexpr unsigned long getEmptyKey() { return ~0UL; } + static constexpr unsigned long getTombstoneKey() { return ~0UL - 1L; } + + static constexpr unsigned getHashValue(const unsigned long &Val) { + return (unsigned)(Val * 37UL); + } + + static constexpr bool isEqual(const unsigned long &LHS, + const unsigned long &RHS) { + return LHS == RHS; + } +}; + +// Provide DenseMapInfo for unsigned long longs. +template <> +struct DenseMapInfo<unsigned long long> { + static constexpr unsigned long long getEmptyKey() { return ~0ULL; } + static constexpr unsigned long long getTombstoneKey() { return ~0ULL - 1ULL; } + + static constexpr unsigned getHashValue(const unsigned long long &Val) { + return (unsigned)(Val * 37ULL); + } + + static constexpr bool isEqual(const unsigned long long &LHS, + const unsigned long long &RHS) { + return LHS == RHS; + } +}; + +// Provide DenseMapInfo for shorts. +template <> +struct DenseMapInfo<short> { + static constexpr short getEmptyKey() { return 0x7FFF; } + static constexpr short getTombstoneKey() { return -0x7FFF - 1; } + static constexpr unsigned getHashValue(const short &Val) { return Val * 37U; } + static constexpr bool isEqual(const short &LHS, const short &RHS) { + return LHS == RHS; + } +}; + +// Provide DenseMapInfo for ints. +template <> +struct DenseMapInfo<int> { + static constexpr int getEmptyKey() { return 0x7fffffff; } + static constexpr int getTombstoneKey() { return -0x7fffffff - 1; } + static constexpr unsigned getHashValue(const int &Val) { + return (unsigned)(Val * 37U); + } + + static constexpr bool isEqual(const int &LHS, const int &RHS) { + return LHS == RHS; + } +}; + +// Provide DenseMapInfo for longs. +template <> +struct DenseMapInfo<long> { + static constexpr long getEmptyKey() { + return (1UL << (sizeof(long) * 8 - 1)) - 1UL; + } + + static constexpr long getTombstoneKey() { return getEmptyKey() - 1L; } + + static constexpr unsigned getHashValue(const long &Val) { + return (unsigned)(Val * 37UL); + } + + static constexpr bool isEqual(const long &LHS, const long &RHS) { + return LHS == RHS; + } +}; + +// Provide DenseMapInfo for long longs. +template <> +struct DenseMapInfo<long long> { + static constexpr long long getEmptyKey() { return 0x7fffffffffffffffLL; } + static constexpr long long getTombstoneKey() { + return -0x7fffffffffffffffLL - 1; + } + + static constexpr unsigned getHashValue(const long long &Val) { + return (unsigned)(Val * 37ULL); + } + + static constexpr bool isEqual(const long long &LHS, const long long &RHS) { + return LHS == RHS; + } +}; + +// Provide DenseMapInfo for all pairs whose members have info. +template <typename T, typename U> +struct DenseMapInfo<detail::DenseMapPair<T, U>> { + using Pair = detail::DenseMapPair<T, U>; + using FirstInfo = DenseMapInfo<T>; + using SecondInfo = DenseMapInfo<U>; + + static constexpr Pair getEmptyKey() { + return detail::DenseMapPair<T, U>(FirstInfo::getEmptyKey(), + SecondInfo::getEmptyKey()); + } + + static constexpr Pair getTombstoneKey() { + return detail::DenseMapPair<T, U>(FirstInfo::getTombstoneKey(), + SecondInfo::getTombstoneKey()); + } + + static constexpr unsigned getHashValue(const Pair &PairVal) { + return detail::combineHashValue(FirstInfo::getHashValue(PairVal.first), + SecondInfo::getHashValue(PairVal.second)); + } + + static constexpr bool isEqual(const Pair &LHS, const Pair &RHS) { + return FirstInfo::isEqual(LHS.first, RHS.first) && + SecondInfo::isEqual(LHS.second, RHS.second); + } +}; + +} // namespace __sanitizer + +#endif // SANITIZER_DENSE_MAP_INFO_H diff --git a/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_errno.cpp b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_errno.cpp new file mode 100644 index 0000000000..cbadf4d924 --- /dev/null +++ b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_errno.cpp @@ -0,0 +1,34 @@ +//===-- sanitizer_errno.cpp -------------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file is shared between sanitizers run-time libraries. +// +// Defines errno to avoid including errno.h and its dependencies into other +// files (e.g. interceptors are not supposed to include any system headers). +// +//===----------------------------------------------------------------------===// + +#include "sanitizer_errno_codes.h" +#include "sanitizer_internal_defs.h" + +#include <errno.h> + +namespace __sanitizer { + +COMPILER_CHECK(errno_ENOMEM == ENOMEM); +COMPILER_CHECK(errno_EBUSY == EBUSY); +COMPILER_CHECK(errno_EINVAL == EINVAL); + +// EOWNERDEAD is not present in some older platforms. +#if defined(EOWNERDEAD) +extern const int errno_EOWNERDEAD = EOWNERDEAD; +#else +extern const int errno_EOWNERDEAD = -1; +#endif + +} // namespace __sanitizer diff --git a/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_errno.h b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_errno.h new file mode 100644 index 0000000000..70a6e88dba --- /dev/null +++ b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_errno.h @@ -0,0 +1,38 @@ +//===-- sanitizer_errno.h ---------------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file is shared between sanitizers run-time libraries. +// +// Defines errno to avoid including errno.h and its dependencies into sensitive +// files (e.g. interceptors are not supposed to include any system headers). +// It's ok to use errno.h directly when your file already depend on other system +// includes though. +// +//===----------------------------------------------------------------------===// + +#ifndef SANITIZER_ERRNO_H +#define SANITIZER_ERRNO_H + +#include "sanitizer_errno_codes.h" +#include "sanitizer_platform.h" + +#if SANITIZER_FREEBSD || SANITIZER_MAC +# define __errno_location __error +#elif SANITIZER_ANDROID || SANITIZER_NETBSD +# define __errno_location __errno +#elif SANITIZER_SOLARIS +# define __errno_location ___errno +#elif SANITIZER_WINDOWS +# define __errno_location _errno +#endif + +extern "C" int *__errno_location(); + +#define errno (*__errno_location()) + +#endif // SANITIZER_ERRNO_H diff --git a/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_errno_codes.h b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_errno_codes.h new file mode 100644 index 0000000000..192e9392d4 --- /dev/null +++ b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_errno_codes.h @@ -0,0 +1,34 @@ +//===-- sanitizer_errno_codes.h ---------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file is shared between sanitizers run-time libraries. +// +// Defines errno codes to avoid including errno.h and its dependencies into +// sensitive files (e.g. interceptors are not supposed to include any system +// headers). +// It's ok to use errno.h directly when your file already depend on other system +// includes though. +// +//===----------------------------------------------------------------------===// + +#ifndef SANITIZER_ERRNO_CODES_H +#define SANITIZER_ERRNO_CODES_H + +namespace __sanitizer { + +#define errno_ENOMEM 12 +#define errno_EBUSY 16 +#define errno_EINVAL 22 +#define errno_ENAMETOOLONG 36 + +// Those might not present or their value differ on different platforms. +extern const int errno_EOWNERDEAD; + +} // namespace __sanitizer + +#endif // SANITIZER_ERRNO_CODES_H diff --git a/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_file.cpp b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_file.cpp new file mode 100644 index 0000000000..5492560df9 --- /dev/null +++ b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_file.cpp @@ -0,0 +1,246 @@ +//===-- sanitizer_file.cpp -----------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===---------------------------------------------------------------------===// +// +// This file is shared between AddressSanitizer and ThreadSanitizer +// run-time libraries. It defines filesystem-related interfaces. This +// is separate from sanitizer_common.cpp so that it's simpler to disable +// all the filesystem support code for a port that doesn't use it. +// +//===---------------------------------------------------------------------===// + +#include "sanitizer_platform.h" + +#if !SANITIZER_FUCHSIA + +#include "sanitizer_common.h" +#include "sanitizer_file.h" + +namespace __sanitizer { + +void CatastrophicErrorWrite(const char *buffer, uptr length) { + WriteToFile(kStderrFd, buffer, length); +} + +StaticSpinMutex report_file_mu; +ReportFile report_file = {&report_file_mu, kStderrFd, "", "", 0}; + +void RawWrite(const char *buffer) { + report_file.Write(buffer, internal_strlen(buffer)); +} + +void ReportFile::ReopenIfNecessary() { + mu->CheckLocked(); + if (fd == kStdoutFd || fd == kStderrFd) return; + + uptr pid = internal_getpid(); + // If in tracer, use the parent's file. + if (pid == stoptheworld_tracer_pid) + pid = stoptheworld_tracer_ppid; + if (fd != kInvalidFd) { + // If the report file is already opened by the current process, + // do nothing. Otherwise the report file was opened by the parent + // process, close it now. + if (fd_pid == pid) + return; + else + CloseFile(fd); + } + + const char *exe_name = GetProcessName(); + if (common_flags()->log_exe_name && exe_name) { + internal_snprintf(full_path, kMaxPathLength, "%s.%s.%zu", path_prefix, + exe_name, pid); + } else { + internal_snprintf(full_path, kMaxPathLength, "%s.%zu", path_prefix, pid); + } + if (common_flags()->log_suffix) { + internal_strlcat(full_path, common_flags()->log_suffix, kMaxPathLength); + } + error_t err; + fd = OpenFile(full_path, WrOnly, &err); + if (fd == kInvalidFd) { + const char *ErrorMsgPrefix = "ERROR: Can't open file: "; + WriteToFile(kStderrFd, ErrorMsgPrefix, internal_strlen(ErrorMsgPrefix)); + WriteToFile(kStderrFd, full_path, internal_strlen(full_path)); + char errmsg[100]; + internal_snprintf(errmsg, sizeof(errmsg), " (reason: %d)", err); + WriteToFile(kStderrFd, errmsg, internal_strlen(errmsg)); + Die(); + } + fd_pid = pid; +} + +static void RecursiveCreateParentDirs(char *path) { + if (path[0] == '\0') + return; + for (int i = 1; path[i] != '\0'; ++i) { + char save = path[i]; + if (!IsPathSeparator(path[i])) + continue; + path[i] = '\0'; + /* Some of these will fail, because the directory exists, ignore it. */ + CreateDir(path); + path[i] = save; + } +} + +void ReportFile::SetReportPath(const char *path) { + if (path) { + uptr len = internal_strlen(path); + if (len > sizeof(path_prefix) - 100) { + Report("ERROR: Path is too long: %c%c%c%c%c%c%c%c...\n", path[0], path[1], + path[2], path[3], path[4], path[5], path[6], path[7]); + Die(); + } + } + + SpinMutexLock l(mu); + if (fd != kStdoutFd && fd != kStderrFd && fd != kInvalidFd) + CloseFile(fd); + fd = kInvalidFd; + if (!path || internal_strcmp(path, "stderr") == 0) { + fd = kStderrFd; + } else if (internal_strcmp(path, "stdout") == 0) { + fd = kStdoutFd; + } else { + internal_snprintf(path_prefix, kMaxPathLength, "%s", path); + RecursiveCreateParentDirs(path_prefix); + } +} + +const char *ReportFile::GetReportPath() { + SpinMutexLock l(mu); + ReopenIfNecessary(); + return full_path; +} + +bool ReadFileToBuffer(const char *file_name, char **buff, uptr *buff_size, + uptr *read_len, uptr max_len, error_t *errno_p) { + *buff = nullptr; + *buff_size = 0; + *read_len = 0; + if (!max_len) + return true; + uptr PageSize = GetPageSizeCached(); + uptr kMinFileLen = Min(PageSize, max_len); + + // The files we usually open are not seekable, so try different buffer sizes. + for (uptr size = kMinFileLen;; size = Min(size * 2, max_len)) { + UnmapOrDie(*buff, *buff_size); + *buff = (char*)MmapOrDie(size, __func__); + *buff_size = size; + fd_t fd = OpenFile(file_name, RdOnly, errno_p); + if (fd == kInvalidFd) { + UnmapOrDie(*buff, *buff_size); + return false; + } + *read_len = 0; + // Read up to one page at a time. + bool reached_eof = false; + while (*read_len < size) { + uptr just_read; + if (!ReadFromFile(fd, *buff + *read_len, size - *read_len, &just_read, + errno_p)) { + UnmapOrDie(*buff, *buff_size); + CloseFile(fd); + return false; + } + *read_len += just_read; + if (just_read == 0 || *read_len == max_len) { + reached_eof = true; + break; + } + } + CloseFile(fd); + if (reached_eof) // We've read the whole file. + break; + } + return true; +} + +bool ReadFileToVector(const char *file_name, + InternalMmapVectorNoCtor<char> *buff, uptr max_len, + error_t *errno_p) { + buff->clear(); + if (!max_len) + return true; + uptr PageSize = GetPageSizeCached(); + fd_t fd = OpenFile(file_name, RdOnly, errno_p); + if (fd == kInvalidFd) + return false; + uptr read_len = 0; + while (read_len < max_len) { + if (read_len >= buff->size()) + buff->resize(Min(Max(PageSize, read_len * 2), max_len)); + CHECK_LT(read_len, buff->size()); + CHECK_LE(buff->size(), max_len); + uptr just_read; + if (!ReadFromFile(fd, buff->data() + read_len, buff->size() - read_len, + &just_read, errno_p)) { + CloseFile(fd); + return false; + } + read_len += just_read; + if (!just_read) + break; + } + CloseFile(fd); + buff->resize(read_len); + return true; +} + +static const char kPathSeparator = SANITIZER_WINDOWS ? ';' : ':'; + +char *FindPathToBinary(const char *name) { + if (FileExists(name)) { + return internal_strdup(name); + } + + const char *path = GetEnv("PATH"); + if (!path) + return nullptr; + uptr name_len = internal_strlen(name); + InternalMmapVector<char> buffer(kMaxPathLength); + const char *beg = path; + while (true) { + const char *end = internal_strchrnul(beg, kPathSeparator); + uptr prefix_len = end - beg; + if (prefix_len + name_len + 2 <= kMaxPathLength) { + internal_memcpy(buffer.data(), beg, prefix_len); + buffer[prefix_len] = '/'; + internal_memcpy(&buffer[prefix_len + 1], name, name_len); + buffer[prefix_len + 1 + name_len] = '\0'; + if (FileExists(buffer.data())) + return internal_strdup(buffer.data()); + } + if (*end == '\0') break; + beg = end + 1; + } + return nullptr; +} + +} // namespace __sanitizer + +using namespace __sanitizer; + +extern "C" { +void __sanitizer_set_report_path(const char *path) { + report_file.SetReportPath(path); +} + +void __sanitizer_set_report_fd(void *fd) { + report_file.fd = (fd_t)reinterpret_cast<uptr>(fd); + report_file.fd_pid = internal_getpid(); +} + +const char *__sanitizer_get_report_path() { + return report_file.GetReportPath(); +} +} // extern "C" + +#endif // !SANITIZER_FUCHSIA diff --git a/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_file.h b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_file.h new file mode 100644 index 0000000000..3d7916171c --- /dev/null +++ b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_file.h @@ -0,0 +1,109 @@ +//===-- sanitizer_file.h ---------------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===---------------------------------------------------------------------===// +// +// This file is shared between run-time libraries of sanitizers. +// It declares filesystem-related interfaces. This is separate from +// sanitizer_common.h so that it's simpler to disable all the filesystem +// support code for a port that doesn't use it. +// +//===---------------------------------------------------------------------===// +#ifndef SANITIZER_FILE_H +#define SANITIZER_FILE_H + +#include "sanitizer_interface_internal.h" +#include "sanitizer_internal_defs.h" +#include "sanitizer_libc.h" +#include "sanitizer_mutex.h" + +namespace __sanitizer { + +struct ReportFile { + void Write(const char *buffer, uptr length); + bool SupportsColors(); + void SetReportPath(const char *path); + const char *GetReportPath(); + + // 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; + +enum FileAccessMode { + RdOnly, + WrOnly, + RdWr +}; + +// Returns kInvalidFd on error. +fd_t OpenFile(const char *filename, FileAccessMode mode, + error_t *errno_p = nullptr); +void CloseFile(fd_t); + +// Return true on success, false on error. +bool ReadFromFile(fd_t fd, void *buff, uptr buff_size, + uptr *bytes_read = nullptr, error_t *error_p = nullptr); +bool WriteToFile(fd_t fd, const void *buff, uptr buff_size, + uptr *bytes_written = nullptr, error_t *error_p = nullptr); + +// Scoped file handle closer. +struct FileCloser { + explicit FileCloser(fd_t fd) : fd(fd) {} + ~FileCloser() { CloseFile(fd); } + fd_t fd; +}; + +bool SupportsColoredOutput(fd_t fd); + +// OS +const char *GetPwd(); +bool FileExists(const char *filename); +char *FindPathToBinary(const char *name); +bool IsPathSeparator(const char c); +bool IsAbsolutePath(const char *path); +// Returns true on success, false on failure. +bool CreateDir(const char *pathname); +// Starts a subprocess and returs its pid. +// If *_fd parameters are not kInvalidFd their corresponding input/output +// streams will be redirect to the file. The files will always be closed +// in parent process even in case of an error. +// The child process will close all fds after STDERR_FILENO +// before passing control to a program. +pid_t StartSubprocess(const char *filename, const char *const argv[], + const char *const envp[], fd_t stdin_fd = kInvalidFd, + fd_t stdout_fd = kInvalidFd, fd_t stderr_fd = kInvalidFd); +// Checks if specified process is still running +bool IsProcessRunning(pid_t pid); +// Waits for the process to finish and returns its exit code. +// Returns -1 in case of an error. +int WaitForProcess(pid_t pid); + +// Maps given file to virtual memory, and returns pointer to it +// (or NULL if mapping fails). Stores the size of mmaped region +// in '*buff_size'. +void *MapFileToMemory(const char *file_name, uptr *buff_size); +void *MapWritableFileToMemory(void *addr, uptr size, fd_t fd, OFF_T offset); + +} // namespace __sanitizer + +#endif // SANITIZER_FILE_H diff --git a/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_flag_parser.cpp b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_flag_parser.cpp new file mode 100644 index 0000000000..9e274268bf --- /dev/null +++ b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_flag_parser.cpp @@ -0,0 +1,191 @@ +//===-- sanitizer_flag_parser.cpp -----------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file is a part of ThreadSanitizer/AddressSanitizer runtime. +// +//===----------------------------------------------------------------------===// + +#include "sanitizer_flag_parser.h" + +#include "sanitizer_common.h" +#include "sanitizer_libc.h" +#include "sanitizer_flags.h" +#include "sanitizer_flag_parser.h" + +namespace __sanitizer { + +LowLevelAllocator FlagParser::Alloc; + +class UnknownFlags { + static const int kMaxUnknownFlags = 20; + const char *unknown_flags_[kMaxUnknownFlags]; + int n_unknown_flags_; + + public: + void Add(const char *name) { + CHECK_LT(n_unknown_flags_, kMaxUnknownFlags); + unknown_flags_[n_unknown_flags_++] = name; + } + + void Report() { + if (!n_unknown_flags_) return; + Printf("WARNING: found %d unrecognized flag(s):\n", n_unknown_flags_); + for (int i = 0; i < n_unknown_flags_; ++i) + Printf(" %s\n", unknown_flags_[i]); + n_unknown_flags_ = 0; + } +}; + +UnknownFlags unknown_flags; + +void ReportUnrecognizedFlags() { + unknown_flags.Report(); +} + +char *FlagParser::ll_strndup(const char *s, uptr n) { + uptr len = internal_strnlen(s, n); + char *s2 = (char*)Alloc.Allocate(len + 1); + internal_memcpy(s2, s, len); + s2[len] = 0; + return s2; +} + +void FlagParser::PrintFlagDescriptions() { + char buffer[128]; + buffer[sizeof(buffer) - 1] = '\0'; + Printf("Available flags for %s:\n", SanitizerToolName); + for (int i = 0; i < n_flags_; ++i) { + bool truncated = !(flags_[i].handler->Format(buffer, sizeof(buffer))); + CHECK_EQ(buffer[sizeof(buffer) - 1], '\0'); + const char *truncation_str = truncated ? " Truncated" : ""; + Printf("\t%s\n\t\t- %s (Current Value%s: %s)\n", flags_[i].name, + flags_[i].desc, truncation_str, buffer); + } +} + +void FlagParser::fatal_error(const char *err) { + Printf("%s: ERROR: %s\n", SanitizerToolName, err); + Die(); +} + +bool FlagParser::is_space(char c) { + return c == ' ' || c == ',' || c == ':' || c == '\n' || c == '\t' || + c == '\r'; +} + +void FlagParser::skip_whitespace() { + while (is_space(buf_[pos_])) ++pos_; +} + +void FlagParser::parse_flag(const char *env_option_name) { + uptr name_start = pos_; + while (buf_[pos_] != 0 && buf_[pos_] != '=' && !is_space(buf_[pos_])) ++pos_; + if (buf_[pos_] != '=') { + if (env_option_name) { + Printf("%s: ERROR: expected '=' in %s\n", SanitizerToolName, + env_option_name); + Die(); + } else { + fatal_error("expected '='"); + } + } + char *name = ll_strndup(buf_ + name_start, pos_ - name_start); + + uptr value_start = ++pos_; + char *value; + if (buf_[pos_] == '\'' || buf_[pos_] == '"') { + char quote = buf_[pos_++]; + while (buf_[pos_] != 0 && buf_[pos_] != quote) ++pos_; + if (buf_[pos_] == 0) fatal_error("unterminated string"); + value = ll_strndup(buf_ + value_start + 1, pos_ - value_start - 1); + ++pos_; // consume the closing quote + } else { + while (buf_[pos_] != 0 && !is_space(buf_[pos_])) ++pos_; + if (buf_[pos_] != 0 && !is_space(buf_[pos_])) + fatal_error("expected separator or eol"); + value = ll_strndup(buf_ + value_start, pos_ - value_start); + } + + bool res = run_handler(name, value); + if (!res) fatal_error("Flag parsing failed."); +} + +void FlagParser::parse_flags(const char *env_option_name) { + while (true) { + skip_whitespace(); + if (buf_[pos_] == 0) break; + parse_flag(env_option_name); + } + + // Do a sanity check for certain flags. + if (common_flags_dont_use.malloc_context_size < 1) + common_flags_dont_use.malloc_context_size = 1; +} + +void FlagParser::ParseStringFromEnv(const char *env_name) { + const char *env = GetEnv(env_name); + VPrintf(1, "%s: %s\n", env_name, env ? env : "<empty>"); + ParseString(env, env_name); +} + +void FlagParser::ParseString(const char *s, const char *env_option_name) { + if (!s) return; + // Backup current parser state to allow nested ParseString() calls. + const char *old_buf_ = buf_; + uptr old_pos_ = pos_; + buf_ = s; + pos_ = 0; + + parse_flags(env_option_name); + + buf_ = old_buf_; + pos_ = old_pos_; +} + +bool FlagParser::ParseFile(const char *path, bool ignore_missing) { + static const uptr kMaxIncludeSize = 1 << 15; + char *data; + uptr data_mapped_size; + error_t err; + uptr len; + if (!ReadFileToBuffer(path, &data, &data_mapped_size, &len, + Max(kMaxIncludeSize, GetPageSizeCached()), &err)) { + if (ignore_missing) + return true; + Printf("Failed to read options from '%s': error %d\n", path, err); + return false; + } + ParseString(data, path); + UnmapOrDie(data, data_mapped_size); + return true; +} + +bool FlagParser::run_handler(const char *name, const char *value) { + for (int i = 0; i < n_flags_; ++i) { + if (internal_strcmp(name, flags_[i].name) == 0) + return flags_[i].handler->Parse(value); + } + // Unrecognized flag. This is not a fatal error, we may print a warning later. + unknown_flags.Add(name); + return true; +} + +void FlagParser::RegisterHandler(const char *name, FlagHandlerBase *handler, + const char *desc) { + CHECK_LT(n_flags_, kMaxFlags); + flags_[n_flags_].name = name; + flags_[n_flags_].desc = desc; + flags_[n_flags_].handler = handler; + ++n_flags_; +} + +FlagParser::FlagParser() : n_flags_(0), buf_(nullptr), pos_(0) { + flags_ = (Flag *)Alloc.Allocate(sizeof(Flag) * kMaxFlags); +} + +} // namespace __sanitizer diff --git a/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_flag_parser.h b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_flag_parser.h new file mode 100644 index 0000000000..3ccc6a6fa5 --- /dev/null +++ b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_flag_parser.h @@ -0,0 +1,204 @@ +//===-- sanitizer_flag_parser.h ---------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file is a part of ThreadSanitizer/AddressSanitizer runtime. +// +//===----------------------------------------------------------------------===// + +#ifndef SANITIZER_FLAG_REGISTRY_H +#define SANITIZER_FLAG_REGISTRY_H + +#include "sanitizer_internal_defs.h" +#include "sanitizer_libc.h" +#include "sanitizer_common.h" + +namespace __sanitizer { + +class FlagHandlerBase { + public: + virtual bool Parse(const char *value) { return false; } + // Write the C string representation of the current value (truncated to fit) + // into the buffer of size `size`. Returns false if truncation occurred and + // returns true otherwise. + virtual bool Format(char *buffer, uptr size) { + if (size > 0) + buffer[0] = '\0'; + return false; + } + + protected: + ~FlagHandlerBase() {} + + inline bool FormatString(char *buffer, uptr size, const char *str_to_use) { + uptr num_symbols_should_write = + internal_snprintf(buffer, size, "%s", str_to_use); + return num_symbols_should_write < size; + } +}; + +template <typename T> +class FlagHandler final : public FlagHandlerBase { + T *t_; + + public: + explicit FlagHandler(T *t) : t_(t) {} + bool Parse(const char *value) final; + bool Format(char *buffer, uptr size) final; +}; + +inline bool ParseBool(const char *value, bool *b) { + if (internal_strcmp(value, "0") == 0 || + internal_strcmp(value, "no") == 0 || + internal_strcmp(value, "false") == 0) { + *b = false; + return true; + } + if (internal_strcmp(value, "1") == 0 || + internal_strcmp(value, "yes") == 0 || + internal_strcmp(value, "true") == 0) { + *b = true; + return true; + } + return false; +} + +template <> +inline bool FlagHandler<bool>::Parse(const char *value) { + if (ParseBool(value, t_)) return true; + Printf("ERROR: Invalid value for bool option: '%s'\n", value); + return false; +} + +template <> +inline bool FlagHandler<bool>::Format(char *buffer, uptr size) { + return FormatString(buffer, size, *t_ ? "true" : "false"); +} + +template <> +inline bool FlagHandler<HandleSignalMode>::Parse(const char *value) { + bool b; + if (ParseBool(value, &b)) { + *t_ = b ? kHandleSignalYes : kHandleSignalNo; + return true; + } + if (internal_strcmp(value, "2") == 0 || + internal_strcmp(value, "exclusive") == 0) { + *t_ = kHandleSignalExclusive; + return true; + } + Printf("ERROR: Invalid value for signal handler option: '%s'\n", value); + return false; +} + +template <> +inline bool FlagHandler<HandleSignalMode>::Format(char *buffer, uptr size) { + uptr num_symbols_should_write = internal_snprintf(buffer, size, "%d", *t_); + return num_symbols_should_write < size; +} + +template <> +inline bool FlagHandler<const char *>::Parse(const char *value) { + *t_ = value; + return true; +} + +template <> +inline bool FlagHandler<const char *>::Format(char *buffer, uptr size) { + return FormatString(buffer, size, *t_); +} + +template <> +inline bool FlagHandler<int>::Parse(const char *value) { + const char *value_end; + *t_ = internal_simple_strtoll(value, &value_end, 10); + bool ok = *value_end == 0; + if (!ok) Printf("ERROR: Invalid value for int option: '%s'\n", value); + return ok; +} + +template <> +inline bool FlagHandler<int>::Format(char *buffer, uptr size) { + uptr num_symbols_should_write = internal_snprintf(buffer, size, "%d", *t_); + return num_symbols_should_write < size; +} + +template <> +inline bool FlagHandler<uptr>::Parse(const char *value) { + const char *value_end; + *t_ = internal_simple_strtoll(value, &value_end, 10); + bool ok = *value_end == 0; + if (!ok) Printf("ERROR: Invalid value for uptr option: '%s'\n", value); + return ok; +} + +template <> +inline bool FlagHandler<uptr>::Format(char *buffer, uptr size) { + uptr num_symbols_should_write = internal_snprintf(buffer, size, "0x%zx", *t_); + return num_symbols_should_write < size; +} + +template <> +inline bool FlagHandler<s64>::Parse(const char *value) { + const char *value_end; + *t_ = internal_simple_strtoll(value, &value_end, 10); + bool ok = *value_end == 0; + if (!ok) Printf("ERROR: Invalid value for s64 option: '%s'\n", value); + return ok; +} + +template <> +inline bool FlagHandler<s64>::Format(char *buffer, uptr size) { + uptr num_symbols_should_write = internal_snprintf(buffer, size, "%lld", *t_); + return num_symbols_should_write < size; +} + +class FlagParser { + static const int kMaxFlags = 200; + struct Flag { + const char *name; + const char *desc; + FlagHandlerBase *handler; + } *flags_; + int n_flags_; + + const char *buf_; + uptr pos_; + + public: + FlagParser(); + void RegisterHandler(const char *name, FlagHandlerBase *handler, + const char *desc); + void ParseString(const char *s, const char *env_name = 0); + void ParseStringFromEnv(const char *env_name); + bool ParseFile(const char *path, bool ignore_missing); + void PrintFlagDescriptions(); + + static LowLevelAllocator Alloc; + + private: + void fatal_error(const char *err); + bool is_space(char c); + void skip_whitespace(); + void parse_flags(const char *env_option_name); + void parse_flag(const char *env_option_name); + bool run_handler(const char *name, const char *value); + char *ll_strndup(const char *s, uptr n); +}; + +template <typename T> +static void RegisterFlag(FlagParser *parser, const char *name, const char *desc, + T *var) { + FlagHandler<T> *fh = new (FlagParser::Alloc) FlagHandler<T>(var); + parser->RegisterHandler(name, fh, desc); +} + +void ReportUnrecognizedFlags(); + +} // namespace __sanitizer + +#endif // SANITIZER_FLAG_REGISTRY_H diff --git a/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_flags.cpp b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_flags.cpp new file mode 100644 index 0000000000..d52e96a7c3 --- /dev/null +++ b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_flags.cpp @@ -0,0 +1,139 @@ +//===-- sanitizer_flags.cpp -----------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file is a part of ThreadSanitizer/AddressSanitizer runtime. +// +//===----------------------------------------------------------------------===// + +#include "sanitizer_flags.h" + +#include "sanitizer_common.h" +#include "sanitizer_flag_parser.h" +#include "sanitizer_libc.h" +#include "sanitizer_linux.h" +#include "sanitizer_list.h" + +namespace __sanitizer { + +CommonFlags common_flags_dont_use; + +void CommonFlags::SetDefaults() { +#define COMMON_FLAG(Type, Name, DefaultValue, Description) Name = DefaultValue; +#include "sanitizer_flags.inc" +#undef COMMON_FLAG +} + +void CommonFlags::CopyFrom(const CommonFlags &other) { + internal_memcpy(this, &other, sizeof(*this)); +} + +// Copy the string from "s" to "out", making the following substitutions: +// %b = binary basename +// %p = pid +// %d = binary directory +void SubstituteForFlagValue(const char *s, char *out, uptr out_size) { + char *out_end = out + out_size; + while (*s && out < out_end - 1) { + if (s[0] != '%') { + *out++ = *s++; + continue; + } + switch (s[1]) { + case 'b': { + const char *base = GetProcessName(); + CHECK(base); + while (*base && out < out_end - 1) + *out++ = *base++; + s += 2; // skip "%b" + break; + } + case 'p': { + int pid = internal_getpid(); + char buf[32]; + char *buf_pos = buf + 32; + do { + *--buf_pos = (pid % 10) + '0'; + pid /= 10; + } while (pid); + while (buf_pos < buf + 32 && out < out_end - 1) + *out++ = *buf_pos++; + s += 2; // skip "%p" + break; + } + case 'd': { + uptr len = ReadBinaryDir(out, out_end - out); + out += len; + s += 2; // skip "%d" + break; + } + default: + *out++ = *s++; + break; + } + } + CHECK(out < out_end - 1); + *out = '\0'; +} + +class FlagHandlerInclude final : public FlagHandlerBase { + FlagParser *parser_; + bool ignore_missing_; + const char *original_path_; + + public: + explicit FlagHandlerInclude(FlagParser *parser, bool ignore_missing) + : parser_(parser), ignore_missing_(ignore_missing), original_path_("") {} + bool Parse(const char *value) final { + original_path_ = value; + if (internal_strchr(value, '%')) { + char *buf = (char *)MmapOrDie(kMaxPathLength, "FlagHandlerInclude"); + SubstituteForFlagValue(value, buf, kMaxPathLength); + bool res = parser_->ParseFile(buf, ignore_missing_); + UnmapOrDie(buf, kMaxPathLength); + return res; + } + return parser_->ParseFile(value, ignore_missing_); + } + bool Format(char *buffer, uptr size) override { + // Note `original_path_` isn't actually what's parsed due to `%` + // substitutions. Printing the substituted path would require holding onto + // mmap'ed memory. + return FormatString(buffer, size, original_path_); + } +}; + +void RegisterIncludeFlags(FlagParser *parser, CommonFlags *cf) { + FlagHandlerInclude *fh_include = new (FlagParser::Alloc) + FlagHandlerInclude(parser, /*ignore_missing*/ false); + parser->RegisterHandler("include", fh_include, + "read more options from the given file"); + FlagHandlerInclude *fh_include_if_exists = new (FlagParser::Alloc) + FlagHandlerInclude(parser, /*ignore_missing*/ true); + parser->RegisterHandler( + "include_if_exists", fh_include_if_exists, + "read more options from the given file (if it exists)"); +} + +void RegisterCommonFlags(FlagParser *parser, CommonFlags *cf) { +#define COMMON_FLAG(Type, Name, DefaultValue, Description) \ + RegisterFlag(parser, #Name, Description, &cf->Name); +#include "sanitizer_flags.inc" +#undef COMMON_FLAG + + RegisterIncludeFlags(parser, cf); +} + +void InitializeCommonFlags(CommonFlags *cf) { + // need to record coverage to generate coverage report. + cf->coverage |= cf->html_cov_report; + SetVerbosity(cf->verbosity); + + InitializePlatformCommonFlags(cf); +} + +} // namespace __sanitizer diff --git a/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_flags.h b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_flags.h new file mode 100644 index 0000000000..5b59e5801b --- /dev/null +++ b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_flags.h @@ -0,0 +1,71 @@ +//===-- sanitizer_flags.h ---------------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file is a part of ThreadSanitizer/AddressSanitizer runtime. +// +//===----------------------------------------------------------------------===// + +#ifndef SANITIZER_FLAGS_H +#define SANITIZER_FLAGS_H + +#include "sanitizer_internal_defs.h" + +namespace __sanitizer { + +enum HandleSignalMode { + kHandleSignalNo, + kHandleSignalYes, + kHandleSignalExclusive, +}; + +struct CommonFlags { +#define COMMON_FLAG(Type, Name, DefaultValue, Description) Type Name; +#include "sanitizer_flags.inc" +#undef COMMON_FLAG + + void SetDefaults(); + void CopyFrom(const CommonFlags &other); +}; + +// Functions to get/set global CommonFlags shared by all sanitizer runtimes: +extern CommonFlags common_flags_dont_use; +inline const CommonFlags *common_flags() { + return &common_flags_dont_use; +} + +inline void SetCommonFlagsDefaults() { + common_flags_dont_use.SetDefaults(); +} + +// This function can only be used to setup tool-specific overrides for +// CommonFlags defaults. Generally, it should only be used right after +// SetCommonFlagsDefaults(), but before ParseCommonFlagsFromString(), and +// only during the flags initialization (i.e. before they are used for +// the first time). +inline void OverrideCommonFlags(const CommonFlags &cf) { + common_flags_dont_use.CopyFrom(cf); +} + +void SubstituteForFlagValue(const char *s, char *out, uptr out_size); + +class FlagParser; +void RegisterCommonFlags(FlagParser *parser, + CommonFlags *cf = &common_flags_dont_use); +void RegisterIncludeFlags(FlagParser *parser, CommonFlags *cf); + +// Should be called after parsing all flags. Sets up common flag values +// and perform initializations common to all sanitizers (e.g. setting +// verbosity). +void InitializeCommonFlags(CommonFlags *cf = &common_flags_dont_use); + +// Platform specific flags initialization. +void InitializePlatformCommonFlags(CommonFlags *cf); + +} // namespace __sanitizer + +#endif // SANITIZER_FLAGS_H diff --git a/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_flags.inc b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_flags.inc new file mode 100644 index 0000000000..0ca91aff8d --- /dev/null +++ b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_flags.inc @@ -0,0 +1,268 @@ +//===-- sanitizer_flags.h ---------------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file describes common flags available in all sanitizers. +// +//===----------------------------------------------------------------------===// + +#ifndef COMMON_FLAG +#error "Define COMMON_FLAG prior to including this file!" +#endif + +// COMMON_FLAG(Type, Name, DefaultValue, Description) +// Supported types: bool, const char *, int, uptr. +// Default value must be a compile-time constant. +// Description must be a string literal. + +COMMON_FLAG( + bool, symbolize, true, + "If set, use the online symbolizer from common sanitizer runtime to turn " + "virtual addresses to file/line locations.") +COMMON_FLAG( + const char *, external_symbolizer_path, nullptr, + "Path to external symbolizer. If empty, the tool will search $PATH for " + "the symbolizer.") +COMMON_FLAG( + bool, allow_addr2line, false, + "If set, allows online symbolizer to run addr2line binary to symbolize " + "stack traces (addr2line will only be used if llvm-symbolizer binary is " + "unavailable.") +COMMON_FLAG(const char *, strip_path_prefix, "", + "Strips this prefix from file paths in error reports.") +COMMON_FLAG(bool, fast_unwind_on_check, false, + "If available, use the fast frame-pointer-based unwinder on " + "internal CHECK failures.") +COMMON_FLAG(bool, fast_unwind_on_fatal, false, + "If available, use the fast frame-pointer-based unwinder on fatal " + "errors.") +// ARM thumb/thumb2 frame pointer is inconsistent on GCC and Clang [1] +// and fast-unwider is also unreliable with mixing arm and thumb code [2]. +// [1] https://gcc.gnu.org/bugzilla/show_bug.cgi?id=92172 +// [2] https://bugs.llvm.org/show_bug.cgi?id=44158 +COMMON_FLAG(bool, fast_unwind_on_malloc, + !(SANITIZER_LINUX && !SANITIZER_ANDROID && SANITIZER_ARM), + "If available, use the fast frame-pointer-based unwinder on " + "malloc/free.") +COMMON_FLAG(bool, handle_ioctl, false, "Intercept and handle ioctl requests.") +COMMON_FLAG(int, malloc_context_size, 1, + "Max number of stack frames kept for each allocation/deallocation.") +COMMON_FLAG( + const char *, log_path, nullptr, + "Write logs to \"log_path.pid\". The special values are \"stdout\" and " + "\"stderr\". If unspecified, defaults to \"stderr\".") +COMMON_FLAG( + bool, log_exe_name, false, + "Mention name of executable when reporting error and " + "append executable name to logs (as in \"log_path.exe_name.pid\").") +COMMON_FLAG(const char *, log_suffix, nullptr, + "String to append to log file name, e.g. \".txt\".") +COMMON_FLAG( + bool, log_to_syslog, (bool)SANITIZER_ANDROID || (bool)SANITIZER_MAC, + "Write all sanitizer output to syslog in addition to other means of " + "logging.") +COMMON_FLAG( + int, verbosity, 0, + "Verbosity level (0 - silent, 1 - a bit of output, 2+ - more output).") +COMMON_FLAG(bool, strip_env, 1, + "Whether to remove the sanitizer from DYLD_INSERT_LIBRARIES to " + "avoid passing it to children. Default is true.") +COMMON_FLAG(bool, detect_leaks, !SANITIZER_MAC, "Enable memory leak detection.") +COMMON_FLAG( + bool, leak_check_at_exit, true, + "Invoke leak checking in an atexit handler. Has no effect if " + "detect_leaks=false, or if __lsan_do_leak_check() is called before the " + "handler has a chance to run.") +COMMON_FLAG(bool, allocator_may_return_null, false, + "If false, the allocator will crash instead of returning 0 on " + "out-of-memory.") +COMMON_FLAG(bool, print_summary, true, + "If false, disable printing error summaries in addition to error " + "reports.") +COMMON_FLAG(int, print_module_map, 0, + "Print the process module map where supported (0 - don't print, " + "1 - print only once before process exits, 2 - print after each " + "report).") +COMMON_FLAG(bool, check_printf, true, "Check printf arguments.") +#define COMMON_FLAG_HANDLE_SIGNAL_HELP(signal) \ + "Controls custom tool's " #signal " handler (0 - do not registers the " \ + "handler, 1 - register the handler and allow user to set own, " \ + "2 - registers the handler and block user from changing it). " +COMMON_FLAG(HandleSignalMode, handle_segv, kHandleSignalYes, + COMMON_FLAG_HANDLE_SIGNAL_HELP(SIGSEGV)) +COMMON_FLAG(HandleSignalMode, handle_sigbus, kHandleSignalYes, + COMMON_FLAG_HANDLE_SIGNAL_HELP(SIGBUS)) +COMMON_FLAG(HandleSignalMode, handle_abort, kHandleSignalNo, + COMMON_FLAG_HANDLE_SIGNAL_HELP(SIGABRT)) +COMMON_FLAG(HandleSignalMode, handle_sigill, kHandleSignalNo, + COMMON_FLAG_HANDLE_SIGNAL_HELP(SIGILL)) +COMMON_FLAG(HandleSignalMode, handle_sigtrap, kHandleSignalNo, + COMMON_FLAG_HANDLE_SIGNAL_HELP(SIGTRAP)) +COMMON_FLAG(HandleSignalMode, handle_sigfpe, kHandleSignalYes, + COMMON_FLAG_HANDLE_SIGNAL_HELP(SIGFPE)) +#undef COMMON_FLAG_HANDLE_SIGNAL_HELP +COMMON_FLAG(bool, allow_user_segv_handler, true, + "Deprecated. True has no effect, use handle_sigbus=1. If false, " + "handle_*=1 will be upgraded to handle_*=2.") +COMMON_FLAG(bool, use_sigaltstack, true, + "If set, uses alternate stack for signal handling.") +COMMON_FLAG(bool, detect_deadlocks, true, + "If set, deadlock detection is enabled.") +COMMON_FLAG( + uptr, clear_shadow_mmap_threshold, 64 * 1024, + "Large shadow regions are zero-filled using mmap(NORESERVE) instead of " + "memset(). This is the threshold size in bytes.") +COMMON_FLAG(const char *, color, "auto", + "Colorize reports: (always|never|auto).") +COMMON_FLAG( + bool, legacy_pthread_cond, false, + "Enables support for dynamic libraries linked with libpthread 2.2.5.") +COMMON_FLAG(bool, intercept_tls_get_addr, false, "Intercept __tls_get_addr.") +COMMON_FLAG(bool, help, false, "Print the flag descriptions.") +COMMON_FLAG(uptr, mmap_limit_mb, 0, + "Limit the amount of mmap-ed memory (excluding shadow) in Mb; " + "not a user-facing flag, used mosly for testing the tools") +COMMON_FLAG(uptr, hard_rss_limit_mb, 0, + "Hard RSS limit in Mb." + " If non-zero, a background thread is spawned at startup" + " which periodically reads RSS and aborts the process if the" + " limit is reached") +COMMON_FLAG(uptr, soft_rss_limit_mb, 0, + "Soft RSS limit in Mb." + " If non-zero, a background thread is spawned at startup" + " which periodically reads RSS. If the limit is reached" + " all subsequent malloc/new calls will fail or return NULL" + " (depending on the value of allocator_may_return_null)" + " until the RSS goes below the soft limit." + " This limit does not affect memory allocations other than" + " malloc/new.") +COMMON_FLAG(uptr, max_allocation_size_mb, 0, + "If non-zero, malloc/new calls larger than this size will return " + "nullptr (or crash if allocator_may_return_null=false).") +COMMON_FLAG(bool, heap_profile, false, "Experimental heap profiler, asan-only") +COMMON_FLAG(s32, allocator_release_to_os_interval_ms, + ((bool)SANITIZER_FUCHSIA || (bool)SANITIZER_WINDOWS) ? -1 : 5000, + "Only affects a 64-bit allocator. If set, tries to release unused " + "memory to the OS, but not more often than this interval (in " + "milliseconds). Negative values mean do not attempt to release " + "memory to the OS.\n") +COMMON_FLAG(bool, can_use_proc_maps_statm, true, + "If false, do not attempt to read /proc/maps/statm." + " Mostly useful for testing sanitizers.") +COMMON_FLAG( + bool, coverage, false, + "If set, coverage information will be dumped at program shutdown (if the " + "coverage instrumentation was enabled at compile time).") +COMMON_FLAG(const char *, coverage_dir, ".", + "Target directory for coverage dumps. Defaults to the current " + "directory.") +COMMON_FLAG(const char *, cov_8bit_counters_out, "", + "If non-empty, write 8bit counters to this file. ") +COMMON_FLAG(const char *, cov_pcs_out, "", + "If non-empty, write the coverage pc table to this file. ") +COMMON_FLAG(bool, full_address_space, false, + "Sanitize complete address space; " + "by default kernel area on 32-bit platforms will not be sanitized") +COMMON_FLAG(bool, print_suppressions, true, + "Print matched suppressions at exit.") +COMMON_FLAG( + bool, disable_coredump, (SANITIZER_WORDSIZE == 64) && !SANITIZER_GO, + "Disable core dumping. By default, disable_coredump=1 on 64-bit to avoid" + " dumping a 16T+ core file. Ignored on OSes that don't dump core by" + " default and for sanitizers that don't reserve lots of virtual memory.") +COMMON_FLAG(bool, use_madv_dontdump, true, + "If set, instructs kernel to not store the (huge) shadow " + "in core file.") +COMMON_FLAG(bool, symbolize_inline_frames, true, + "Print inlined frames in stacktraces. Defaults to true.") +COMMON_FLAG(bool, demangle, true, "Print demangled symbols.") +COMMON_FLAG(bool, symbolize_vs_style, false, + "Print file locations in Visual Studio style (e.g: " + " file(10,42): ...") +COMMON_FLAG(int, dedup_token_length, 0, + "If positive, after printing a stack trace also print a short " + "string token based on this number of frames that will simplify " + "deduplication of the reports. " + "Example: 'DEDUP_TOKEN: foo-bar-main'. Default is 0.") +COMMON_FLAG(const char *, stack_trace_format, "DEFAULT", + "Format string used to render stack frames. " + "See sanitizer_stacktrace_printer.h for the format description. " + "Use DEFAULT to get default format.") +COMMON_FLAG(int, compress_stack_depot, 0, + "Compress stack depot to save memory.") +COMMON_FLAG(bool, no_huge_pages_for_shadow, true, + "If true, the shadow is not allowed to use huge pages. ") +COMMON_FLAG(bool, strict_string_checks, false, + "If set check that string arguments are properly null-terminated") +COMMON_FLAG(bool, intercept_strstr, true, + "If set, uses custom wrappers for strstr and strcasestr functions " + "to find more errors.") +COMMON_FLAG(bool, intercept_strspn, true, + "If set, uses custom wrappers for strspn and strcspn function " + "to find more errors.") +COMMON_FLAG(bool, intercept_strtok, true, + "If set, uses a custom wrapper for the strtok function " + "to find more errors.") +COMMON_FLAG(bool, intercept_strpbrk, true, + "If set, uses custom wrappers for strpbrk function " + "to find more errors.") +COMMON_FLAG( + bool, intercept_strcmp, true, + "If set, uses custom wrappers for strcmp functions to find more errors.") +COMMON_FLAG(bool, intercept_strlen, true, + "If set, uses custom wrappers for strlen and strnlen functions " + "to find more errors.") +COMMON_FLAG(bool, intercept_strndup, true, + "If set, uses custom wrappers for strndup functions " + "to find more errors.") +COMMON_FLAG(bool, intercept_strchr, true, + "If set, uses custom wrappers for strchr, strchrnul, and strrchr " + "functions to find more errors.") +COMMON_FLAG(bool, intercept_memcmp, true, + "If set, uses custom wrappers for memcmp function " + "to find more errors.") +COMMON_FLAG(bool, strict_memcmp, true, + "If true, assume that memcmp(p1, p2, n) always reads n bytes before " + "comparing p1 and p2.") +COMMON_FLAG(bool, intercept_memmem, true, + "If set, uses a wrapper for memmem() to find more errors.") +COMMON_FLAG(bool, intercept_intrin, true, + "If set, uses custom wrappers for memset/memcpy/memmove " + "intrinsics to find more errors.") +COMMON_FLAG(bool, intercept_stat, true, + "If set, uses custom wrappers for *stat functions " + "to find more errors.") +COMMON_FLAG(bool, intercept_send, true, + "If set, uses custom wrappers for send* functions " + "to find more errors.") +COMMON_FLAG(bool, decorate_proc_maps, (bool)SANITIZER_ANDROID, + "If set, decorate sanitizer mappings in /proc/self/maps with " + "user-readable names") +COMMON_FLAG(int, exitcode, 1, "Override the program exit status if the tool " + "found an error") +COMMON_FLAG( + bool, abort_on_error, (bool)SANITIZER_ANDROID || (bool)SANITIZER_MAC, + "If set, the tool calls abort() instead of _exit() after printing the " + "error report.") +COMMON_FLAG(bool, suppress_equal_pcs, true, + "Deduplicate multiple reports for single source location in " + "halt_on_error=false mode (asan only).") +COMMON_FLAG(bool, print_cmdline, false, "Print command line on crash " + "(asan only).") +COMMON_FLAG(bool, html_cov_report, false, "Generate html coverage report.") +COMMON_FLAG(const char *, sancov_path, "sancov", "Sancov tool location.") +COMMON_FLAG(bool, dump_instruction_bytes, false, + "If true, dump 16 bytes starting at the instruction that caused SEGV") +COMMON_FLAG(bool, dump_registers, true, + "If true, dump values of CPU registers when SEGV happens. Only " + "available on OS X for now.") +COMMON_FLAG(bool, detect_write_exec, false, + "If true, triggers warning when writable-executable pages requests " + "are being made") +COMMON_FLAG(bool, test_only_emulate_no_memorymap, false, + "TEST ONLY fail to read memory mappings to emulate sanitized " + "\"init\"") diff --git a/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_flat_map.h b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_flat_map.h new file mode 100644 index 0000000000..05fb554d20 --- /dev/null +++ b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_flat_map.h @@ -0,0 +1,173 @@ +//===-- sanitizer_flat_map.h ------------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// Part of the Sanitizer Allocator. +// +//===----------------------------------------------------------------------===// + +#ifndef SANITIZER_FLAT_MAP_H +#define SANITIZER_FLAT_MAP_H + +#include "sanitizer_atomic.h" +#include "sanitizer_common.h" +#include "sanitizer_internal_defs.h" +#include "sanitizer_local_address_space_view.h" +#include "sanitizer_mutex.h" + +namespace __sanitizer { + +// Call these callbacks on mmap/munmap. +struct NoOpMapUnmapCallback { + void OnMap(uptr p, uptr size) const {} + void OnUnmap(uptr p, uptr size) const {} +}; + +// Maps integers in rage [0, kSize) to values. +template <typename T, u64 kSize, + typename AddressSpaceViewTy = LocalAddressSpaceView> +class FlatMap { + public: + using AddressSpaceView = AddressSpaceViewTy; + void Init() { internal_memset(map_, 0, sizeof(map_)); } + + constexpr uptr size() const { return kSize; } + + bool contains(uptr idx) const { + CHECK_LT(idx, kSize); + return true; + } + + T &operator[](uptr idx) { + DCHECK_LT(idx, kSize); + return map_[idx]; + } + + const T &operator[](uptr idx) const { + DCHECK_LT(idx, kSize); + return map_[idx]; + } + + private: + T map_[kSize]; +}; + +// TwoLevelMap maps integers in range [0, kSize1*kSize2) to values. +// It is implemented as a two-dimensional array: array of kSize1 pointers +// to kSize2-byte arrays. The secondary arrays are mmaped on demand. +// Each value is initially zero and can be set to something else only once. +// Setting and getting values from multiple threads is safe w/o extra locking. +template <typename T, u64 kSize1, u64 kSize2, + typename AddressSpaceViewTy = LocalAddressSpaceView, + class MapUnmapCallback = NoOpMapUnmapCallback> +class TwoLevelMap { + static_assert(IsPowerOfTwo(kSize2), "Use a power of two for performance."); + + public: + using AddressSpaceView = AddressSpaceViewTy; + void Init() { + mu_.Init(); + internal_memset(map1_, 0, sizeof(map1_)); + } + + void TestOnlyUnmap() { + for (uptr i = 0; i < kSize1; i++) { + T *p = Get(i); + if (!p) + continue; + MapUnmapCallback().OnUnmap(reinterpret_cast<uptr>(p), MmapSize()); + UnmapOrDie(p, kSize2); + } + Init(); + } + + uptr MemoryUsage() const { + uptr res = 0; + for (uptr i = 0; i < kSize1; i++) { + T *p = Get(i); + if (!p) + continue; + res += MmapSize(); + } + return res; + } + + constexpr uptr size() const { return kSize1 * kSize2; } + constexpr uptr size1() const { return kSize1; } + constexpr uptr size2() const { return kSize2; } + + bool contains(uptr idx) const { + CHECK_LT(idx, kSize1 * kSize2); + return Get(idx / kSize2); + } + + const T &operator[](uptr idx) const { + DCHECK_LT(idx, kSize1 * kSize2); + T *map2 = GetOrCreate(idx / kSize2); + return *AddressSpaceView::Load(&map2[idx % kSize2]); + } + + T &operator[](uptr idx) { + DCHECK_LT(idx, kSize1 * kSize2); + T *map2 = GetOrCreate(idx / kSize2); + return *AddressSpaceView::LoadWritable(&map2[idx % kSize2]); + } + + private: + constexpr uptr MmapSize() const { + return RoundUpTo(kSize2 * sizeof(T), GetPageSizeCached()); + } + + T *Get(uptr idx) const { + DCHECK_LT(idx, kSize1); + return reinterpret_cast<T *>( + atomic_load(&map1_[idx], memory_order_acquire)); + } + + T *GetOrCreate(uptr idx) const { + DCHECK_LT(idx, kSize1); + // This code needs to use memory_order_acquire/consume, but we use + // memory_order_relaxed for performance reasons (matters for arm64). We + // expect memory_order_relaxed to be effectively equivalent to + // memory_order_consume in this case for all relevant architectures: all + // dependent data is reachable only by dereferencing the resulting pointer. + // If relaxed load fails to see stored ptr, the code will fall back to + // Create() and reload the value again with locked mutex as a memory + // barrier. + T *res = reinterpret_cast<T *>(atomic_load_relaxed(&map1_[idx])); + if (LIKELY(res)) + return res; + return Create(idx); + } + + NOINLINE T *Create(uptr idx) const { + SpinMutexLock l(&mu_); + T *res = Get(idx); + if (!res) { + res = reinterpret_cast<T *>(MmapOrDie(MmapSize(), "TwoLevelMap")); + MapUnmapCallback().OnMap(reinterpret_cast<uptr>(res), kSize2); + atomic_store(&map1_[idx], reinterpret_cast<uptr>(res), + memory_order_release); + } + return res; + } + + mutable StaticSpinMutex mu_; + mutable atomic_uintptr_t map1_[kSize1]; +}; + +template <u64 kSize, typename AddressSpaceViewTy = LocalAddressSpaceView> +using FlatByteMap = FlatMap<u8, kSize, AddressSpaceViewTy>; + +template <u64 kSize1, u64 kSize2, + typename AddressSpaceViewTy = LocalAddressSpaceView, + class MapUnmapCallback = NoOpMapUnmapCallback> +using TwoLevelByteMap = + TwoLevelMap<u8, kSize1, kSize2, AddressSpaceViewTy, MapUnmapCallback>; +} // namespace __sanitizer + +#endif diff --git a/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_freebsd.h b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_freebsd.h new file mode 100644 index 0000000000..82b227eab6 --- /dev/null +++ b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_freebsd.h @@ -0,0 +1,137 @@ +//===-- sanitizer_freebsd.h -------------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file is a part of Sanitizer runtime. It contains FreeBSD-specific +// definitions. +// +//===----------------------------------------------------------------------===// + +#ifndef SANITIZER_FREEBSD_H +#define SANITIZER_FREEBSD_H + +#include "sanitizer_internal_defs.h" + +// x86-64 FreeBSD 9.2 and older define 'ucontext_t' incorrectly in +// 32-bit mode. +#if SANITIZER_FREEBSD && (SANITIZER_WORDSIZE == 32) +#include <osreldate.h> +#if __FreeBSD_version <= 902001 // v9.2 +#include <link.h> +#include <sys/param.h> +#include <ucontext.h> + +namespace __sanitizer { + +typedef unsigned long long __xuint64_t; + +typedef __int32_t __xregister_t; + +typedef struct __xmcontext { + __xregister_t mc_onstack; + __xregister_t mc_gs; + __xregister_t mc_fs; + __xregister_t mc_es; + __xregister_t mc_ds; + __xregister_t mc_edi; + __xregister_t mc_esi; + __xregister_t mc_ebp; + __xregister_t mc_isp; + __xregister_t mc_ebx; + __xregister_t mc_edx; + __xregister_t mc_ecx; + __xregister_t mc_eax; + __xregister_t mc_trapno; + __xregister_t mc_err; + __xregister_t mc_eip; + __xregister_t mc_cs; + __xregister_t mc_eflags; + __xregister_t mc_esp; + __xregister_t mc_ss; + + int mc_len; + int mc_fpformat; + int mc_ownedfp; + __xregister_t mc_flags; + + int mc_fpstate[128] __aligned(16); + __xregister_t mc_fsbase; + __xregister_t mc_gsbase; + __xregister_t mc_xfpustate; + __xregister_t mc_xfpustate_len; + + int mc_spare2[4]; +} xmcontext_t; + +typedef struct __xucontext { + sigset_t uc_sigmask; + xmcontext_t uc_mcontext; + + struct __ucontext *uc_link; + stack_t uc_stack; + int uc_flags; + int __spare__[4]; +} xucontext_t; + +struct xkinfo_vmentry { + int kve_structsize; + int kve_type; + __xuint64_t kve_start; + __xuint64_t kve_end; + __xuint64_t kve_offset; + __xuint64_t kve_vn_fileid; + __uint32_t kve_vn_fsid; + int kve_flags; + int kve_resident; + int kve_private_resident; + int kve_protection; + int kve_ref_count; + int kve_shadow_count; + int kve_vn_type; + __xuint64_t kve_vn_size; + __uint32_t kve_vn_rdev; + __uint16_t kve_vn_mode; + __uint16_t kve_status; + int _kve_ispare[12]; + char kve_path[PATH_MAX]; +}; + +typedef struct { + __uint32_t p_type; + __uint32_t p_offset; + __uint32_t p_vaddr; + __uint32_t p_paddr; + __uint32_t p_filesz; + __uint32_t p_memsz; + __uint32_t p_flags; + __uint32_t p_align; +} XElf32_Phdr; + +struct xdl_phdr_info { + Elf_Addr dlpi_addr; + const char *dlpi_name; + const XElf32_Phdr *dlpi_phdr; + Elf_Half dlpi_phnum; + unsigned long long int dlpi_adds; + unsigned long long int dlpi_subs; + size_t dlpi_tls_modid; + void *dlpi_tls_data; +}; + +typedef int (*__xdl_iterate_hdr_callback)(struct xdl_phdr_info *, size_t, + void *); +typedef int xdl_iterate_phdr_t(__xdl_iterate_hdr_callback, void *); + +#define xdl_iterate_phdr(callback, param) \ + (((xdl_iterate_phdr_t *)dl_iterate_phdr)((callback), (param))) + +} // namespace __sanitizer + +#endif // __FreeBSD_version <= 902001 +#endif // SANITIZER_FREEBSD && (SANITIZER_WORDSIZE == 32) + +#endif // SANITIZER_FREEBSD_H diff --git a/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_fuchsia.cpp b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_fuchsia.cpp new file mode 100644 index 0000000000..54cdc8a7fb --- /dev/null +++ b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_fuchsia.cpp @@ -0,0 +1,520 @@ +//===-- sanitizer_fuchsia.cpp ---------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file is shared between AddressSanitizer and other sanitizer +// run-time libraries and implements Fuchsia-specific functions from +// sanitizer_common.h. +//===----------------------------------------------------------------------===// + +#include "sanitizer_fuchsia.h" +#if SANITIZER_FUCHSIA + +#include <pthread.h> +#include <stdlib.h> +#include <unistd.h> +#error #include <zircon/errors.h> +#error #include <zircon/process.h> +#error #include <zircon/syscalls.h> +#error #include <zircon/utc.h> + +#include "sanitizer_common.h" +#include "sanitizer_libc.h" +#include "sanitizer_mutex.h" + +namespace __sanitizer { + +void NORETURN internal__exit(int exitcode) { _zx_process_exit(exitcode); } + +uptr internal_sched_yield() { + zx_status_t status = _zx_nanosleep(0); + CHECK_EQ(status, ZX_OK); + return 0; // Why doesn't this return void? +} + +void internal_usleep(u64 useconds) { + zx_status_t status = _zx_nanosleep(_zx_deadline_after(ZX_USEC(useconds))); + CHECK_EQ(status, ZX_OK); +} + +u64 NanoTime() { + zx_handle_t utc_clock = _zx_utc_reference_get(); + CHECK_NE(utc_clock, ZX_HANDLE_INVALID); + zx_time_t time; + zx_status_t status = _zx_clock_read(utc_clock, &time); + CHECK_EQ(status, ZX_OK); + return time; +} + +u64 MonotonicNanoTime() { return _zx_clock_get_monotonic(); } + +uptr internal_getpid() { + zx_info_handle_basic_t info; + zx_status_t status = + _zx_object_get_info(_zx_process_self(), ZX_INFO_HANDLE_BASIC, &info, + sizeof(info), NULL, NULL); + CHECK_EQ(status, ZX_OK); + uptr pid = static_cast<uptr>(info.koid); + CHECK_EQ(pid, info.koid); + return pid; +} + +int internal_dlinfo(void *handle, int request, void *p) { UNIMPLEMENTED(); } + +uptr GetThreadSelf() { return reinterpret_cast<uptr>(thrd_current()); } + +tid_t GetTid() { return GetThreadSelf(); } + +void Abort() { abort(); } + +int Atexit(void (*function)(void)) { return atexit(function); } + +void GetThreadStackTopAndBottom(bool, uptr *stack_top, uptr *stack_bottom) { + pthread_attr_t attr; + CHECK_EQ(pthread_getattr_np(pthread_self(), &attr), 0); + void *base; + size_t size; + CHECK_EQ(pthread_attr_getstack(&attr, &base, &size), 0); + CHECK_EQ(pthread_attr_destroy(&attr), 0); + + *stack_bottom = reinterpret_cast<uptr>(base); + *stack_top = *stack_bottom + size; +} + +void InitializePlatformEarly() {} +void MaybeReexec() {} +void CheckASLR() {} +void CheckMPROTECT() {} +void PlatformPrepareForSandboxing(__sanitizer_sandbox_arguments *args) {} +void DisableCoreDumperIfNecessary() {} +void InstallDeadlySignalHandlers(SignalHandlerType handler) {} +void SetAlternateSignalStack() {} +void UnsetAlternateSignalStack() {} +void InitTlsSize() {} + +bool SignalContext::IsStackOverflow() const { return false; } +void SignalContext::DumpAllRegisters(void *context) { UNIMPLEMENTED(); } +const char *SignalContext::Describe() const { UNIMPLEMENTED(); } + +void FutexWait(atomic_uint32_t *p, u32 cmp) { + zx_status_t status = _zx_futex_wait(reinterpret_cast<zx_futex_t *>(p), cmp, + ZX_HANDLE_INVALID, ZX_TIME_INFINITE); + if (status != ZX_ERR_BAD_STATE) // Normal race. + CHECK_EQ(status, ZX_OK); +} + +void FutexWake(atomic_uint32_t *p, u32 count) { + zx_status_t status = _zx_futex_wake(reinterpret_cast<zx_futex_t *>(p), count); + CHECK_EQ(status, ZX_OK); +} + +uptr GetPageSize() { return _zx_system_get_page_size(); } + +uptr GetMmapGranularity() { return _zx_system_get_page_size(); } + +sanitizer_shadow_bounds_t ShadowBounds; + +void InitShadowBounds() { ShadowBounds = __sanitizer_shadow_bounds(); } + +uptr GetMaxUserVirtualAddress() { + InitShadowBounds(); + return ShadowBounds.memory_limit - 1; +} + +uptr GetMaxVirtualAddress() { return GetMaxUserVirtualAddress(); } + +static void *DoAnonymousMmapOrDie(uptr size, const char *mem_type, + bool raw_report, bool die_for_nomem) { + size = RoundUpTo(size, GetPageSize()); + + zx_handle_t vmo; + zx_status_t status = _zx_vmo_create(size, 0, &vmo); + if (status != ZX_OK) { + if (status != ZX_ERR_NO_MEMORY || die_for_nomem) + ReportMmapFailureAndDie(size, mem_type, "zx_vmo_create", status, + raw_report); + return nullptr; + } + _zx_object_set_property(vmo, ZX_PROP_NAME, mem_type, + internal_strlen(mem_type)); + + // TODO(mcgrathr): Maybe allocate a VMAR for all sanitizer heap and use that? + uintptr_t addr; + status = + _zx_vmar_map(_zx_vmar_root_self(), ZX_VM_PERM_READ | ZX_VM_PERM_WRITE, 0, + vmo, 0, size, &addr); + _zx_handle_close(vmo); + + if (status != ZX_OK) { + if (status != ZX_ERR_NO_MEMORY || die_for_nomem) + ReportMmapFailureAndDie(size, mem_type, "zx_vmar_map", status, + raw_report); + return nullptr; + } + + IncreaseTotalMmap(size); + + return reinterpret_cast<void *>(addr); +} + +void *MmapOrDie(uptr size, const char *mem_type, bool raw_report) { + return DoAnonymousMmapOrDie(size, mem_type, raw_report, true); +} + +void *MmapNoReserveOrDie(uptr size, const char *mem_type) { + return MmapOrDie(size, mem_type); +} + +void *MmapOrDieOnFatalError(uptr size, const char *mem_type) { + return DoAnonymousMmapOrDie(size, mem_type, false, false); +} + +uptr ReservedAddressRange::Init(uptr init_size, const char *name, + uptr fixed_addr) { + init_size = RoundUpTo(init_size, GetPageSize()); + DCHECK_EQ(os_handle_, ZX_HANDLE_INVALID); + uintptr_t base; + zx_handle_t vmar; + zx_status_t status = _zx_vmar_allocate( + _zx_vmar_root_self(), + ZX_VM_CAN_MAP_READ | ZX_VM_CAN_MAP_WRITE | ZX_VM_CAN_MAP_SPECIFIC, 0, + init_size, &vmar, &base); + if (status != ZX_OK) + ReportMmapFailureAndDie(init_size, name, "zx_vmar_allocate", status); + base_ = reinterpret_cast<void *>(base); + size_ = init_size; + name_ = name; + os_handle_ = vmar; + + return reinterpret_cast<uptr>(base_); +} + +static uptr DoMmapFixedOrDie(zx_handle_t vmar, uptr fixed_addr, uptr map_size, + void *base, const char *name, bool die_for_nomem) { + uptr offset = fixed_addr - reinterpret_cast<uptr>(base); + map_size = RoundUpTo(map_size, GetPageSize()); + zx_handle_t vmo; + zx_status_t status = _zx_vmo_create(map_size, 0, &vmo); + if (status != ZX_OK) { + if (status != ZX_ERR_NO_MEMORY || die_for_nomem) + ReportMmapFailureAndDie(map_size, name, "zx_vmo_create", status); + return 0; + } + _zx_object_set_property(vmo, ZX_PROP_NAME, name, internal_strlen(name)); + DCHECK_GE(base + size_, map_size + offset); + uintptr_t addr; + + status = + _zx_vmar_map(vmar, ZX_VM_PERM_READ | ZX_VM_PERM_WRITE | ZX_VM_SPECIFIC, + offset, vmo, 0, map_size, &addr); + _zx_handle_close(vmo); + if (status != ZX_OK) { + if (status != ZX_ERR_NO_MEMORY || die_for_nomem) { + ReportMmapFailureAndDie(map_size, name, "zx_vmar_map", status); + } + return 0; + } + IncreaseTotalMmap(map_size); + return addr; +} + +uptr ReservedAddressRange::Map(uptr fixed_addr, uptr map_size, + const char *name) { + return DoMmapFixedOrDie(os_handle_, fixed_addr, map_size, base_, name_, + false); +} + +uptr ReservedAddressRange::MapOrDie(uptr fixed_addr, uptr map_size, + const char *name) { + return DoMmapFixedOrDie(os_handle_, fixed_addr, map_size, base_, name_, true); +} + +void UnmapOrDieVmar(void *addr, uptr size, zx_handle_t target_vmar) { + if (!addr || !size) + return; + size = RoundUpTo(size, GetPageSize()); + + zx_status_t status = + _zx_vmar_unmap(target_vmar, reinterpret_cast<uintptr_t>(addr), size); + if (status != ZX_OK) { + Report("ERROR: %s failed to deallocate 0x%zx (%zd) bytes at address %p\n", + SanitizerToolName, size, size, addr); + CHECK("unable to unmap" && 0); + } + + DecreaseTotalMmap(size); +} + +void ReservedAddressRange::Unmap(uptr addr, uptr size) { + CHECK_LE(size, size_); + const zx_handle_t vmar = static_cast<zx_handle_t>(os_handle_); + if (addr == reinterpret_cast<uptr>(base_)) { + if (size == size_) { + // Destroying the vmar effectively unmaps the whole mapping. + _zx_vmar_destroy(vmar); + _zx_handle_close(vmar); + os_handle_ = static_cast<uptr>(ZX_HANDLE_INVALID); + DecreaseTotalMmap(size); + return; + } + } else { + CHECK_EQ(addr + size, reinterpret_cast<uptr>(base_) + size_); + } + // Partial unmapping does not affect the fact that the initial range is still + // reserved, and the resulting unmapped memory can't be reused. + UnmapOrDieVmar(reinterpret_cast<void *>(addr), size, vmar); +} + +// This should never be called. +void *MmapFixedNoAccess(uptr fixed_addr, uptr size, const char *name) { + UNIMPLEMENTED(); +} + +bool MprotectNoAccess(uptr addr, uptr size) { + return _zx_vmar_protect(_zx_vmar_root_self(), 0, addr, size) == ZX_OK; +} + +bool MprotectReadOnly(uptr addr, uptr size) { + return _zx_vmar_protect(_zx_vmar_root_self(), ZX_VM_PERM_READ, addr, size) == + ZX_OK; +} + +void *MmapAlignedOrDieOnFatalError(uptr size, uptr alignment, + const char *mem_type) { + CHECK_GE(size, GetPageSize()); + CHECK(IsPowerOfTwo(size)); + CHECK(IsPowerOfTwo(alignment)); + + zx_handle_t vmo; + zx_status_t status = _zx_vmo_create(size, 0, &vmo); + if (status != ZX_OK) { + if (status != ZX_ERR_NO_MEMORY) + ReportMmapFailureAndDie(size, mem_type, "zx_vmo_create", status, false); + return nullptr; + } + _zx_object_set_property(vmo, ZX_PROP_NAME, mem_type, + internal_strlen(mem_type)); + + // TODO(mcgrathr): Maybe allocate a VMAR for all sanitizer heap and use that? + + // Map a larger size to get a chunk of address space big enough that + // it surely contains an aligned region of the requested size. Then + // overwrite the aligned middle portion with a mapping from the + // beginning of the VMO, and unmap the excess before and after. + size_t map_size = size + alignment; + uintptr_t addr; + status = + _zx_vmar_map(_zx_vmar_root_self(), ZX_VM_PERM_READ | ZX_VM_PERM_WRITE, 0, + vmo, 0, map_size, &addr); + if (status == ZX_OK) { + uintptr_t map_addr = addr; + uintptr_t map_end = map_addr + map_size; + addr = RoundUpTo(map_addr, alignment); + uintptr_t end = addr + size; + if (addr != map_addr) { + zx_info_vmar_t info; + status = _zx_object_get_info(_zx_vmar_root_self(), ZX_INFO_VMAR, &info, + sizeof(info), NULL, NULL); + if (status == ZX_OK) { + uintptr_t new_addr; + status = _zx_vmar_map( + _zx_vmar_root_self(), + ZX_VM_PERM_READ | ZX_VM_PERM_WRITE | ZX_VM_SPECIFIC_OVERWRITE, + addr - info.base, vmo, 0, size, &new_addr); + if (status == ZX_OK) + CHECK_EQ(new_addr, addr); + } + } + if (status == ZX_OK && addr != map_addr) + status = _zx_vmar_unmap(_zx_vmar_root_self(), map_addr, addr - map_addr); + if (status == ZX_OK && end != map_end) + status = _zx_vmar_unmap(_zx_vmar_root_self(), end, map_end - end); + } + _zx_handle_close(vmo); + + if (status != ZX_OK) { + if (status != ZX_ERR_NO_MEMORY) + ReportMmapFailureAndDie(size, mem_type, "zx_vmar_map", status, false); + return nullptr; + } + + IncreaseTotalMmap(size); + + return reinterpret_cast<void *>(addr); +} + +void UnmapOrDie(void *addr, uptr size) { + UnmapOrDieVmar(addr, size, _zx_vmar_root_self()); +} + +void ReleaseMemoryPagesToOS(uptr beg, uptr end) { + uptr beg_aligned = RoundUpTo(beg, GetPageSize()); + uptr end_aligned = RoundDownTo(end, GetPageSize()); + if (beg_aligned < end_aligned) { + zx_handle_t root_vmar = _zx_vmar_root_self(); + CHECK_NE(root_vmar, ZX_HANDLE_INVALID); + zx_status_t status = + _zx_vmar_op_range(root_vmar, ZX_VMAR_OP_DECOMMIT, beg_aligned, + end_aligned - beg_aligned, nullptr, 0); + CHECK_EQ(status, ZX_OK); + } +} + +void DumpProcessMap() { + // TODO(mcgrathr): write it + return; +} + +bool IsAccessibleMemoryRange(uptr beg, uptr size) { + // TODO(mcgrathr): Figure out a better way. + zx_handle_t vmo; + zx_status_t status = _zx_vmo_create(size, 0, &vmo); + if (status == ZX_OK) { + status = _zx_vmo_write(vmo, reinterpret_cast<const void *>(beg), 0, size); + _zx_handle_close(vmo); + } + return status == ZX_OK; +} + +// FIXME implement on this platform. +void GetMemoryProfile(fill_profile_f cb, uptr *stats) {} + +bool ReadFileToBuffer(const char *file_name, char **buff, uptr *buff_size, + uptr *read_len, uptr max_len, error_t *errno_p) { + zx_handle_t vmo; + zx_status_t status = __sanitizer_get_configuration(file_name, &vmo); + if (status == ZX_OK) { + uint64_t vmo_size; + status = _zx_vmo_get_size(vmo, &vmo_size); + if (status == ZX_OK) { + if (vmo_size < max_len) + max_len = vmo_size; + size_t map_size = RoundUpTo(max_len, GetPageSize()); + uintptr_t addr; + status = _zx_vmar_map(_zx_vmar_root_self(), ZX_VM_PERM_READ, 0, vmo, 0, + map_size, &addr); + if (status == ZX_OK) { + *buff = reinterpret_cast<char *>(addr); + *buff_size = map_size; + *read_len = max_len; + } + } + _zx_handle_close(vmo); + } + if (status != ZX_OK && errno_p) + *errno_p = status; + return status == ZX_OK; +} + +void RawWrite(const char *buffer) { + constexpr size_t size = 128; + static _Thread_local char line[size]; + static _Thread_local size_t lastLineEnd = 0; + static _Thread_local size_t cur = 0; + + while (*buffer) { + if (cur >= size) { + if (lastLineEnd == 0) + lastLineEnd = size; + __sanitizer_log_write(line, lastLineEnd); + internal_memmove(line, line + lastLineEnd, cur - lastLineEnd); + cur = cur - lastLineEnd; + lastLineEnd = 0; + } + if (*buffer == '\n') + lastLineEnd = cur + 1; + line[cur++] = *buffer++; + } + // Flush all complete lines before returning. + if (lastLineEnd != 0) { + __sanitizer_log_write(line, lastLineEnd); + internal_memmove(line, line + lastLineEnd, cur - lastLineEnd); + cur = cur - lastLineEnd; + lastLineEnd = 0; + } +} + +void CatastrophicErrorWrite(const char *buffer, uptr length) { + __sanitizer_log_write(buffer, length); +} + +char **StoredArgv; +char **StoredEnviron; + +char **GetArgv() { return StoredArgv; } +char **GetEnviron() { return StoredEnviron; } + +const char *GetEnv(const char *name) { + if (StoredEnviron) { + uptr NameLen = internal_strlen(name); + for (char **Env = StoredEnviron; *Env != 0; Env++) { + if (internal_strncmp(*Env, name, NameLen) == 0 && (*Env)[NameLen] == '=') + return (*Env) + NameLen + 1; + } + } + return nullptr; +} + +uptr ReadBinaryName(/*out*/ char *buf, uptr buf_len) { + const char *argv0 = "<UNKNOWN>"; + if (StoredArgv && StoredArgv[0]) { + argv0 = StoredArgv[0]; + } + internal_strncpy(buf, argv0, buf_len); + return internal_strlen(buf); +} + +uptr ReadLongProcessName(/*out*/ char *buf, uptr buf_len) { + return ReadBinaryName(buf, buf_len); +} + +uptr MainThreadStackBase, MainThreadStackSize; + +bool GetRandom(void *buffer, uptr length, bool blocking) { + CHECK_LE(length, ZX_CPRNG_DRAW_MAX_LEN); + _zx_cprng_draw(buffer, length); + return true; +} + +u32 GetNumberOfCPUs() { return zx_system_get_num_cpus(); } + +uptr GetRSS() { UNIMPLEMENTED(); } + +void *internal_start_thread(void *(*func)(void *arg), void *arg) { return 0; } +void internal_join_thread(void *th) {} + +void InitializePlatformCommonFlags(CommonFlags *cf) {} + +} // namespace __sanitizer + +using namespace __sanitizer; + +extern "C" { +void __sanitizer_startup_hook(int argc, char **argv, char **envp, + void *stack_base, size_t stack_size) { + __sanitizer::StoredArgv = argv; + __sanitizer::StoredEnviron = envp; + __sanitizer::MainThreadStackBase = reinterpret_cast<uintptr_t>(stack_base); + __sanitizer::MainThreadStackSize = stack_size; +} + +void __sanitizer_set_report_path(const char *path) { + // Handle the initialization code in each sanitizer, but no other calls. + // This setting is never consulted on Fuchsia. + DCHECK_EQ(path, common_flags()->log_path); +} + +void __sanitizer_set_report_fd(void *fd) { + UNREACHABLE("not available on Fuchsia"); +} + +const char *__sanitizer_get_report_path() { + UNREACHABLE("not available on Fuchsia"); +} +} // extern "C" + +#endif // SANITIZER_FUCHSIA diff --git a/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_fuchsia.h b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_fuchsia.h new file mode 100644 index 0000000000..77c9a3f9d1 --- /dev/null +++ b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_fuchsia.h @@ -0,0 +1,38 @@ +//===-- sanitizer_fuchsia.h ------------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===---------------------------------------------------------------------===// +// +// Fuchsia-specific sanitizer support. +// +//===---------------------------------------------------------------------===// +#ifndef SANITIZER_FUCHSIA_H +#define SANITIZER_FUCHSIA_H + +#include "sanitizer_platform.h" +#if SANITIZER_FUCHSIA + +#include "sanitizer_common.h" + +#error #include <zircon/sanitizer.h> +#error #include <zircon/syscalls/object.h> + +namespace __sanitizer { + +extern uptr MainThreadStackBase, MainThreadStackSize; +extern sanitizer_shadow_bounds_t ShadowBounds; + +struct MemoryMappingLayoutData { + InternalMmapVector<zx_info_maps_t> data; + size_t current; // Current index into the vector. +}; + +void InitShadowBounds(); + +} // namespace __sanitizer + +#endif // SANITIZER_FUCHSIA +#endif // SANITIZER_FUCHSIA_H diff --git a/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_getauxval.h b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_getauxval.h new file mode 100644 index 0000000000..38439e44f6 --- /dev/null +++ b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_getauxval.h @@ -0,0 +1,60 @@ +//===-- sanitizer_getauxval.h -----------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// Common getauxval() guards and definitions. +// getauxval() is not defined until glibc version 2.16, or until API level 21 +// for Android. +// Implement the getauxval() compat function for NetBSD. +// +//===----------------------------------------------------------------------===// + +#ifndef SANITIZER_GETAUXVAL_H +#define SANITIZER_GETAUXVAL_H + +#include "sanitizer_platform.h" +#include "sanitizer_glibc_version.h" + +#if SANITIZER_LINUX || SANITIZER_FUCHSIA + +# if (__GLIBC_PREREQ(2, 16) || (SANITIZER_ANDROID && __ANDROID_API__ >= 21) || \ + SANITIZER_FUCHSIA) && \ + !SANITIZER_GO +# define SANITIZER_USE_GETAUXVAL 1 +# else +# define SANITIZER_USE_GETAUXVAL 0 +# endif + +# if SANITIZER_USE_GETAUXVAL +# include <sys/auxv.h> +# else +// The weak getauxval definition allows to check for the function at runtime. +// This is useful for Android, when compiled at a lower API level yet running +// on a more recent platform that offers the function. +extern "C" SANITIZER_WEAK_ATTRIBUTE unsigned long getauxval(unsigned long type); +# endif + +#elif SANITIZER_NETBSD + +#define SANITIZER_USE_GETAUXVAL 1 + +#include <dlfcn.h> +#include <elf.h> + +static inline decltype(AuxInfo::a_v) getauxval(decltype(AuxInfo::a_type) type) { + for (const AuxInfo *aux = (const AuxInfo *)_dlauxinfo(); + aux->a_type != AT_NULL; ++aux) { + if (type == aux->a_type) + return aux->a_v; + } + + return 0; +} + +#endif + +#endif // SANITIZER_GETAUXVAL_H diff --git a/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_glibc_version.h b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_glibc_version.h new file mode 100644 index 0000000000..47175f20aa --- /dev/null +++ b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_glibc_version.h @@ -0,0 +1,26 @@ +//===-- sanitizer_glibc_version.h -----------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file is a part of Sanitizer common code. +// +//===----------------------------------------------------------------------===// + +#ifndef SANITIZER_GLIBC_VERSION_H +#define SANITIZER_GLIBC_VERSION_H + +#include "sanitizer_platform.h" + +#if SANITIZER_LINUX || SANITIZER_FUCHSIA +#include <features.h> +#endif + +#ifndef __GLIBC_PREREQ +#define __GLIBC_PREREQ(x, y) 0 +#endif + +#endif diff --git a/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_hash.h b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_hash.h new file mode 100644 index 0000000000..f7cf9f234e --- /dev/null +++ b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_hash.h @@ -0,0 +1,67 @@ +//===-- sanitizer_common.h --------------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file implements a simple hash function. +//===----------------------------------------------------------------------===// + +#ifndef SANITIZER_HASH_H +#define SANITIZER_HASH_H + +#include "sanitizer_internal_defs.h" + +namespace __sanitizer { +class MurMur2HashBuilder { + static const u32 m = 0x5bd1e995; + static const u32 seed = 0x9747b28c; + static const u32 r = 24; + u32 h; + + public: + explicit MurMur2HashBuilder(u32 init = 0) { h = seed ^ init; } + void add(u32 k) { + k *= m; + k ^= k >> r; + k *= m; + h *= m; + h ^= k; + } + u32 get() { + u32 x = h; + x ^= x >> 13; + x *= m; + x ^= x >> 15; + return x; + } +}; + +class MurMur2Hash64Builder { + static const u64 m = 0xc6a4a7935bd1e995ull; + static const u64 seed = 0x9747b28c9747b28cull; + static const u64 r = 47; + u64 h; + + public: + explicit MurMur2Hash64Builder(u64 init = 0) { h = seed ^ (init * m); } + void add(u64 k) { + k *= m; + k ^= k >> r; + k *= m; + h ^= k; + h *= m; + } + u64 get() { + u64 x = h; + x ^= x >> r; + x *= m; + x ^= x >> r; + return x; + } +}; +} //namespace __sanitizer + +#endif // SANITIZER_HASH_H diff --git a/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_interceptors_ioctl_netbsd.inc b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_interceptors_ioctl_netbsd.inc new file mode 100644 index 0000000000..9683b97ab9 --- /dev/null +++ b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_interceptors_ioctl_netbsd.inc @@ -0,0 +1,1535 @@ +//===-- sanitizer_interceptors_ioctl_netbsd.inc -----------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// Ioctl handling in common sanitizer interceptors. +//===----------------------------------------------------------------------===// + +#if SANITIZER_NETBSD + +#include "sanitizer_flags.h" + +struct ioctl_desc { + unsigned req; + // FIXME: support read+write arguments. Currently READWRITE and WRITE do the + // same thing. + // XXX: The declarations below may use WRITE instead of READWRITE, unless + // explicitly noted. + enum { NONE, READ, WRITE, READWRITE, CUSTOM } type : 3; + unsigned size : 29; + const char *name; +}; + +const unsigned ioctl_table_max = 1238; +static ioctl_desc ioctl_table[ioctl_table_max]; +static unsigned ioctl_table_size = 0; + +// This can not be declared as a global, because references to struct_*_sz +// require a global initializer. And this table must be available before global +// initializers are run. +static void ioctl_table_fill() { +#define _(rq, tp, sz) \ + if (IOCTL_##rq != IOCTL_NOT_PRESENT) { \ + CHECK(ioctl_table_size < ioctl_table_max); \ + ioctl_table[ioctl_table_size].req = IOCTL_##rq; \ + ioctl_table[ioctl_table_size].type = ioctl_desc::tp; \ + ioctl_table[ioctl_table_size].size = sz; \ + ioctl_table[ioctl_table_size].name = #rq; \ + ++ioctl_table_size; \ + } + + /* Entries from file: altq/altq_afmap.h */ + _(AFM_ADDFMAP, READWRITE, struct_atm_flowmap_sz); + _(AFM_DELFMAP, READWRITE, struct_atm_flowmap_sz); + _(AFM_CLEANFMAP, READWRITE, struct_atm_flowmap_sz); + _(AFM_GETFMAP, READWRITE, struct_atm_flowmap_sz); + /* Entries from file: altq/altq.h */ + _(ALTQGTYPE, READWRITE, struct_altqreq_sz); + _(ALTQTBRSET, READ, struct_tbrreq_sz); + _(ALTQTBRGET, READWRITE, struct_tbrreq_sz); + /* Entries from file: altq/altq_blue.h */ + _(BLUE_IF_ATTACH, READ, struct_blue_interface_sz); + _(BLUE_DISABLE, READ, struct_blue_interface_sz); + _(BLUE_CONFIG, READWRITE, struct_blue_conf_sz); + _(BLUE_GETSTATS, READWRITE, struct_blue_stats_sz); + /* Entries from file: altq/altq_cbq.h */ + _(CBQ_ENABLE, READ, struct_cbq_interface_sz); + _(CBQ_ADD_CLASS, READWRITE, struct_cbq_add_class_sz); + _(CBQ_DEL_CLASS, READ, struct_cbq_delete_class_sz); + _(CBQ_MODIFY_CLASS, READWRITE, struct_cbq_modify_class_sz); + _(CBQ_DEL_FILTER, READ, struct_cbq_delete_filter_sz); + _(CBQ_GETSTATS, READWRITE, struct_cbq_getstats_sz); + /* Entries from file: altq/altq_cdnr.h */ + _(CDNR_IF_DETACH, READ, struct_cdnr_interface_sz); + _(CDNR_ADD_FILTER, READWRITE, struct_cdnr_add_filter_sz); + _(CDNR_GETSTATS, READWRITE, struct_cdnr_get_stats_sz); + _(CDNR_ADD_ELEM, READWRITE, struct_cdnr_add_element_sz); + _(CDNR_DEL_ELEM, READ, struct_cdnr_delete_element_sz); + _(CDNR_ADD_TBM, READWRITE, struct_cdnr_add_tbmeter_sz); + _(CDNR_MOD_TBM, READ, struct_cdnr_modify_tbmeter_sz); + _(CDNR_TBM_STATS, READWRITE, struct_cdnr_tbmeter_stats_sz); + _(CDNR_ADD_TCM, READWRITE, struct_cdnr_add_trtcm_sz); + _(CDNR_MOD_TCM, READWRITE, struct_cdnr_modify_trtcm_sz); + _(CDNR_TCM_STATS, READWRITE, struct_cdnr_tcm_stats_sz); + _(CDNR_ADD_TSW, READWRITE, struct_cdnr_add_tswtcm_sz); + _(CDNR_MOD_TSW, READWRITE, struct_cdnr_modify_tswtcm_sz); + /* Entries from file: altq/altq_fifoq.h */ + _(FIFOQ_CONFIG, READWRITE, struct_fifoq_conf_sz); + _(FIFOQ_GETSTATS, READWRITE, struct_fifoq_getstats_sz); + /* Entries from file: altq/altq_hfsc.h */ + _(HFSC_CLEAR_HIERARCHY, READ, struct_hfsc_interface_sz); + _(HFSC_ADD_CLASS, READWRITE, struct_hfsc_add_class_sz); + _(HFSC_GETSTATS, READWRITE, struct_hfsc_class_stats_sz); + /* Entries from file: altq/altq_jobs.h */ + _(JOBS_IF_ATTACH, READ, struct_jobs_attach_sz); + _(JOBS_IF_DETACH, READ, struct_jobs_interface_sz); + _(JOBS_ENABLE, READ, struct_jobs_interface_sz); + _(JOBS_DISABLE, READ, struct_jobs_interface_sz); + _(JOBS_CLEAR, READ, struct_jobs_interface_sz); + _(JOBS_ADD_CLASS, READWRITE, struct_jobs_add_class_sz); + _(JOBS_MOD_CLASS, READ, struct_jobs_modify_class_sz); + /* Entries from file: altq/altq_priq.h */ + _(PRIQ_IF_ATTACH, READ, struct_priq_interface_sz); + _(PRIQ_CLEAR, READ, struct_priq_interface_sz); + _(PRIQ_ADD_CLASS, READWRITE, struct_priq_add_class_sz); + _(PRIQ_DEL_CLASS, READ, struct_priq_delete_class_sz); + _(PRIQ_MOD_CLASS, READ, struct_priq_modify_class_sz); + _(PRIQ_ADD_FILTER, READWRITE, struct_priq_add_filter_sz); + _(PRIQ_DEL_FILTER, READ, struct_priq_delete_filter_sz); + _(PRIQ_GETSTATS, READWRITE, struct_priq_class_stats_sz); + /* Entries from file: altq/altq_red.h */ + _(RED_CONFIG, READWRITE, struct_red_conf_sz); + _(RED_GETSTATS, READWRITE, struct_red_stats_sz); + _(RED_SETDEFAULTS, READ, struct_redparams_sz); + /* Entries from file: altq/altq_rio.h */ + _(RIO_CONFIG, READWRITE, struct_rio_conf_sz); + _(RIO_GETSTATS, READWRITE, struct_rio_stats_sz); + _(RIO_SETDEFAULTS, READ, struct_redparams_sz); + /* Entries from file: altq/altq_wfq.h */ + _(WFQ_CONFIG, READWRITE, struct_wfq_conf_sz); + _(WFQ_GET_QID, READWRITE, struct_wfq_getqid_sz); + _(WFQ_SET_WEIGHT, READWRITE, struct_wfq_setweight_sz); + /* Entries from file: crypto/cryptodev.h */ + _(CRIOGET, READWRITE, sizeof(u32)); + _(CIOCFSESSION, READ, sizeof(u32)); + _(CIOCKEY, READWRITE, struct_crypt_kop_sz); + _(CIOCNFKEYM, READWRITE, struct_crypt_mkop_sz); + _(CIOCNFSESSION, READ, struct_crypt_sfop_sz); + _(CIOCNCRYPTRETM, READWRITE, struct_cryptret_sz); + _(CIOCNCRYPTRET, READWRITE, struct_crypt_result_sz); + _(CIOCGSESSION, READWRITE, struct_session_op_sz); + _(CIOCNGSESSION, READWRITE, struct_crypt_sgop_sz); + _(CIOCCRYPT, READWRITE, struct_crypt_op_sz); + _(CIOCNCRYPTM, READWRITE, struct_crypt_mop_sz); + _(CIOCASYMFEAT, WRITE, sizeof(u32)); + /* Entries from file: dev/apm/apmio.h */ + _(APM_IOC_REJECT, READ, struct_apm_event_info_sz); + _(OAPM_IOC_GETPOWER, WRITE, struct_apm_power_info_sz); + _(APM_IOC_GETPOWER, READWRITE, struct_apm_power_info_sz); + _(APM_IOC_NEXTEVENT, WRITE, struct_apm_event_info_sz); + _(APM_IOC_DEV_CTL, READ, struct_apm_ctl_sz); + /* Entries from file: dev/dm/netbsd-dm.h */ + _(NETBSD_DM_IOCTL, READWRITE, struct_plistref_sz); + /* Entries from file: dev/dmover/dmover_io.h */ + _(DMIO_SETFUNC, READ, struct_dmio_setfunc_sz); + /* Entries from file: dev/dtv/dtvio_demux.h */ + _(DMX_START, NONE, 0); + _(DMX_STOP, NONE, 0); + _(DMX_SET_FILTER, READ, struct_dmx_sct_filter_params_sz); + _(DMX_SET_PES_FILTER, READ, struct_dmx_pes_filter_params_sz); + _(DMX_SET_BUFFER_SIZE, NONE, 0); + _(DMX_GET_STC, READWRITE, struct_dmx_stc_sz); + _(DMX_ADD_PID, READ, sizeof(u16)); + _(DMX_REMOVE_PID, READ, sizeof(u16)); + _(DMX_GET_CAPS, WRITE, struct_dmx_caps_sz); + _(DMX_SET_SOURCE, READ, enum_dmx_source_sz); + /* Entries from file: dev/dtv/dtvio_frontend.h */ + _(FE_READ_STATUS, WRITE, enum_fe_status_sz); + _(FE_READ_BER, WRITE, sizeof(u32)); + _(FE_READ_SNR, WRITE, sizeof(u16)); + _(FE_READ_SIGNAL_STRENGTH, WRITE, sizeof(u16)); + _(FE_READ_UNCORRECTED_BLOCKS, WRITE, sizeof(u32)); + _(FE_SET_FRONTEND, READWRITE, struct_dvb_frontend_parameters_sz); + _(FE_GET_FRONTEND, WRITE, struct_dvb_frontend_parameters_sz); + _(FE_GET_EVENT, WRITE, struct_dvb_frontend_event_sz); + _(FE_GET_INFO, WRITE, struct_dvb_frontend_info_sz); + _(FE_DISEQC_RESET_OVERLOAD, NONE, 0); + _(FE_DISEQC_SEND_MASTER_CMD, READ, struct_dvb_diseqc_master_cmd_sz); + _(FE_DISEQC_RECV_SLAVE_REPLY, WRITE, struct_dvb_diseqc_slave_reply_sz); + _(FE_DISEQC_SEND_BURST, READ, enum_fe_sec_mini_cmd_sz); + _(FE_SET_TONE, READ, enum_fe_sec_tone_mode_sz); + _(FE_SET_VOLTAGE, READ, enum_fe_sec_voltage_sz); + _(FE_ENABLE_HIGH_LNB_VOLTAGE, READ, sizeof(int)); + _(FE_SET_FRONTEND_TUNE_MODE, READ, sizeof(unsigned int)); + _(FE_DISHNETWORK_SEND_LEGACY_CMD, READ, sizeof(unsigned long)); + /* Entries from file: dev/hdaudio/hdaudioio.h */ + _(HDAUDIO_FGRP_INFO, READWRITE, struct_plistref_sz); + _(HDAUDIO_FGRP_GETCONFIG, READWRITE, struct_plistref_sz); + _(HDAUDIO_FGRP_SETCONFIG, READWRITE, struct_plistref_sz); + _(HDAUDIO_FGRP_WIDGET_INFO, READWRITE, struct_plistref_sz); + _(HDAUDIO_FGRP_CODEC_INFO, READWRITE, struct_plistref_sz); + _(HDAUDIO_AFG_WIDGET_INFO, READWRITE, struct_plistref_sz); + _(HDAUDIO_AFG_CODEC_INFO, READWRITE, struct_plistref_sz); + /* Entries from file: dev/hdmicec/hdmicecio.h */ + _(CEC_GET_PHYS_ADDR, WRITE, sizeof(u16)); + _(CEC_GET_LOG_ADDRS, WRITE, sizeof(u16)); + _(CEC_SET_LOG_ADDRS, READ, sizeof(u16)); + _(CEC_GET_VENDOR_ID, WRITE, sizeof(u32)); + /* Entries from file: dev/hpc/hpcfbio.h */ + _(HPCFBIO_GCONF, READWRITE, struct_hpcfb_fbconf_sz); + _(HPCFBIO_SCONF, READ, struct_hpcfb_fbconf_sz); + _(HPCFBIO_GDSPCONF, READWRITE, struct_hpcfb_dspconf_sz); + _(HPCFBIO_SDSPCONF, READ, struct_hpcfb_dspconf_sz); + _(HPCFBIO_GOP, WRITE, struct_hpcfb_dsp_op_sz); + _(HPCFBIO_SOP, READWRITE, struct_hpcfb_dsp_op_sz); + /* Entries from file: dev/i2o/iopio.h */ + _(IOPIOCPT, READWRITE, struct_ioppt_sz); + _(IOPIOCGLCT, READWRITE, struct_iovec_sz); + _(IOPIOCGSTATUS, READWRITE, struct_iovec_sz); + _(IOPIOCRECONFIG, NONE, 0); + _(IOPIOCGTIDMAP, READWRITE, struct_iovec_sz); + /* Entries from file: dev/ic/athioctl.h */ + _(SIOCGATHSTATS, READWRITE, struct_ifreq_sz); + _(SIOCGATHDIAG, READWRITE, struct_ath_diag_sz); + /* Entries from file: dev/ic/bt8xx.h */ + _(METEORCAPTUR, READ, sizeof(int)); + _(METEORCAPFRM, READ, struct_meteor_capframe_sz); + _(METEORSETGEO, READ, struct_meteor_geomet_sz); + _(METEORGETGEO, WRITE, struct_meteor_geomet_sz); + _(METEORSTATUS, WRITE, sizeof(unsigned short)); + _(METEORSHUE, READ, sizeof(signed char)); + _(METEORGHUE, WRITE, sizeof(signed char)); + _(METEORSFMT, READ, sizeof(unsigned int)); + _(METEORGFMT, WRITE, sizeof(unsigned int)); + _(METEORSINPUT, READ, sizeof(unsigned int)); + _(METEORGINPUT, WRITE, sizeof(unsigned int)); + _(METEORSCHCV, READ, sizeof(unsigned char)); + _(METEORGCHCV, WRITE, sizeof(unsigned char)); + _(METEORSCOUNT, READ, struct_meteor_counts_sz); + _(METEORGCOUNT, WRITE, struct_meteor_counts_sz); + _(METEORSFPS, READ, sizeof(unsigned short)); + _(METEORGFPS, WRITE, sizeof(unsigned short)); + _(METEORSSIGNAL, READ, sizeof(unsigned int)); + _(METEORGSIGNAL, WRITE, sizeof(unsigned int)); + _(METEORSVIDEO, READ, struct_meteor_video_sz); + _(METEORGVIDEO, WRITE, struct_meteor_video_sz); + _(METEORSBRIG, READ, sizeof(unsigned char)); + _(METEORGBRIG, WRITE, sizeof(unsigned char)); + _(METEORSCSAT, READ, sizeof(unsigned char)); + _(METEORGCSAT, WRITE, sizeof(unsigned char)); + _(METEORSCONT, READ, sizeof(unsigned char)); + _(METEORGCONT, WRITE, sizeof(unsigned char)); + _(METEORSHWS, READ, sizeof(unsigned char)); + _(METEORGHWS, WRITE, sizeof(unsigned char)); + _(METEORSVWS, READ, sizeof(unsigned char)); + _(METEORGVWS, WRITE, sizeof(unsigned char)); + _(METEORSTS, READ, sizeof(unsigned char)); + _(METEORGTS, WRITE, sizeof(unsigned char)); + _(TVTUNER_SETCHNL, READ, sizeof(unsigned int)); + _(TVTUNER_GETCHNL, WRITE, sizeof(unsigned int)); + _(TVTUNER_SETTYPE, READ, sizeof(unsigned int)); + _(TVTUNER_GETTYPE, WRITE, sizeof(unsigned int)); + _(TVTUNER_GETSTATUS, WRITE, sizeof(unsigned int)); + _(TVTUNER_SETFREQ, READ, sizeof(unsigned int)); + _(TVTUNER_GETFREQ, WRITE, sizeof(unsigned int)); + _(TVTUNER_SETAFC, READ, sizeof(int)); + _(TVTUNER_GETAFC, WRITE, sizeof(int)); + _(RADIO_SETMODE, READ, sizeof(unsigned int)); + _(RADIO_GETMODE, WRITE, sizeof(unsigned char)); + _(RADIO_SETFREQ, READ, sizeof(unsigned int)); + _(RADIO_GETFREQ, WRITE, sizeof(unsigned int)); + _(METEORSACTPIXFMT, READ, sizeof(int)); + _(METEORGACTPIXFMT, WRITE, sizeof(int)); + _(METEORGSUPPIXFMT, READWRITE, struct_meteor_pixfmt_sz); + _(TVTUNER_GETCHNLSET, READWRITE, struct_bktr_chnlset_sz); + _(REMOTE_GETKEY, WRITE, struct_bktr_remote_sz); + /* Entries from file: dev/ic/icp_ioctl.h */ + _(GDT_IOCTL_GENERAL, READWRITE, struct_gdt_ucmd_sz); + _(GDT_IOCTL_DRVERS, WRITE, sizeof(int)); + _(GDT_IOCTL_CTRTYPE, READWRITE, struct_gdt_ctrt_sz); + _(GDT_IOCTL_OSVERS, WRITE, struct_gdt_osv_sz); + _(GDT_IOCTL_CTRCNT, WRITE, sizeof(int)); + _(GDT_IOCTL_EVENT, READWRITE, struct_gdt_event_sz); + _(GDT_IOCTL_STATIST, WRITE, struct_gdt_statist_sz); + _(GDT_IOCTL_RESCAN, READWRITE, struct_gdt_rescan_sz); + /* Entries from file: dev/ic/isp_ioctl.h */ + _(ISP_SDBLEV, READWRITE, sizeof(int)); + _(ISP_RESETHBA, NONE, 0); + _(ISP_RESCAN, NONE, 0); + _(ISP_SETROLE, READWRITE, sizeof(int)); + _(ISP_GETROLE, WRITE, sizeof(int)); + _(ISP_GET_STATS, WRITE, struct_isp_stats_sz); + _(ISP_CLR_STATS, NONE, 0); + _(ISP_FC_LIP, NONE, 0); + _(ISP_FC_GETDINFO, READWRITE, struct_isp_fc_device_sz); + _(ISP_GET_FW_CRASH_DUMP, NONE, 0); + _(ISP_FORCE_CRASH_DUMP, NONE, 0); + _(ISP_FC_GETHINFO, READWRITE, struct_isp_hba_device_sz); + _(ISP_TSK_MGMT, READWRITE, struct_isp_fc_tsk_mgmt_sz); + _(ISP_FC_GETDLIST, NONE, 0); + /* Entries from file: dev/ic/mlxio.h */ + _(MLXD_STATUS, WRITE, sizeof(int)); + _(MLXD_CHECKASYNC, WRITE, sizeof(int)); + _(MLXD_DETACH, READ, sizeof(int)); + _(MLX_RESCAN_DRIVES, NONE, 0); + _(MLX_PAUSE_CHANNEL, READ, struct_mlx_pause_sz); + _(MLX_COMMAND, READWRITE, struct_mlx_usercommand_sz); + _(MLX_REBUILDASYNC, READWRITE, struct_mlx_rebuild_request_sz); + _(MLX_REBUILDSTAT, WRITE, struct_mlx_rebuild_status_sz); + _(MLX_GET_SYSDRIVE, READWRITE, sizeof(int)); + _(MLX_GET_CINFO, WRITE, struct_mlx_cinfo_sz); + /* Entries from file: dev/ic/nvmeio.h */ + _(NVME_PASSTHROUGH_CMD, READWRITE, struct_nvme_pt_command_sz); + /* Entries from file: dev/ic/qemufwcfgio.h */ + _(FWCFGIO_SET_INDEX, READ, sizeof(u16)); + /* Entries from file: dev/ir/irdaio.h */ + _(IRDA_RESET_PARAMS, NONE, 0); + _(IRDA_SET_PARAMS, READ, struct_irda_params_sz); + _(IRDA_GET_SPEEDMASK, WRITE, sizeof(unsigned int)); + _(IRDA_GET_TURNAROUNDMASK, WRITE, sizeof(unsigned int)); + _(IRFRAMETTY_GET_DEVICE, WRITE, sizeof(unsigned int)); + _(IRFRAMETTY_GET_DONGLE, WRITE, sizeof(unsigned int)); + _(IRFRAMETTY_SET_DONGLE, READ, sizeof(unsigned int)); + /* Entries from file: dev/isa/isvio.h */ + _(ISV_CMD, READWRITE, struct_isv_cmd_sz); + /* Entries from file: dev/isa/wtreg.h */ + _(WTQICMD, NONE, 0); + /* Entries from file: dev/iscsi/iscsi_ioctl.h */ + _(ISCSI_GET_VERSION, READWRITE, struct_iscsi_get_version_parameters_sz); + _(ISCSI_LOGIN, READWRITE, struct_iscsi_login_parameters_sz); + _(ISCSI_LOGOUT, READWRITE, struct_iscsi_logout_parameters_sz); + _(ISCSI_ADD_CONNECTION, READWRITE, struct_iscsi_login_parameters_sz); + _(ISCSI_RESTORE_CONNECTION, READWRITE, struct_iscsi_login_parameters_sz); + _(ISCSI_REMOVE_CONNECTION, READWRITE, struct_iscsi_remove_parameters_sz); + _(ISCSI_CONNECTION_STATUS, READWRITE, struct_iscsi_conn_status_parameters_sz); + _(ISCSI_SEND_TARGETS, READWRITE, struct_iscsi_send_targets_parameters_sz); + _(ISCSI_SET_NODE_NAME, READWRITE, struct_iscsi_set_node_name_parameters_sz); + _(ISCSI_IO_COMMAND, READWRITE, struct_iscsi_iocommand_parameters_sz); + _(ISCSI_REGISTER_EVENT, READWRITE, struct_iscsi_register_event_parameters_sz); + _(ISCSI_DEREGISTER_EVENT, READWRITE, + struct_iscsi_register_event_parameters_sz); + _(ISCSI_WAIT_EVENT, READWRITE, struct_iscsi_wait_event_parameters_sz); + _(ISCSI_POLL_EVENT, READWRITE, struct_iscsi_wait_event_parameters_sz); + /* Entries from file: dev/ofw/openfirmio.h */ + _(OFIOCGET, READWRITE, struct_ofiocdesc_sz); + _(OFIOCSET, READ, struct_ofiocdesc_sz); + _(OFIOCNEXTPROP, READWRITE, struct_ofiocdesc_sz); + _(OFIOCGETOPTNODE, WRITE, sizeof(int)); + _(OFIOCGETNEXT, READWRITE, sizeof(int)); + _(OFIOCGETCHILD, READWRITE, sizeof(int)); + _(OFIOCFINDDEVICE, READWRITE, struct_ofiocdesc_sz); + /* Entries from file: dev/pci/amrio.h */ + _(AMR_IO_VERSION, WRITE, sizeof(int)); + _(AMR_IO_COMMAND, READWRITE, struct_amr_user_ioctl_sz); + /* Entries from file: dev/pci/mlyio.h */ + _(MLYIO_COMMAND, READWRITE, struct_mly_user_command_sz); + _(MLYIO_HEALTH, READ, struct_mly_user_health_sz); + /* Entries from file: dev/pci/pciio.h */ + _(PCI_IOC_CFGREAD, READWRITE, struct_pciio_cfgreg_sz); + _(PCI_IOC_CFGWRITE, READ, struct_pciio_cfgreg_sz); + _(PCI_IOC_BDF_CFGREAD, READWRITE, struct_pciio_bdf_cfgreg_sz); + _(PCI_IOC_BDF_CFGWRITE, READ, struct_pciio_bdf_cfgreg_sz); + _(PCI_IOC_BUSINFO, WRITE, struct_pciio_businfo_sz); + _(PCI_IOC_DRVNAME, READWRITE, struct_pciio_drvname_sz); + _(PCI_IOC_DRVNAMEONBUS, READWRITE, struct_pciio_drvnameonbus_sz); + /* Entries from file: dev/pci/tweio.h */ + _(TWEIO_COMMAND, READWRITE, struct_twe_usercommand_sz); + _(TWEIO_STATS, READWRITE, union_twe_statrequest_sz); + _(TWEIO_AEN_POLL, WRITE, sizeof(int)); + _(TWEIO_AEN_WAIT, WRITE, sizeof(int)); + _(TWEIO_SET_PARAM, READ, struct_twe_paramcommand_sz); + _(TWEIO_GET_PARAM, READ, struct_twe_paramcommand_sz); + _(TWEIO_RESET, NONE, 0); + _(TWEIO_ADD_UNIT, READ, struct_twe_drivecommand_sz); + _(TWEIO_DEL_UNIT, READ, struct_twe_drivecommand_sz); + /* Entries from file: dev/pcmcia/if_cnwioctl.h */ + _(SIOCSCNWDOMAIN, READ, struct_ifreq_sz); + _(SIOCGCNWDOMAIN, READWRITE, struct_ifreq_sz); + _(SIOCSCNWKEY, READWRITE, struct_ifreq_sz); + _(SIOCGCNWSTATUS, READWRITE, struct_cnwstatus_sz); + _(SIOCGCNWSTATS, READWRITE, struct_cnwistats_sz); + _(SIOCGCNWTRAIL, READWRITE, struct_cnwitrail_sz); + /* Entries from file: dev/pcmcia/if_rayreg.h */ + _(SIOCGRAYSIGLEV, READWRITE, struct_ifreq_sz); + /* Entries from file: dev/raidframe/raidframeio.h */ + _(RAIDFRAME_SHUTDOWN, NONE, 0); + _(RAIDFRAME_TUR, READ, sizeof(u64)); + _(RAIDFRAME_FAIL_DISK, READ, struct_rf_recon_req_sz); + _(RAIDFRAME_CHECK_RECON_STATUS, READWRITE, sizeof(int)); + _(RAIDFRAME_REWRITEPARITY, NONE, 0); + _(RAIDFRAME_COPYBACK, NONE, 0); + _(RAIDFRAME_SPARET_WAIT, WRITE, struct_RF_SparetWait_sz); + _(RAIDFRAME_SEND_SPARET, READ, sizeof(uptr)); + _(RAIDFRAME_ABORT_SPARET_WAIT, NONE, 0); + _(RAIDFRAME_START_ATRACE, NONE, 0); + _(RAIDFRAME_STOP_ATRACE, NONE, 0); + _(RAIDFRAME_GET_SIZE, WRITE, sizeof(int)); + _(RAIDFRAME_RESET_ACCTOTALS, NONE, 0); + _(RAIDFRAME_KEEP_ACCTOTALS, READ, sizeof(int)); + _(RAIDFRAME_GET_COMPONENT_LABEL, READWRITE, struct_RF_ComponentLabel_sz); + _(RAIDFRAME_SET_COMPONENT_LABEL, READ, struct_RF_ComponentLabel_sz); + _(RAIDFRAME_INIT_LABELS, READ, struct_RF_ComponentLabel_sz); + _(RAIDFRAME_ADD_HOT_SPARE, READ, struct_RF_SingleComponent_sz); + _(RAIDFRAME_REMOVE_HOT_SPARE, READ, struct_RF_SingleComponent_sz); + _(RAIDFRAME_REBUILD_IN_PLACE, READ, struct_RF_SingleComponent_sz); + _(RAIDFRAME_CHECK_PARITY, READWRITE, sizeof(int)); + _(RAIDFRAME_CHECK_PARITYREWRITE_STATUS, READWRITE, sizeof(int)); + _(RAIDFRAME_CHECK_COPYBACK_STATUS, READWRITE, sizeof(int)); + _(RAIDFRAME_SET_AUTOCONFIG, READWRITE, sizeof(int)); + _(RAIDFRAME_SET_ROOT, READWRITE, sizeof(int)); + _(RAIDFRAME_DELETE_COMPONENT, READ, struct_RF_SingleComponent_sz); + _(RAIDFRAME_INCORPORATE_HOT_SPARE, READ, struct_RF_SingleComponent_sz); + _(RAIDFRAME_CHECK_RECON_STATUS_EXT, READWRITE, struct_RF_ProgressInfo_sz); + _(RAIDFRAME_CHECK_PARITYREWRITE_STATUS_EXT, READWRITE, + struct_RF_ProgressInfo_sz); + _(RAIDFRAME_CHECK_COPYBACK_STATUS_EXT, READWRITE, struct_RF_ProgressInfo_sz); + _(RAIDFRAME_PARITYMAP_STATUS, WRITE, struct_rf_pmstat_sz); + _(RAIDFRAME_PARITYMAP_GET_DISABLE, WRITE, sizeof(int)); + _(RAIDFRAME_PARITYMAP_SET_DISABLE, READ, sizeof(int)); + _(RAIDFRAME_PARITYMAP_SET_PARAMS, READ, struct_rf_pmparams_sz); + _(RAIDFRAME_SET_LAST_UNIT, READ, sizeof(int)); + _(RAIDFRAME_GET_INFO, READWRITE, sizeof(uptr)); + _(RAIDFRAME_CONFIGURE, READ, sizeof(uptr)); + /* Entries from file: dev/sbus/mbppio.h */ + _(MBPPIOCSPARAM, READ, struct_mbpp_param_sz); + _(MBPPIOCGPARAM, WRITE, struct_mbpp_param_sz); + _(MBPPIOCGSTAT, WRITE, sizeof(int)); + /* Entries from file: dev/scsipi/ses.h */ + _(SESIOC_GETNOBJ, NONE, 0); + _(SESIOC_GETOBJMAP, NONE, 0); + _(SESIOC_GETENCSTAT, NONE, 0); + _(SESIOC_SETENCSTAT, NONE, 0); + _(SESIOC_GETOBJSTAT, NONE, 0); + _(SESIOC_SETOBJSTAT, NONE, 0); + _(SESIOC_GETTEXT, NONE, 0); + _(SESIOC_INIT, NONE, 0); + /* Entries from file: dev/sun/disklabel.h */ + _(SUN_DKIOCGGEOM, WRITE, struct_sun_dkgeom_sz); + _(SUN_DKIOCINFO, WRITE, struct_sun_dkctlr_sz); + _(SUN_DKIOCGPART, WRITE, struct_sun_dkpart_sz); + /* Entries from file: dev/sun/fbio.h */ + _(FBIOGTYPE, WRITE, struct_fbtype_sz); + _(FBIOPUTCMAP, READ, struct_fbcmap_sz); + _(FBIOGETCMAP, READ, struct_fbcmap_sz); + _(FBIOGATTR, WRITE, struct_fbgattr_sz); + _(FBIOSVIDEO, READ, sizeof(int)); + _(FBIOGVIDEO, WRITE, sizeof(int)); + _(FBIOSCURSOR, READ, struct_fbcursor_sz); + _(FBIOGCURSOR, READWRITE, struct_fbcursor_sz); + _(FBIOSCURPOS, READ, struct_fbcurpos_sz); + _(FBIOGCURPOS, READ, struct_fbcurpos_sz); + _(FBIOGCURMAX, WRITE, struct_fbcurpos_sz); + /* Entries from file: dev/sun/kbio.h */ + _(KIOCTRANS, READ, sizeof(int)); + _(KIOCSETKEY, READWRITE, struct_okiockey_sz); + _(KIOCGETKEY, READWRITE, struct_okiockey_sz); + _(KIOCGTRANS, WRITE, sizeof(int)); + _(KIOCCMD, READ, sizeof(int)); + _(KIOCTYPE, WRITE, sizeof(int)); + _(KIOCSDIRECT, READ, sizeof(int)); + _(KIOCSKEY, READ, struct_kiockeymap_sz); + _(KIOCGKEY, READWRITE, struct_kiockeymap_sz); + _(KIOCSLED, READ, sizeof(char)); + _(KIOCGLED, WRITE, sizeof(char)); + _(KIOCLAYOUT, WRITE, sizeof(int)); + /* Entries from file: dev/sun/vuid_event.h */ + _(VUIDSFORMAT, READ, sizeof(int)); + _(VUIDGFORMAT, WRITE, sizeof(int)); + /* Entries from file: dev/tc/sticio.h */ + _(STICIO_GXINFO, WRITE, struct_stic_xinfo_sz); + _(STICIO_RESET, NONE, 0); + _(STICIO_STARTQ, NONE, 0); + _(STICIO_STOPQ, NONE, 0); + /* Entries from file: dev/usb/ukyopon.h */ + _(UKYOPON_IDENTIFY, WRITE, struct_ukyopon_identify_sz); + /* Entries from file: dev/usb/usb.h */ + _(USB_REQUEST, READWRITE, struct_usb_ctl_request_sz); + _(USB_SETDEBUG, READ, sizeof(int)); + _(USB_DISCOVER, NONE, 0); + _(USB_DEVICEINFO, READWRITE, struct_usb_device_info_sz); + _(USB_DEVICEINFO_OLD, READWRITE, struct_usb_device_info_old_sz); + _(USB_DEVICESTATS, WRITE, struct_usb_device_stats_sz); + _(USB_GET_REPORT_DESC, WRITE, struct_usb_ctl_report_desc_sz); + _(USB_SET_IMMED, READ, sizeof(int)); + _(USB_GET_REPORT, READWRITE, struct_usb_ctl_report_sz); + _(USB_SET_REPORT, READ, struct_usb_ctl_report_sz); + _(USB_GET_REPORT_ID, WRITE, sizeof(int)); + _(USB_GET_CONFIG, WRITE, sizeof(int)); + _(USB_SET_CONFIG, READ, sizeof(int)); + _(USB_GET_ALTINTERFACE, READWRITE, struct_usb_alt_interface_sz); + _(USB_SET_ALTINTERFACE, READWRITE, struct_usb_alt_interface_sz); + _(USB_GET_NO_ALT, READWRITE, struct_usb_alt_interface_sz); + _(USB_GET_DEVICE_DESC, WRITE, struct_usb_device_descriptor_sz); + _(USB_GET_CONFIG_DESC, READWRITE, struct_usb_config_desc_sz); + _(USB_GET_INTERFACE_DESC, READWRITE, struct_usb_interface_desc_sz); + _(USB_GET_ENDPOINT_DESC, READWRITE, struct_usb_endpoint_desc_sz); + _(USB_GET_FULL_DESC, READWRITE, struct_usb_full_desc_sz); + _(USB_GET_STRING_DESC, READWRITE, struct_usb_string_desc_sz); + _(USB_DO_REQUEST, READWRITE, struct_usb_ctl_request_sz); + _(USB_GET_DEVICEINFO, WRITE, struct_usb_device_info_sz); + _(USB_GET_DEVICEINFO_OLD, WRITE, struct_usb_device_info_old_sz); + _(USB_SET_SHORT_XFER, READ, sizeof(int)); + _(USB_SET_TIMEOUT, READ, sizeof(int)); + _(USB_SET_BULK_RA, READ, sizeof(int)); + _(USB_SET_BULK_WB, READ, sizeof(int)); + _(USB_SET_BULK_RA_OPT, READ, struct_usb_bulk_ra_wb_opt_sz); + _(USB_SET_BULK_WB_OPT, READ, struct_usb_bulk_ra_wb_opt_sz); + _(USB_GET_CM_OVER_DATA, WRITE, sizeof(int)); + _(USB_SET_CM_OVER_DATA, READ, sizeof(int)); + /* Entries from file: dev/usb/utoppy.h */ + _(UTOPPYIOTURBO, READ, sizeof(int)); + _(UTOPPYIOREBOOT, NONE, 0); + _(UTOPPYIOSTATS, WRITE, struct_utoppy_stats_sz); + _(UTOPPYIORENAME, READ, struct_utoppy_rename_sz); + _(UTOPPYIOMKDIR, READ, sizeof(uptr)); + _(UTOPPYIODELETE, READ, sizeof(uptr)); + _(UTOPPYIOREADDIR, READ, sizeof(uptr)); + _(UTOPPYIOREADFILE, READ, struct_utoppy_readfile_sz); + _(UTOPPYIOWRITEFILE, READ, struct_utoppy_writefile_sz); + /* Entries from file: dev/vme/xio.h */ + _(DIOSXDCMD, READWRITE, struct_xd_iocmd_sz); + /* Entries from file: dev/wscons/wsdisplay_usl_io.h */ + _(VT_OPENQRY, WRITE, sizeof(int)); + _(VT_SETMODE, READ, struct_vt_mode_sz); + _(VT_GETMODE, WRITE, struct_vt_mode_sz); + _(VT_RELDISP, NONE, 0); + _(VT_ACTIVATE, NONE, 0); + _(VT_WAITACTIVE, NONE, 0); + _(VT_GETACTIVE, WRITE, sizeof(int)); + _(VT_GETSTATE, WRITE, struct_vt_stat_sz); + _(KDGETKBENT, READWRITE, struct_kbentry_sz); + _(KDGKBMODE, WRITE, sizeof(int)); + _(KDSKBMODE, NONE, 0); + _(KDMKTONE, NONE, 0); + _(KDSETMODE, NONE, 0); + _(KDENABIO, NONE, 0); + _(KDDISABIO, NONE, 0); + _(KDGKBTYPE, WRITE, sizeof(char)); + _(KDGETLED, WRITE, sizeof(int)); + _(KDSETLED, NONE, 0); + _(KDSETRAD, NONE, 0); + _(VGAPCVTID, READWRITE, struct_pcvtid_sz); + _(CONS_GETVERS, WRITE, sizeof(int)); + /* Entries from file: dev/wscons/wsconsio.h */ + _(WSKBDIO_GTYPE, WRITE, sizeof(unsigned int)); + _(WSKBDIO_BELL, NONE, 0); + _(WSKBDIO_COMPLEXBELL, READ, struct_wskbd_bell_data_sz); + _(WSKBDIO_SETBELL, READ, struct_wskbd_bell_data_sz); + _(WSKBDIO_GETBELL, WRITE, struct_wskbd_bell_data_sz); + _(WSKBDIO_SETDEFAULTBELL, READ, struct_wskbd_bell_data_sz); + _(WSKBDIO_GETDEFAULTBELL, WRITE, struct_wskbd_bell_data_sz); + _(WSKBDIO_SETKEYREPEAT, READ, struct_wskbd_keyrepeat_data_sz); + _(WSKBDIO_GETKEYREPEAT, WRITE, struct_wskbd_keyrepeat_data_sz); + _(WSKBDIO_SETDEFAULTKEYREPEAT, READ, struct_wskbd_keyrepeat_data_sz); + _(WSKBDIO_GETDEFAULTKEYREPEAT, WRITE, struct_wskbd_keyrepeat_data_sz); + _(WSKBDIO_SETLEDS, READ, sizeof(int)); + _(WSKBDIO_GETLEDS, WRITE, sizeof(int)); + _(WSKBDIO_GETMAP, READWRITE, struct_wskbd_map_data_sz); + _(WSKBDIO_SETMAP, READ, struct_wskbd_map_data_sz); + _(WSKBDIO_GETENCODING, WRITE, sizeof(int)); + _(WSKBDIO_SETENCODING, READ, sizeof(int)); + _(WSKBDIO_SETMODE, READ, sizeof(int)); + _(WSKBDIO_GETMODE, WRITE, sizeof(int)); + _(WSKBDIO_SETKEYCLICK, READ, sizeof(int)); + _(WSKBDIO_GETKEYCLICK, WRITE, sizeof(int)); + _(WSKBDIO_GETSCROLL, WRITE, struct_wskbd_scroll_data_sz); + _(WSKBDIO_SETSCROLL, READ, struct_wskbd_scroll_data_sz); + _(WSKBDIO_SETVERSION, READ, sizeof(int)); + _(WSMOUSEIO_GTYPE, WRITE, sizeof(unsigned int)); + _(WSMOUSEIO_SRES, READ, sizeof(unsigned int)); + _(WSMOUSEIO_SSCALE, READ, sizeof(unsigned int)); + _(WSMOUSEIO_SRATE, READ, sizeof(unsigned int)); + _(WSMOUSEIO_SCALIBCOORDS, READ, struct_wsmouse_calibcoords_sz); + _(WSMOUSEIO_GCALIBCOORDS, WRITE, struct_wsmouse_calibcoords_sz); + _(WSMOUSEIO_GETID, READWRITE, struct_wsmouse_id_sz); + _(WSMOUSEIO_GETREPEAT, WRITE, struct_wsmouse_repeat_sz); + _(WSMOUSEIO_SETREPEAT, READ, struct_wsmouse_repeat_sz); + _(WSMOUSEIO_SETVERSION, READ, sizeof(int)); + _(WSDISPLAYIO_GTYPE, WRITE, sizeof(unsigned int)); + _(WSDISPLAYIO_GINFO, WRITE, struct_wsdisplay_fbinfo_sz); + _(WSDISPLAYIO_GETCMAP, READ, struct_wsdisplay_cmap_sz); + _(WSDISPLAYIO_PUTCMAP, READ, struct_wsdisplay_cmap_sz); + _(WSDISPLAYIO_GVIDEO, WRITE, sizeof(unsigned int)); + _(WSDISPLAYIO_SVIDEO, READ, sizeof(unsigned int)); + _(WSDISPLAYIO_GCURPOS, WRITE, struct_wsdisplay_curpos_sz); + _(WSDISPLAYIO_SCURPOS, READ, struct_wsdisplay_curpos_sz); + _(WSDISPLAYIO_GCURMAX, WRITE, struct_wsdisplay_curpos_sz); + _(WSDISPLAYIO_GCURSOR, READWRITE, struct_wsdisplay_cursor_sz); + _(WSDISPLAYIO_SCURSOR, READ, struct_wsdisplay_cursor_sz); + _(WSDISPLAYIO_GMODE, WRITE, sizeof(unsigned int)); + _(WSDISPLAYIO_SMODE, READ, sizeof(unsigned int)); + _(WSDISPLAYIO_LDFONT, READ, struct_wsdisplay_font_sz); + _(WSDISPLAYIO_ADDSCREEN, READ, struct_wsdisplay_addscreendata_sz); + _(WSDISPLAYIO_DELSCREEN, READ, struct_wsdisplay_delscreendata_sz); + _(WSDISPLAYIO_SFONT, READ, struct_wsdisplay_usefontdata_sz); + _(_O_WSDISPLAYIO_SETKEYBOARD, READWRITE, struct_wsdisplay_kbddata_sz); + _(WSDISPLAYIO_GETPARAM, READWRITE, struct_wsdisplay_param_sz); + _(WSDISPLAYIO_SETPARAM, READWRITE, struct_wsdisplay_param_sz); + _(WSDISPLAYIO_GETACTIVESCREEN, WRITE, sizeof(int)); + _(WSDISPLAYIO_GETWSCHAR, READWRITE, struct_wsdisplay_char_sz); + _(WSDISPLAYIO_PUTWSCHAR, READWRITE, struct_wsdisplay_char_sz); + _(WSDISPLAYIO_DGSCROLL, WRITE, struct_wsdisplay_scroll_data_sz); + _(WSDISPLAYIO_DSSCROLL, READ, struct_wsdisplay_scroll_data_sz); + _(WSDISPLAYIO_GMSGATTRS, WRITE, struct_wsdisplay_msgattrs_sz); + _(WSDISPLAYIO_SMSGATTRS, READ, struct_wsdisplay_msgattrs_sz); + _(WSDISPLAYIO_GBORDER, WRITE, sizeof(int)); + _(WSDISPLAYIO_SBORDER, READ, sizeof(int)); + _(WSDISPLAYIO_SSPLASH, READ, sizeof(int)); + _(WSDISPLAYIO_SPROGRESS, READ, sizeof(int)); + _(WSDISPLAYIO_LINEBYTES, WRITE, sizeof(unsigned int)); + _(WSDISPLAYIO_SETVERSION, READ, sizeof(int)); + _(WSMUXIO_ADD_DEVICE, READ, struct_wsmux_device_sz); + _(WSMUXIO_REMOVE_DEVICE, READ, struct_wsmux_device_sz); + _(WSMUXIO_LIST_DEVICES, READWRITE, struct_wsmux_device_list_sz); + _(WSMUXIO_INJECTEVENT, READ, struct_wscons_event_sz); + _(WSDISPLAYIO_GET_BUSID, WRITE, struct_wsdisplayio_bus_id_sz); + _(WSDISPLAYIO_GET_EDID, READWRITE, struct_wsdisplayio_edid_info_sz); + _(WSDISPLAYIO_SET_POLLING, READ, sizeof(int)); + _(WSDISPLAYIO_GET_FBINFO, READWRITE, struct_wsdisplayio_fbinfo_sz); + _(WSDISPLAYIO_DOBLIT, READWRITE, struct_wsdisplayio_blit_sz); + _(WSDISPLAYIO_WAITBLIT, READWRITE, struct_wsdisplayio_blit_sz); + /* Entries from file: dev/biovar.h */ + _(BIOCLOCATE, READWRITE, struct_bio_locate_sz); + _(BIOCINQ, READWRITE, struct_bioc_inq_sz); + _(BIOCDISK_NOVOL, READWRITE, struct_bioc_disk_sz); + _(BIOCDISK, READWRITE, struct_bioc_disk_sz); + _(BIOCVOL, READWRITE, struct_bioc_vol_sz); + _(BIOCALARM, READWRITE, struct_bioc_alarm_sz); + _(BIOCBLINK, READWRITE, struct_bioc_blink_sz); + _(BIOCSETSTATE, READWRITE, struct_bioc_setstate_sz); + _(BIOCVOLOPS, READWRITE, struct_bioc_volops_sz); + /* Entries from file: dev/md.h */ + _(MD_GETCONF, WRITE, struct_md_conf_sz); + _(MD_SETCONF, READ, struct_md_conf_sz); + /* Entries from file: dev/ccdvar.h */ + _(CCDIOCSET, READWRITE, struct_ccd_ioctl_sz); + _(CCDIOCCLR, READ, struct_ccd_ioctl_sz); + /* Entries from file: dev/cgdvar.h */ + _(CGDIOCSET, READWRITE, struct_cgd_ioctl_sz); + _(CGDIOCCLR, READ, struct_cgd_ioctl_sz); + _(CGDIOCGET, READWRITE, struct_cgd_user_sz); + /* Entries from file: dev/fssvar.h */ + _(FSSIOCSET, READ, struct_fss_set_sz); + _(FSSIOCGET, WRITE, struct_fss_get_sz); + _(FSSIOCCLR, NONE, 0); + _(FSSIOFSET, READ, sizeof(int)); + _(FSSIOFGET, WRITE, sizeof(int)); + /* Entries from file: dev/bluetooth/btdev.h */ + _(BTDEV_ATTACH, READ, struct_plistref_sz); + _(BTDEV_DETACH, READ, struct_plistref_sz); + /* Entries from file: dev/bluetooth/btsco.h */ + _(BTSCO_GETINFO, WRITE, struct_btsco_info_sz); + /* Entries from file: dev/kttcpio.h */ + _(KTTCP_IO_SEND, READWRITE, struct_kttcp_io_args_sz); + _(KTTCP_IO_RECV, READWRITE, struct_kttcp_io_args_sz); + /* Entries from file: dev/lockstat.h */ + _(IOC_LOCKSTAT_GVERSION, WRITE, sizeof(int)); + _(IOC_LOCKSTAT_ENABLE, READ, struct_lsenable_sz); + _(IOC_LOCKSTAT_DISABLE, WRITE, struct_lsdisable_sz); + /* Entries from file: dev/vndvar.h */ + _(VNDIOCSET, READWRITE, struct_vnd_ioctl_sz); + _(VNDIOCCLR, READ, struct_vnd_ioctl_sz); + _(VNDIOCGET, READWRITE, struct_vnd_user_sz); + /* Entries from file: dev/spkrio.h */ + _(SPKRTONE, READ, struct_tone_sz); + _(SPKRTUNE, NONE, 0); + _(SPKRGETVOL, WRITE, sizeof(unsigned int)); + _(SPKRSETVOL, READ, sizeof(unsigned int)); +#if defined(__x86_64__) + /* Entries from file: dev/nvmm/nvmm_ioctl.h */ + _(NVMM_IOC_CAPABILITY, WRITE, struct_nvmm_ioc_capability_sz); + _(NVMM_IOC_MACHINE_CREATE, READWRITE, struct_nvmm_ioc_machine_create_sz); + _(NVMM_IOC_MACHINE_DESTROY, READ, struct_nvmm_ioc_machine_destroy_sz); + _(NVMM_IOC_MACHINE_CONFIGURE, READ, struct_nvmm_ioc_machine_configure_sz); + _(NVMM_IOC_VCPU_CREATE, READ, struct_nvmm_ioc_vcpu_create_sz); + _(NVMM_IOC_VCPU_DESTROY, READ, struct_nvmm_ioc_vcpu_destroy_sz); + _(NVMM_IOC_VCPU_CONFIGURE, READ, struct_nvmm_ioc_vcpu_configure_sz); + _(NVMM_IOC_VCPU_SETSTATE, READ, struct_nvmm_ioc_vcpu_setstate_sz); + _(NVMM_IOC_VCPU_GETSTATE, READ, struct_nvmm_ioc_vcpu_getstate_sz); + _(NVMM_IOC_VCPU_INJECT, READ, struct_nvmm_ioc_vcpu_inject_sz); + _(NVMM_IOC_VCPU_RUN, READWRITE, struct_nvmm_ioc_vcpu_run_sz); + _(NVMM_IOC_GPA_MAP, READ, struct_nvmm_ioc_gpa_map_sz); + _(NVMM_IOC_GPA_UNMAP, READ, struct_nvmm_ioc_gpa_unmap_sz); + _(NVMM_IOC_HVA_MAP, READ, struct_nvmm_ioc_hva_map_sz); + _(NVMM_IOC_HVA_UNMAP, READ, struct_nvmm_ioc_hva_unmap_sz); + _(NVMM_IOC_CTL, READ, struct_nvmm_ioc_ctl_sz); +#endif + /* Entries from file: dev/spi/spi_io.h */ + _(SPI_IOCTL_CONFIGURE, READ, struct_spi_ioctl_configure_sz); + _(SPI_IOCTL_TRANSFER, READ, struct_spi_ioctl_transfer_sz); + /* Entries from file: fs/autofs/autofs_ioctl.h */ + _(AUTOFSREQUEST, WRITE, struct_autofs_daemon_request_sz); + _(AUTOFSDONE, READ, struct_autofs_daemon_done_sz); + /* Entries from file: net/bpf.h */ + _(BIOCGBLEN, WRITE, sizeof(unsigned int)); + _(BIOCSBLEN, READWRITE, sizeof(unsigned int)); + _(BIOCSETF, READ, struct_bpf_program_sz); + _(BIOCFLUSH, NONE, 0); + _(BIOCPROMISC, NONE, 0); + _(BIOCGDLT, WRITE, sizeof(unsigned int)); + _(BIOCGETIF, WRITE, struct_ifreq_sz); + _(BIOCSETIF, READ, struct_ifreq_sz); + _(BIOCGSTATS, WRITE, struct_bpf_stat_sz); + _(BIOCGSTATSOLD, WRITE, struct_bpf_stat_old_sz); + _(BIOCIMMEDIATE, READ, sizeof(unsigned int)); + _(BIOCVERSION, WRITE, struct_bpf_version_sz); + _(BIOCSTCPF, READ, struct_bpf_program_sz); + _(BIOCSUDPF, READ, struct_bpf_program_sz); + _(BIOCGHDRCMPLT, WRITE, sizeof(unsigned int)); + _(BIOCSHDRCMPLT, READ, sizeof(unsigned int)); + _(BIOCSDLT, READ, sizeof(unsigned int)); + _(BIOCGDLTLIST, READWRITE, struct_bpf_dltlist_sz); + _(BIOCGDIRECTION, WRITE, sizeof(unsigned int)); + _(BIOCSDIRECTION, READ, sizeof(unsigned int)); + _(BIOCSRTIMEOUT, READ, struct_timeval_sz); + _(BIOCGRTIMEOUT, WRITE, struct_timeval_sz); + _(BIOCGFEEDBACK, WRITE, sizeof(unsigned int)); + _(BIOCSFEEDBACK, READ, sizeof(unsigned int)); + /* Entries from file: net/if_gre.h */ + _(GRESADDRS, READ, struct_ifreq_sz); + _(GRESADDRD, READ, struct_ifreq_sz); + _(GREGADDRS, READWRITE, struct_ifreq_sz); + _(GREGADDRD, READWRITE, struct_ifreq_sz); + _(GRESPROTO, READ, struct_ifreq_sz); + _(GREGPROTO, READWRITE, struct_ifreq_sz); + _(GRESSOCK, READ, struct_ifreq_sz); + _(GREDSOCK, READ, struct_ifreq_sz); + /* Entries from file: net/if_ppp.h */ + _(PPPIOCGRAWIN, WRITE, struct_ppp_rawin_sz); + _(PPPIOCGFLAGS, WRITE, sizeof(int)); + _(PPPIOCSFLAGS, READ, sizeof(int)); + _(PPPIOCGASYNCMAP, WRITE, sizeof(int)); + _(PPPIOCSASYNCMAP, READ, sizeof(int)); + _(PPPIOCGUNIT, WRITE, sizeof(int)); + _(PPPIOCGRASYNCMAP, WRITE, sizeof(int)); + _(PPPIOCSRASYNCMAP, READ, sizeof(int)); + _(PPPIOCGMRU, WRITE, sizeof(int)); + _(PPPIOCSMRU, READ, sizeof(int)); + _(PPPIOCSMAXCID, READ, sizeof(int)); + _(PPPIOCGXASYNCMAP, WRITE, (8 * sizeof(u32))); + _(PPPIOCSXASYNCMAP, READ, (8 * sizeof(u32))); + _(PPPIOCXFERUNIT, NONE, 0); + _(PPPIOCSCOMPRESS, READ, struct_ppp_option_data_sz); + _(PPPIOCGNPMODE, READWRITE, struct_npioctl_sz); + _(PPPIOCSNPMODE, READ, struct_npioctl_sz); + _(PPPIOCGIDLE, WRITE, struct_ppp_idle_sz); + _(PPPIOCGMTU, WRITE, sizeof(int)); + _(PPPIOCSMTU, READ, sizeof(int)); + _(SIOCGPPPSTATS, READWRITE, struct_ifpppstatsreq_sz); + _(SIOCGPPPCSTATS, READWRITE, struct_ifpppcstatsreq_sz); + /* Entries from file: net/npf.h */ + _(IOC_NPF_VERSION, WRITE, sizeof(int)); + _(IOC_NPF_SWITCH, READ, sizeof(int)); + _(IOC_NPF_LOAD, READWRITE, struct_nvlist_ref_sz); + _(IOC_NPF_TABLE, READ, struct_npf_ioctl_table_sz); + _(IOC_NPF_STATS, READ, sizeof(uptr)); + _(IOC_NPF_SAVE, WRITE, struct_nvlist_ref_sz); + _(IOC_NPF_RULE, READWRITE, struct_nvlist_ref_sz); + _(IOC_NPF_CONN_LOOKUP, READWRITE, struct_nvlist_ref_sz); + _(IOC_NPF_TABLE_REPLACE, READWRITE, struct_nvlist_ref_sz); + /* Entries from file: net/if_pppoe.h */ + _(PPPOESETPARMS, READ, struct_pppoediscparms_sz); + _(PPPOEGETPARMS, READWRITE, struct_pppoediscparms_sz); + _(PPPOEGETSESSION, READWRITE, struct_pppoeconnectionstate_sz); + /* Entries from file: net/if_sppp.h */ + _(SPPPGETAUTHCFG, READWRITE, struct_spppauthcfg_sz); + _(SPPPSETAUTHCFG, READ, struct_spppauthcfg_sz); + _(SPPPGETLCPCFG, READWRITE, struct_sppplcpcfg_sz); + _(SPPPSETLCPCFG, READ, struct_sppplcpcfg_sz); + _(SPPPGETSTATUS, READWRITE, struct_spppstatus_sz); + _(SPPPGETSTATUSNCP, READWRITE, struct_spppstatusncp_sz); + _(SPPPGETIDLETO, READWRITE, struct_spppidletimeout_sz); + _(SPPPSETIDLETO, READ, struct_spppidletimeout_sz); + _(SPPPGETAUTHFAILURES, READWRITE, struct_spppauthfailurestats_sz); + _(SPPPSETAUTHFAILURE, READ, struct_spppauthfailuresettings_sz); + _(SPPPSETDNSOPTS, READ, struct_spppdnssettings_sz); + _(SPPPGETDNSOPTS, READWRITE, struct_spppdnssettings_sz); + _(SPPPGETDNSADDRS, READWRITE, struct_spppdnsaddrs_sz); + _(SPPPSETKEEPALIVE, READ, struct_spppkeepalivesettings_sz); + _(SPPPGETKEEPALIVE, READWRITE, struct_spppkeepalivesettings_sz); + /* Entries from file: net/if_srt.h */ + _(SRT_GETNRT, WRITE, sizeof(unsigned int)); + _(SRT_GETRT, READWRITE, struct_srt_rt_sz); + _(SRT_SETRT, READ, struct_srt_rt_sz); + _(SRT_DELRT, READ, sizeof(unsigned int)); + _(SRT_SFLAGS, READ, sizeof(unsigned int)); + _(SRT_GFLAGS, WRITE, sizeof(unsigned int)); + _(SRT_SGFLAGS, READWRITE, sizeof(unsigned int)); + _(SRT_DEBUG, READ, sizeof(uptr)); + /* Entries from file: net/if_tap.h */ + _(TAPGIFNAME, WRITE, struct_ifreq_sz); + /* Entries from file: net/if_tun.h */ + _(TUNSDEBUG, READ, sizeof(int)); + _(TUNGDEBUG, WRITE, sizeof(int)); + _(TUNSIFMODE, READ, sizeof(int)); + _(TUNSIFHEAD, READ, sizeof(int)); + _(TUNGIFHEAD, WRITE, sizeof(int)); + /* Entries from file: net/pfvar.h */ + _(DIOCSTART, NONE, 0); + _(DIOCSTOP, NONE, 0); + _(DIOCADDRULE, READWRITE, struct_pfioc_rule_sz); + _(DIOCGETRULES, READWRITE, struct_pfioc_rule_sz); + _(DIOCGETRULE, READWRITE, struct_pfioc_rule_sz); + _(DIOCSETLCK, READWRITE, sizeof(u32)); + _(DIOCCLRSTATES, READWRITE, struct_pfioc_state_kill_sz); + _(DIOCGETSTATE, READWRITE, struct_pfioc_state_sz); + _(DIOCSETSTATUSIF, READWRITE, struct_pfioc_if_sz); + _(DIOCGETSTATUS, READWRITE, struct_pf_status_sz); + _(DIOCCLRSTATUS, NONE, 0); + _(DIOCNATLOOK, READWRITE, struct_pfioc_natlook_sz); + _(DIOCSETDEBUG, READWRITE, sizeof(u32)); + _(DIOCGETSTATES, READWRITE, struct_pfioc_states_sz); + _(DIOCCHANGERULE, READWRITE, struct_pfioc_rule_sz); + _(DIOCSETTIMEOUT, READWRITE, struct_pfioc_tm_sz); + _(DIOCGETTIMEOUT, READWRITE, struct_pfioc_tm_sz); + _(DIOCADDSTATE, READWRITE, struct_pfioc_state_sz); + _(DIOCCLRRULECTRS, NONE, 0); + _(DIOCGETLIMIT, READWRITE, struct_pfioc_limit_sz); + _(DIOCSETLIMIT, READWRITE, struct_pfioc_limit_sz); + _(DIOCKILLSTATES, READWRITE, struct_pfioc_state_kill_sz); + _(DIOCSTARTALTQ, NONE, 0); + _(DIOCSTOPALTQ, NONE, 0); + _(DIOCADDALTQ, READWRITE, struct_pfioc_altq_sz); + _(DIOCGETALTQS, READWRITE, struct_pfioc_altq_sz); + _(DIOCGETALTQ, READWRITE, struct_pfioc_altq_sz); + _(DIOCCHANGEALTQ, READWRITE, struct_pfioc_altq_sz); + _(DIOCGETQSTATS, READWRITE, struct_pfioc_qstats_sz); + _(DIOCBEGINADDRS, READWRITE, struct_pfioc_pooladdr_sz); + _(DIOCADDADDR, READWRITE, struct_pfioc_pooladdr_sz); + _(DIOCGETADDRS, READWRITE, struct_pfioc_pooladdr_sz); + _(DIOCGETADDR, READWRITE, struct_pfioc_pooladdr_sz); + _(DIOCCHANGEADDR, READWRITE, struct_pfioc_pooladdr_sz); + _(DIOCADDSTATES, READWRITE, struct_pfioc_states_sz); + _(DIOCGETRULESETS, READWRITE, struct_pfioc_ruleset_sz); + _(DIOCGETRULESET, READWRITE, struct_pfioc_ruleset_sz); + _(DIOCRCLRTABLES, READWRITE, struct_pfioc_table_sz); + _(DIOCRADDTABLES, READWRITE, struct_pfioc_table_sz); + _(DIOCRDELTABLES, READWRITE, struct_pfioc_table_sz); + _(DIOCRGETTABLES, READWRITE, struct_pfioc_table_sz); + _(DIOCRGETTSTATS, READWRITE, struct_pfioc_table_sz); + _(DIOCRCLRTSTATS, READWRITE, struct_pfioc_table_sz); + _(DIOCRCLRADDRS, READWRITE, struct_pfioc_table_sz); + _(DIOCRADDADDRS, READWRITE, struct_pfioc_table_sz); + _(DIOCRDELADDRS, READWRITE, struct_pfioc_table_sz); + _(DIOCRSETADDRS, READWRITE, struct_pfioc_table_sz); + _(DIOCRGETADDRS, READWRITE, struct_pfioc_table_sz); + _(DIOCRGETASTATS, READWRITE, struct_pfioc_table_sz); + _(DIOCRCLRASTATS, READWRITE, struct_pfioc_table_sz); + _(DIOCRTSTADDRS, READWRITE, struct_pfioc_table_sz); + _(DIOCRSETTFLAGS, READWRITE, struct_pfioc_table_sz); + _(DIOCRINADEFINE, READWRITE, struct_pfioc_table_sz); + _(DIOCOSFPFLUSH, NONE, 0); + _(DIOCOSFPADD, READWRITE, struct_pf_osfp_ioctl_sz); + _(DIOCOSFPGET, READWRITE, struct_pf_osfp_ioctl_sz); + _(DIOCXBEGIN, READWRITE, struct_pfioc_trans_sz); + _(DIOCXCOMMIT, READWRITE, struct_pfioc_trans_sz); + _(DIOCXROLLBACK, READWRITE, struct_pfioc_trans_sz); + _(DIOCGETSRCNODES, READWRITE, struct_pfioc_src_nodes_sz); + _(DIOCCLRSRCNODES, NONE, 0); + _(DIOCSETHOSTID, READWRITE, sizeof(u32)); + _(DIOCIGETIFACES, READWRITE, struct_pfioc_iface_sz); + _(DIOCSETIFFLAG, READWRITE, struct_pfioc_iface_sz); + _(DIOCCLRIFFLAG, READWRITE, struct_pfioc_iface_sz); + _(DIOCKILLSRCNODES, READWRITE, struct_pfioc_src_node_kill_sz); + /* Entries from file: netbt/hci.h */ + _(SIOCGBTINFO, READWRITE, struct_btreq_sz); + _(SIOCGBTINFOA, READWRITE, struct_btreq_sz); + _(SIOCNBTINFO, READWRITE, struct_btreq_sz); + _(SIOCSBTFLAGS, READWRITE, struct_btreq_sz); + _(SIOCSBTPOLICY, READWRITE, struct_btreq_sz); + _(SIOCSBTPTYPE, READWRITE, struct_btreq_sz); + _(SIOCGBTSTATS, READWRITE, struct_btreq_sz); + _(SIOCZBTSTATS, READWRITE, struct_btreq_sz); + _(SIOCBTDUMP, READ, struct_btreq_sz); + _(SIOCSBTSCOMTU, READWRITE, struct_btreq_sz); + _(SIOCGBTFEAT, READWRITE, struct_btreq_sz); + /* Entries from file: netinet/ip_nat.h */ + _(SIOCADNAT, READ, struct_ipfobj_sz); + _(SIOCRMNAT, READ, struct_ipfobj_sz); + _(SIOCGNATS, READWRITE, struct_ipfobj_sz); + _(SIOCGNATL, READWRITE, struct_ipfobj_sz); + _(SIOCPURGENAT, READWRITE, struct_ipfobj_sz); + /* Entries from file: netinet/sctp_uio.h */ + _(SIOCCONNECTX, READWRITE, struct_sctp_connectx_addrs_sz); + _(SIOCCONNECTXDEL, READWRITE, struct_sctp_connectx_addrs_sz); + /* Entries from file: netinet6/in6_var.h */ + _(SIOCSIFINFO_FLAGS, READWRITE, struct_in6_ndireq_sz); + _(SIOCAADDRCTL_POLICY, READ, struct_in6_addrpolicy_sz); + _(SIOCDADDRCTL_POLICY, READ, struct_in6_addrpolicy_sz); + /* Entries from file: netsmb/smb_dev.h */ + _(SMBIOC_OPENSESSION, READ, struct_smbioc_ossn_sz); + _(SMBIOC_OPENSHARE, READ, struct_smbioc_oshare_sz); + _(SMBIOC_REQUEST, READWRITE, struct_smbioc_rq_sz); + _(SMBIOC_SETFLAGS, READ, struct_smbioc_flags_sz); + _(SMBIOC_LOOKUP, READ, struct_smbioc_lookup_sz); + _(SMBIOC_READ, READWRITE, struct_smbioc_rw_sz); + _(SMBIOC_WRITE, READWRITE, struct_smbioc_rw_sz); + /* Entries from file: sys/agpio.h */ + _(AGPIOC_INFO, WRITE, struct__agp_info_sz); + _(AGPIOC_ACQUIRE, NONE, 0); + _(AGPIOC_RELEASE, NONE, 0); + _(AGPIOC_SETUP, READ, struct__agp_setup_sz); + _(AGPIOC_ALLOCATE, READWRITE, struct__agp_allocate_sz); + _(AGPIOC_DEALLOCATE, READ, sizeof(int)); + _(AGPIOC_BIND, READ, struct__agp_bind_sz); + _(AGPIOC_UNBIND, READ, struct__agp_unbind_sz); + /* Entries from file: sys/audioio.h */ + _(AUDIO_GETINFO, WRITE, struct_audio_info_sz); + _(AUDIO_SETINFO, READWRITE, struct_audio_info_sz); + _(AUDIO_DRAIN, NONE, 0); + _(AUDIO_FLUSH, NONE, 0); + _(AUDIO_WSEEK, WRITE, sizeof(unsigned long)); + _(AUDIO_RERROR, WRITE, sizeof(int)); + _(AUDIO_GETDEV, WRITE, struct_audio_device_sz); + _(AUDIO_GETENC, READWRITE, struct_audio_encoding_sz); + _(AUDIO_GETFD, WRITE, sizeof(int)); + _(AUDIO_SETFD, READWRITE, sizeof(int)); + _(AUDIO_PERROR, WRITE, sizeof(int)); + _(AUDIO_GETIOFFS, WRITE, struct_audio_offset_sz); + _(AUDIO_GETOOFFS, WRITE, struct_audio_offset_sz); + _(AUDIO_GETPROPS, WRITE, sizeof(int)); + _(AUDIO_GETBUFINFO, WRITE, struct_audio_info_sz); + _(AUDIO_SETCHAN, READ, sizeof(int)); + _(AUDIO_GETCHAN, WRITE, sizeof(int)); + _(AUDIO_QUERYFORMAT, READWRITE, struct_audio_format_query_sz); + _(AUDIO_GETFORMAT, WRITE, struct_audio_info_sz); + _(AUDIO_SETFORMAT, READ, struct_audio_info_sz); + _(AUDIO_MIXER_READ, READWRITE, struct_mixer_ctrl_sz); + _(AUDIO_MIXER_WRITE, READWRITE, struct_mixer_ctrl_sz); + _(AUDIO_MIXER_DEVINFO, READWRITE, struct_mixer_devinfo_sz); + /* Entries from file: sys/ataio.h */ + _(ATAIOCCOMMAND, READWRITE, struct_atareq_sz); + _(ATABUSIOSCAN, READ, struct_atabusioscan_args_sz); + _(ATABUSIORESET, NONE, 0); + _(ATABUSIODETACH, READ, struct_atabusiodetach_args_sz); + /* Entries from file: sys/cdio.h */ + _(CDIOCPLAYTRACKS, READ, struct_ioc_play_track_sz); + _(CDIOCPLAYBLOCKS, READ, struct_ioc_play_blocks_sz); + _(CDIOCREADSUBCHANNEL, READWRITE, struct_ioc_read_subchannel_sz); + _(CDIOREADTOCHEADER, WRITE, struct_ioc_toc_header_sz); + _(CDIOREADTOCENTRIES, READWRITE, struct_ioc_read_toc_entry_sz); + _(CDIOREADMSADDR, READWRITE, sizeof(int)); + _(CDIOCSETPATCH, READ, struct_ioc_patch_sz); + _(CDIOCGETVOL, WRITE, struct_ioc_vol_sz); + _(CDIOCSETVOL, READ, struct_ioc_vol_sz); + _(CDIOCSETMONO, NONE, 0); + _(CDIOCSETSTEREO, NONE, 0); + _(CDIOCSETMUTE, NONE, 0); + _(CDIOCSETLEFT, NONE, 0); + _(CDIOCSETRIGHT, NONE, 0); + _(CDIOCSETDEBUG, NONE, 0); + _(CDIOCCLRDEBUG, NONE, 0); + _(CDIOCPAUSE, NONE, 0); + _(CDIOCRESUME, NONE, 0); + _(CDIOCRESET, NONE, 0); + _(CDIOCSTART, NONE, 0); + _(CDIOCSTOP, NONE, 0); + _(CDIOCEJECT, NONE, 0); + _(CDIOCALLOW, NONE, 0); + _(CDIOCPREVENT, NONE, 0); + _(CDIOCCLOSE, NONE, 0); + _(CDIOCPLAYMSF, READ, struct_ioc_play_msf_sz); + _(CDIOCLOADUNLOAD, READ, struct_ioc_load_unload_sz); + /* Entries from file: sys/chio.h */ + _(CHIOMOVE, READ, struct_changer_move_request_sz); + _(CHIOEXCHANGE, READ, struct_changer_exchange_request_sz); + _(CHIOPOSITION, READ, struct_changer_position_request_sz); + _(CHIOSPICKER, READ, sizeof(int)); + _(CHIOGPARAMS, WRITE, struct_changer_params_sz); + _(CHIOIELEM, NONE, 0); + _(OCHIOGSTATUS, READ, struct_ochanger_element_status_request_sz); + _(CHIOGSTATUS, READ, struct_changer_element_status_request_sz); + _(CHIOSVOLTAG, READ, struct_changer_set_voltag_request_sz); + /* Entries from file: sys/clockctl.h */ + _(CLOCKCTL_SETTIMEOFDAY, READ, struct_clockctl_settimeofday_sz); + _(CLOCKCTL_ADJTIME, READWRITE, struct_clockctl_adjtime_sz); + _(CLOCKCTL_CLOCK_SETTIME, READ, struct_clockctl_clock_settime_sz); + _(CLOCKCTL_NTP_ADJTIME, READWRITE, struct_clockctl_ntp_adjtime_sz); + /* Entries from file: sys/cpuio.h */ + _(IOC_CPU_SETSTATE, READ, struct_cpustate_sz); + _(IOC_CPU_GETSTATE, READWRITE, struct_cpustate_sz); + _(IOC_CPU_GETCOUNT, WRITE, sizeof(int)); + _(IOC_CPU_MAPID, READWRITE, sizeof(int)); + _(IOC_CPU_UCODE_GET_VERSION, READWRITE, struct_cpu_ucode_version_sz); + _(IOC_CPU_UCODE_APPLY, READ, struct_cpu_ucode_sz); + /* Entries from file: sys/dkio.h */ + _(DIOCGDINFO, WRITE, struct_disklabel_sz); + _(DIOCSDINFO, READ, struct_disklabel_sz); + _(DIOCWDINFO, READ, 0); + _(DIOCRFORMAT, READWRITE, struct_format_op_sz); + _(DIOCWFORMAT, READWRITE, struct_format_op_sz); + _(DIOCSSTEP, READ, sizeof(int)); + _(DIOCSRETRIES, READ, sizeof(int)); + _(DIOCKLABEL, READ, sizeof(int)); + _(DIOCWLABEL, READ, sizeof(int)); + _(DIOCSBAD, READ, struct_dkbad_sz); + _(DIOCEJECT, READ, sizeof(int)); + _(ODIOCEJECT, NONE, 0); + _(DIOCLOCK, READ, sizeof(int)); + _(DIOCGDEFLABEL, WRITE, struct_disklabel_sz); + _(DIOCCLRLABEL, NONE, 0); + _(DIOCGCACHE, WRITE, sizeof(int)); + _(DIOCSCACHE, READ, sizeof(int)); + _(DIOCCACHESYNC, READ, sizeof(int)); + _(DIOCBSLIST, READWRITE, struct_disk_badsecinfo_sz); + _(DIOCBSFLUSH, NONE, 0); + _(DIOCAWEDGE, READWRITE, struct_dkwedge_info_sz); + _(DIOCGWEDGEINFO, WRITE, struct_dkwedge_info_sz); + _(DIOCDWEDGE, READ, struct_dkwedge_info_sz); + _(DIOCLWEDGES, READWRITE, struct_dkwedge_list_sz); + _(DIOCGSTRATEGY, WRITE, struct_disk_strategy_sz); + _(DIOCSSTRATEGY, READ, struct_disk_strategy_sz); + _(DIOCGDISKINFO, WRITE, struct_plistref_sz); + _(DIOCTUR, WRITE, sizeof(int)); + _(DIOCMWEDGES, WRITE, sizeof(int)); + _(DIOCGSECTORSIZE, WRITE, sizeof(unsigned int)); + _(DIOCGMEDIASIZE, WRITE, sizeof(uptr)); + _(DIOCRMWEDGES, WRITE, sizeof(int)); + /* Entries from file: sys/drvctlio.h */ + _(DRVDETACHDEV, READ, struct_devdetachargs_sz); + _(DRVRESCANBUS, READ, struct_devrescanargs_sz); + _(DRVCTLCOMMAND, READWRITE, struct_plistref_sz); + _(DRVRESUMEDEV, READ, struct_devpmargs_sz); + _(DRVLISTDEV, READWRITE, struct_devlistargs_sz); + _(DRVGETEVENT, WRITE, struct_plistref_sz); + _(DRVSUSPENDDEV, READ, struct_devpmargs_sz); + /* Entries from file: sys/dvdio.h */ + _(DVD_READ_STRUCT, READWRITE, union_dvd_struct_sz); + _(DVD_WRITE_STRUCT, READWRITE, union_dvd_struct_sz); + _(DVD_AUTH, READWRITE, union_dvd_authinfo_sz); + /* Entries from file: sys/envsys.h */ + _(ENVSYS_GETDICTIONARY, READWRITE, struct_plistref_sz); + _(ENVSYS_SETDICTIONARY, READWRITE, struct_plistref_sz); + _(ENVSYS_REMOVEPROPS, READWRITE, struct_plistref_sz); + _(ENVSYS_GTREDATA, READWRITE, struct_envsys_tre_data_sz); + _(ENVSYS_GTREINFO, READWRITE, struct_envsys_basic_info_sz); + /* Entries from file: sys/event.h */ + _(KFILTER_BYFILTER, READWRITE, struct_kfilter_mapping_sz); + _(KFILTER_BYNAME, READWRITE, struct_kfilter_mapping_sz); + /* Entries from file: sys/fdio.h */ + _(FDIOCGETOPTS, WRITE, 0); + _(FDIOCSETOPTS, READ, sizeof(int)); + _(FDIOCSETFORMAT, READ, struct_fdformat_parms_sz); + _(FDIOCGETFORMAT, WRITE, struct_fdformat_parms_sz); + _(FDIOCFORMAT_TRACK, READ, struct_fdformat_cmd_sz); + /* Entries from file: sys/filio.h */ + _(FIOCLEX, NONE, 0); + _(FIONCLEX, NONE, 0); + _(FIOSEEKDATA, READWRITE, sizeof(uptr)); + _(FIOSEEKHOLE, READWRITE, sizeof(uptr)); + _(FIONREAD, WRITE, sizeof(int)); + _(FIONBIO, READ, sizeof(int)); + _(FIOASYNC, READ, sizeof(int)); + _(FIOSETOWN, READ, sizeof(int)); + _(FIOGETOWN, WRITE, sizeof(int)); + _(OFIOGETBMAP, READWRITE, sizeof(u32)); + _(FIOGETBMAP, READWRITE, sizeof(u64)); + _(FIONWRITE, WRITE, sizeof(int)); + _(FIONSPACE, WRITE, sizeof(int)); + /* Entries from file: sys/gpio.h */ + _(GPIOINFO, WRITE, struct_gpio_info_sz); + _(GPIOSET, READWRITE, struct_gpio_set_sz); + _(GPIOUNSET, READWRITE, struct_gpio_set_sz); + _(GPIOREAD, READWRITE, struct_gpio_req_sz); + _(GPIOWRITE, READWRITE, struct_gpio_req_sz); + _(GPIOTOGGLE, READWRITE, struct_gpio_req_sz); + _(GPIOATTACH, READWRITE, struct_gpio_attach_sz); + /* Entries from file: sys/ioctl.h */ + _(PTIOCNETBSD, READ, struct_ioctl_pt_sz); + _(PTIOCSUNOS, READ, struct_ioctl_pt_sz); + _(PTIOCLINUX, READ, struct_ioctl_pt_sz); + _(PTIOCFREEBSD, READ, struct_ioctl_pt_sz); + _(PTIOCULTRIX, READ, struct_ioctl_pt_sz); + /* Entries from file: sys/ioctl_compat.h */ + _(TIOCHPCL, NONE, 0); + _(TIOCGETP, WRITE, struct_sgttyb_sz); + _(TIOCSETP, READ, struct_sgttyb_sz); + _(TIOCSETN, READ, 0); + _(TIOCSETC, READ, struct_tchars_sz); + _(TIOCGETC, WRITE, struct_tchars_sz); + _(TIOCLBIS, READ, sizeof(int)); + _(TIOCLBIC, READ, sizeof(int)); + _(TIOCLSET, READ, sizeof(int)); + _(TIOCLGET, WRITE, sizeof(int)); + _(TIOCSLTC, READ, struct_ltchars_sz); + _(TIOCGLTC, WRITE, struct_ltchars_sz); + _(OTIOCCONS, NONE, 0); + /* Entries from file: sys/joystick.h */ + _(JOY_SETTIMEOUT, READ, sizeof(int)); + _(JOY_GETTIMEOUT, WRITE, sizeof(int)); + _(JOY_SET_X_OFFSET, READ, sizeof(int)); + _(JOY_SET_Y_OFFSET, READ, sizeof(int)); + _(JOY_GET_Y_OFFSET, WRITE, sizeof(int)); + /* Entries from file: sys/ksyms.h */ + _(OKIOCGSYMBOL, READ, struct_ksyms_ogsymbol_sz); + _(OKIOCGVALUE, READ, struct_ksyms_ogsymbol_sz); + _(KIOCGSIZE, WRITE, sizeof(int)); + _(KIOCGVALUE, READWRITE, struct_ksyms_gvalue_sz); + _(KIOCGSYMBOL, READWRITE, struct_ksyms_gsymbol_sz); + /* Entries from file: sys/lua.h */ + _(LUAINFO, READWRITE, struct_lua_info_sz); + _(LUACREATE, READWRITE, struct_lua_create_sz); + _(LUADESTROY, READWRITE, struct_lua_create_sz); + _(LUAREQUIRE, READWRITE, struct_lua_require_sz); + _(LUALOAD, READWRITE, struct_lua_load_sz); + /* Entries from file: sys/midiio.h */ + _(MIDI_PRETIME, READWRITE, sizeof(int)); + _(MIDI_MPUMODE, READWRITE, sizeof(int)); + _(MIDI_MPUCMD, READWRITE, struct_mpu_command_rec_sz); + _(SEQUENCER_RESET, NONE, 0); + _(SEQUENCER_SYNC, NONE, 0); + _(SEQUENCER_INFO, READWRITE, struct_synth_info_sz); + _(SEQUENCER_CTRLRATE, READWRITE, sizeof(int)); + _(SEQUENCER_GETOUTCOUNT, WRITE, sizeof(int)); + _(SEQUENCER_GETINCOUNT, WRITE, sizeof(int)); + _(SEQUENCER_RESETSAMPLES, READ, sizeof(int)); + _(SEQUENCER_NRSYNTHS, WRITE, sizeof(int)); + _(SEQUENCER_NRMIDIS, WRITE, sizeof(int)); + _(SEQUENCER_THRESHOLD, READ, sizeof(int)); + _(SEQUENCER_MEMAVL, READWRITE, sizeof(int)); + _(SEQUENCER_PANIC, NONE, 0); + _(SEQUENCER_OUTOFBAND, READ, struct_seq_event_rec_sz); + _(SEQUENCER_GETTIME, WRITE, sizeof(int)); + _(SEQUENCER_TMR_TIMEBASE, READWRITE, sizeof(int)); + _(SEQUENCER_TMR_START, NONE, 0); + _(SEQUENCER_TMR_STOP, NONE, 0); + _(SEQUENCER_TMR_CONTINUE, NONE, 0); + _(SEQUENCER_TMR_TEMPO, READWRITE, sizeof(int)); + _(SEQUENCER_TMR_SOURCE, READWRITE, sizeof(int)); + _(SEQUENCER_TMR_METRONOME, READ, sizeof(int)); + _(SEQUENCER_TMR_SELECT, READ, sizeof(int)); + /* Entries from file: sys/mtio.h */ + _(MTIOCTOP, READ, struct_mtop_sz); + _(MTIOCGET, WRITE, struct_mtget_sz); + _(MTIOCIEOT, NONE, 0); + _(MTIOCEEOT, NONE, 0); + _(MTIOCRDSPOS, WRITE, sizeof(u32)); + _(MTIOCRDHPOS, WRITE, sizeof(u32)); + _(MTIOCSLOCATE, READ, sizeof(u32)); + _(MTIOCHLOCATE, READ, sizeof(u32)); + /* Entries from file: sys/power.h */ + _(POWER_EVENT_RECVDICT, READWRITE, struct_plistref_sz); + _(POWER_IOC_GET_TYPE, WRITE, struct_power_type_sz); + /* Entries from file: sys/radioio.h */ + _(RIOCGINFO, WRITE, struct_radio_info_sz); + _(RIOCSINFO, READWRITE, struct_radio_info_sz); + _(RIOCSSRCH, READ, sizeof(int)); + /* Entries from file: sys/rndio.h */ + _(RNDGETENTCNT, WRITE, sizeof(u32)); + _(RNDGETSRCNUM, READWRITE, struct_rndstat_sz); + _(RNDGETSRCNAME, READWRITE, struct_rndstat_name_sz); + _(RNDCTL, READ, struct_rndctl_sz); + _(RNDADDDATA, READ, struct_rnddata_sz); + _(RNDGETPOOLSTAT, WRITE, struct_rndpoolstat_sz); + _(RNDGETESTNUM, READWRITE, struct_rndstat_est_sz); + _(RNDGETESTNAME, READWRITE, struct_rndstat_est_name_sz); + /* Entries from file: sys/scanio.h */ + _(SCIOCGET, WRITE, struct_scan_io_sz); + _(SCIOCSET, READ, struct_scan_io_sz); + _(SCIOCRESTART, NONE, 0); + /* Entries from file: sys/scsiio.h */ + _(SCIOCCOMMAND, READWRITE, struct_scsireq_sz); + _(SCIOCDEBUG, READ, sizeof(int)); + _(SCIOCIDENTIFY, WRITE, struct_scsi_addr_sz); + _(OSCIOCIDENTIFY, WRITE, struct_oscsi_addr_sz); + _(SCIOCDECONFIG, NONE, 0); + _(SCIOCRECONFIG, NONE, 0); + _(SCIOCRESET, NONE, 0); + _(SCBUSIOSCAN, READ, struct_scbusioscan_args_sz); + _(SCBUSIORESET, NONE, 0); + _(SCBUSIODETACH, READ, struct_scbusiodetach_args_sz); + _(SCBUSACCEL, READ, struct_scbusaccel_args_sz); + /* Entries from file: sys/sockio.h */ + _(SIOCSHIWAT, READ, sizeof(int)); + _(SIOCGHIWAT, WRITE, sizeof(int)); + _(SIOCSLOWAT, READ, sizeof(int)); + _(SIOCGLOWAT, WRITE, sizeof(int)); + _(SIOCATMARK, WRITE, sizeof(int)); + _(SIOCSPGRP, READ, sizeof(int)); + _(SIOCGPGRP, WRITE, sizeof(int)); + _(SIOCPEELOFF, READWRITE, sizeof(int)); + _(SIOCADDRT, READ, struct_ortentry_sz); + _(SIOCDELRT, READ, struct_ortentry_sz); + _(SIOCSIFADDR, READ, struct_ifreq_sz); + _(SIOCGIFADDR, READWRITE, struct_ifreq_sz); + _(SIOCSIFDSTADDR, READ, struct_ifreq_sz); + _(SIOCGIFDSTADDR, READWRITE, struct_ifreq_sz); + _(SIOCSIFFLAGS, READ, struct_ifreq_sz); + _(SIOCGIFFLAGS, READWRITE, struct_ifreq_sz); + _(SIOCGIFBRDADDR, READWRITE, struct_ifreq_sz); + _(SIOCSIFBRDADDR, READ, struct_ifreq_sz); + _(SIOCGIFCONF, READWRITE, struct_ifconf_sz); + _(SIOCGIFNETMASK, READWRITE, struct_ifreq_sz); + _(SIOCSIFNETMASK, READ, struct_ifreq_sz); + _(SIOCGIFMETRIC, READWRITE, struct_ifreq_sz); + _(SIOCSIFMETRIC, READ, struct_ifreq_sz); + _(SIOCDIFADDR, READ, struct_ifreq_sz); + _(SIOCAIFADDR, READ, struct_ifaliasreq_sz); + _(SIOCGIFALIAS, READWRITE, struct_ifaliasreq_sz); + _(SIOCGIFAFLAG_IN, READWRITE, struct_ifreq_sz); + _(SIOCALIFADDR, READ, struct_if_laddrreq_sz); + _(SIOCGLIFADDR, READWRITE, struct_if_laddrreq_sz); + _(SIOCDLIFADDR, READ, struct_if_laddrreq_sz); + _(SIOCSIFADDRPREF, READ, struct_if_addrprefreq_sz); + _(SIOCGIFADDRPREF, READWRITE, struct_if_addrprefreq_sz); + _(SIOCADDMULTI, READ, struct_ifreq_sz); + _(SIOCDELMULTI, READ, struct_ifreq_sz); + _(SIOCGETVIFCNT, READWRITE, struct_sioc_vif_req_sz); + _(SIOCGETSGCNT, READWRITE, struct_sioc_sg_req_sz); + _(SIOCSIFMEDIA, READWRITE, struct_ifreq_sz); + _(SIOCGIFMEDIA, READWRITE, struct_ifmediareq_sz); + _(SIOCSIFGENERIC, READ, struct_ifreq_sz); + _(SIOCGIFGENERIC, READWRITE, struct_ifreq_sz); + _(SIOCSIFPHYADDR, READ, struct_ifaliasreq_sz); + _(SIOCGIFPSRCADDR, READWRITE, struct_ifreq_sz); + _(SIOCGIFPDSTADDR, READWRITE, struct_ifreq_sz); + _(SIOCDIFPHYADDR, READ, struct_ifreq_sz); + _(SIOCSLIFPHYADDR, READ, struct_if_laddrreq_sz); + _(SIOCGLIFPHYADDR, READWRITE, struct_if_laddrreq_sz); + _(SIOCSIFMTU, READ, struct_ifreq_sz); + _(SIOCGIFMTU, READWRITE, struct_ifreq_sz); + _(SIOCSDRVSPEC, READ, struct_ifdrv_sz); + _(SIOCGDRVSPEC, READWRITE, struct_ifdrv_sz); + _(SIOCIFCREATE, READ, struct_ifreq_sz); + _(SIOCIFDESTROY, READ, struct_ifreq_sz); + _(SIOCIFGCLONERS, READWRITE, struct_if_clonereq_sz); + _(SIOCGIFDLT, READWRITE, struct_ifreq_sz); + _(SIOCGIFCAP, READWRITE, struct_ifcapreq_sz); + _(SIOCSIFCAP, READ, struct_ifcapreq_sz); + _(SIOCSVH, READWRITE, struct_ifreq_sz); + _(SIOCGVH, READWRITE, struct_ifreq_sz); + _(SIOCINITIFADDR, READWRITE, struct_ifaddr_sz); + _(SIOCGIFDATA, READWRITE, struct_ifdatareq_sz); + _(SIOCZIFDATA, READWRITE, struct_ifdatareq_sz); + _(SIOCGLINKSTR, READWRITE, struct_ifdrv_sz); + _(SIOCSLINKSTR, READ, struct_ifdrv_sz); + _(SIOCGETHERCAP, READWRITE, struct_eccapreq_sz); + _(SIOCGIFINDEX, READWRITE, struct_ifreq_sz); + _(SIOCSETHERCAP, READ, struct_eccapreq_sz); + _(SIOCSIFDESCR, READ, struct_ifreq_sz); + _(SIOCGIFDESCR, READWRITE, struct_ifreq_sz); + _(SIOCGUMBINFO, READWRITE, struct_ifreq_sz); + _(SIOCSUMBPARAM, READ, struct_ifreq_sz); + _(SIOCGUMBPARAM, READWRITE, struct_ifreq_sz); + _(SIOCSETPFSYNC, READ, struct_ifreq_sz); + _(SIOCGETPFSYNC, READWRITE, struct_ifreq_sz); + /* Entries from file: sys/timepps.h */ + _(PPS_IOC_CREATE, NONE, 0); + _(PPS_IOC_DESTROY, NONE, 0); + _(PPS_IOC_SETPARAMS, READ, struct_pps_params_sz); + _(PPS_IOC_GETPARAMS, WRITE, struct_pps_params_sz); + _(PPS_IOC_GETCAP, WRITE, sizeof(int)); + _(PPS_IOC_FETCH, READWRITE, struct_pps_info_sz); + _(PPS_IOC_KCBIND, READ, sizeof(int)); + /* Entries from file: sys/ttycom.h */ + _(TIOCEXCL, NONE, 0); + _(TIOCNXCL, NONE, 0); + _(TIOCFLUSH, READ, sizeof(int)); + _(TIOCGETA, WRITE, struct_termios_sz); + _(TIOCSETA, READ, struct_termios_sz); + _(TIOCSETAW, READ, 0); + _(TIOCSETAF, READ, 0); + _(TIOCGETD, WRITE, sizeof(int)); + _(TIOCSETD, READ, sizeof(int)); + _(TIOCGLINED, WRITE, (32 * sizeof(char))); + _(TIOCSLINED, READ, (32 * sizeof(char))); + _(TIOCSBRK, NONE, 0); + _(TIOCCBRK, NONE, 0); + _(TIOCSDTR, NONE, 0); + _(TIOCCDTR, NONE, 0); + _(TIOCGPGRP, WRITE, sizeof(int)); + _(TIOCSPGRP, READ, sizeof(int)); + _(TIOCOUTQ, WRITE, sizeof(int)); + _(TIOCSTI, READ, sizeof(char)); + _(TIOCNOTTY, NONE, 0); + _(TIOCPKT, READ, sizeof(int)); + _(TIOCSTOP, NONE, 0); + _(TIOCSTART, NONE, 0); + _(TIOCMSET, READ, sizeof(int)); + _(TIOCMBIS, READ, sizeof(int)); + _(TIOCMBIC, READ, sizeof(int)); + _(TIOCMGET, WRITE, sizeof(int)); + _(TIOCREMOTE, READ, sizeof(int)); + _(TIOCGWINSZ, WRITE, struct_winsize_sz); + _(TIOCSWINSZ, READ, struct_winsize_sz); + _(TIOCUCNTL, READ, sizeof(int)); + _(TIOCSTAT, READ, sizeof(int)); + _(TIOCGSID, WRITE, sizeof(int)); + _(TIOCCONS, READ, sizeof(int)); + _(TIOCSCTTY, NONE, 0); + _(TIOCEXT, READ, sizeof(int)); + _(TIOCSIG, NONE, 0); + _(TIOCDRAIN, NONE, 0); + _(TIOCGFLAGS, WRITE, sizeof(int)); + _(TIOCSFLAGS, READ, sizeof(int)); + _(TIOCDCDTIMESTAMP, WRITE, struct_timeval_sz); + _(TIOCRCVFRAME, READ, sizeof(uptr)); + _(TIOCXMTFRAME, READ, sizeof(uptr)); + _(TIOCPTMGET, WRITE, struct_ptmget_sz); + _(TIOCGRANTPT, NONE, 0); + _(TIOCPTSNAME, WRITE, struct_ptmget_sz); + _(TIOCSQSIZE, READ, sizeof(int)); + _(TIOCGQSIZE, WRITE, sizeof(int)); + /* Entries from file: sys/verified_exec.h */ + _(VERIEXEC_LOAD, READ, struct_plistref_sz); + _(VERIEXEC_TABLESIZE, READ, struct_plistref_sz); + _(VERIEXEC_DELETE, READ, struct_plistref_sz); + _(VERIEXEC_QUERY, READWRITE, struct_plistref_sz); + _(VERIEXEC_DUMP, WRITE, struct_plistref_sz); + _(VERIEXEC_FLUSH, NONE, 0); + /* Entries from file: sys/videoio.h */ + _(VIDIOC_QUERYCAP, WRITE, struct_v4l2_capability_sz); + _(VIDIOC_RESERVED, NONE, 0); + _(VIDIOC_ENUM_FMT, READWRITE, struct_v4l2_fmtdesc_sz); + _(VIDIOC_G_FMT, READWRITE, struct_v4l2_format_sz); + _(VIDIOC_S_FMT, READWRITE, struct_v4l2_format_sz); + _(VIDIOC_REQBUFS, READWRITE, struct_v4l2_requestbuffers_sz); + _(VIDIOC_QUERYBUF, READWRITE, struct_v4l2_buffer_sz); + _(VIDIOC_G_FBUF, WRITE, struct_v4l2_framebuffer_sz); + _(VIDIOC_S_FBUF, READ, struct_v4l2_framebuffer_sz); + _(VIDIOC_OVERLAY, READ, sizeof(int)); + _(VIDIOC_QBUF, READWRITE, struct_v4l2_buffer_sz); + _(VIDIOC_DQBUF, READWRITE, struct_v4l2_buffer_sz); + _(VIDIOC_STREAMON, READ, sizeof(int)); + _(VIDIOC_STREAMOFF, READ, sizeof(int)); + _(VIDIOC_G_PARM, READWRITE, struct_v4l2_streamparm_sz); + _(VIDIOC_S_PARM, READWRITE, struct_v4l2_streamparm_sz); + _(VIDIOC_G_STD, WRITE, sizeof(u64)); + _(VIDIOC_S_STD, READ, sizeof(u64)); + _(VIDIOC_ENUMSTD, READWRITE, struct_v4l2_standard_sz); + _(VIDIOC_ENUMINPUT, READWRITE, struct_v4l2_input_sz); + _(VIDIOC_G_CTRL, READWRITE, struct_v4l2_control_sz); + _(VIDIOC_S_CTRL, READWRITE, struct_v4l2_control_sz); + _(VIDIOC_G_TUNER, READWRITE, struct_v4l2_tuner_sz); + _(VIDIOC_S_TUNER, READ, struct_v4l2_tuner_sz); + _(VIDIOC_G_AUDIO, WRITE, struct_v4l2_audio_sz); + _(VIDIOC_S_AUDIO, READ, struct_v4l2_audio_sz); + _(VIDIOC_QUERYCTRL, READWRITE, struct_v4l2_queryctrl_sz); + _(VIDIOC_QUERYMENU, READWRITE, struct_v4l2_querymenu_sz); + _(VIDIOC_G_INPUT, WRITE, sizeof(int)); + _(VIDIOC_S_INPUT, READWRITE, sizeof(int)); + _(VIDIOC_G_OUTPUT, WRITE, sizeof(int)); + _(VIDIOC_S_OUTPUT, READWRITE, sizeof(int)); + _(VIDIOC_ENUMOUTPUT, READWRITE, struct_v4l2_output_sz); + _(VIDIOC_G_AUDOUT, WRITE, struct_v4l2_audioout_sz); + _(VIDIOC_S_AUDOUT, READ, struct_v4l2_audioout_sz); + _(VIDIOC_G_MODULATOR, READWRITE, struct_v4l2_modulator_sz); + _(VIDIOC_S_MODULATOR, READ, struct_v4l2_modulator_sz); + _(VIDIOC_G_FREQUENCY, READWRITE, struct_v4l2_frequency_sz); + _(VIDIOC_S_FREQUENCY, READ, struct_v4l2_frequency_sz); + _(VIDIOC_CROPCAP, READWRITE, struct_v4l2_cropcap_sz); + _(VIDIOC_G_CROP, READWRITE, struct_v4l2_crop_sz); + _(VIDIOC_S_CROP, READ, struct_v4l2_crop_sz); + _(VIDIOC_G_JPEGCOMP, WRITE, struct_v4l2_jpegcompression_sz); + _(VIDIOC_S_JPEGCOMP, READ, struct_v4l2_jpegcompression_sz); + _(VIDIOC_QUERYSTD, WRITE, sizeof(u64)); + _(VIDIOC_TRY_FMT, READWRITE, struct_v4l2_format_sz); + _(VIDIOC_ENUMAUDIO, READWRITE, struct_v4l2_audio_sz); + _(VIDIOC_ENUMAUDOUT, READWRITE, struct_v4l2_audioout_sz); + _(VIDIOC_G_PRIORITY, WRITE, enum_v4l2_priority_sz); + _(VIDIOC_S_PRIORITY, READ, enum_v4l2_priority_sz); + _(VIDIOC_ENUM_FRAMESIZES, READWRITE, struct_v4l2_frmsizeenum_sz); + _(VIDIOC_ENUM_FRAMEINTERVALS, READWRITE, struct_v4l2_frmivalenum_sz); + /* Entries from file: sys/wdog.h */ + _(WDOGIOC_GMODE, READWRITE, struct_wdog_mode_sz); + _(WDOGIOC_SMODE, READ, struct_wdog_mode_sz); + _(WDOGIOC_WHICH, WRITE, struct_wdog_mode_sz); + _(WDOGIOC_TICKLE, NONE, 0); + _(WDOGIOC_GTICKLER, WRITE, sizeof(int)); + _(WDOGIOC_GWDOGS, READWRITE, struct_wdog_conf_sz); + /* Entries from file: sys/kcov.h */ + _(KCOV_IOC_SETBUFSIZE, READ, sizeof(u64)); + _(KCOV_IOC_ENABLE, READ, sizeof(int)); + _(KCOV_IOC_DISABLE, NONE, 0); + /* Entries from file: sys/ipmi.h */ + _(IPMICTL_RECEIVE_MSG_TRUNC, READWRITE, struct_ipmi_recv_sz); + _(IPMICTL_RECEIVE_MSG, READWRITE, struct_ipmi_recv_sz); + _(IPMICTL_SEND_COMMAND, READ, struct_ipmi_req_sz); + _(IPMICTL_REGISTER_FOR_CMD, READ, struct_ipmi_cmdspec_sz); + _(IPMICTL_UNREGISTER_FOR_CMD, READ, struct_ipmi_cmdspec_sz); + _(IPMICTL_SET_GETS_EVENTS_CMD, READ, sizeof(int)); + _(IPMICTL_SET_MY_ADDRESS_CMD, READ, sizeof(unsigned int)); + _(IPMICTL_GET_MY_ADDRESS_CMD, WRITE, sizeof(unsigned int)); + _(IPMICTL_SET_MY_LUN_CMD, READ, sizeof(unsigned int)); + _(IPMICTL_GET_MY_LUN_CMD, WRITE, sizeof(unsigned int)); + /* Entries from file: soundcard.h */ + _(SNDCTL_DSP_RESET, NONE, 0); + _(SNDCTL_DSP_SYNC, NONE, 0); + _(SNDCTL_DSP_SPEED, READWRITE, sizeof(int)); + _(SOUND_PCM_READ_RATE, WRITE, sizeof(int)); + _(SNDCTL_DSP_STEREO, READWRITE, sizeof(int)); + _(SNDCTL_DSP_GETBLKSIZE, READWRITE, sizeof(int)); + _(SNDCTL_DSP_SETFMT, READWRITE, sizeof(int)); + _(SOUND_PCM_READ_BITS, WRITE, sizeof(int)); + _(SNDCTL_DSP_CHANNELS, READWRITE, sizeof(int)); + _(SOUND_PCM_READ_CHANNELS, WRITE, sizeof(int)); + _(SOUND_PCM_WRITE_FILTER, READWRITE, sizeof(int)); + _(SOUND_PCM_READ_FILTER, WRITE, sizeof(int)); + _(SNDCTL_DSP_POST, NONE, 0); + _(SNDCTL_DSP_SUBDIVIDE, READWRITE, sizeof(int)); + _(SNDCTL_DSP_SETFRAGMENT, READWRITE, sizeof(int)); + _(SNDCTL_DSP_GETFMTS, WRITE, sizeof(int)); + _(SNDCTL_DSP_GETOSPACE, WRITE, struct_audio_buf_info_sz); + _(SNDCTL_DSP_GETISPACE, WRITE, struct_audio_buf_info_sz); + _(SNDCTL_DSP_NONBLOCK, NONE, 0); + _(SNDCTL_DSP_GETCAPS, WRITE, sizeof(int)); + _(SNDCTL_DSP_GETTRIGGER, WRITE, sizeof(int)); + _(SNDCTL_DSP_SETTRIGGER, READ, sizeof(int)); + _(SNDCTL_DSP_GETIPTR, WRITE, struct_count_info_sz); + _(SNDCTL_DSP_GETOPTR, WRITE, struct_count_info_sz); + _(SNDCTL_DSP_MAPINBUF, WRITE, struct_buffmem_desc_sz); + _(SNDCTL_DSP_MAPOUTBUF, WRITE, struct_buffmem_desc_sz); + _(SNDCTL_DSP_SETSYNCRO, NONE, 0); + _(SNDCTL_DSP_SETDUPLEX, NONE, 0); + _(SNDCTL_DSP_PROFILE, READ, sizeof(int)); + _(SNDCTL_DSP_GETODELAY, WRITE, sizeof(int)); + _(SOUND_MIXER_INFO, WRITE, struct_mixer_info_sz); + _(SOUND_OLD_MIXER_INFO, WRITE, struct__old_mixer_info_sz); + _(OSS_GETVERSION, WRITE, sizeof(int)); + _(SNDCTL_SYSINFO, WRITE, struct_oss_sysinfo_sz); + _(SNDCTL_AUDIOINFO, READWRITE, struct_oss_audioinfo_sz); + _(SNDCTL_ENGINEINFO, READWRITE, struct_oss_audioinfo_sz); + _(SNDCTL_DSP_GETPLAYVOL, WRITE, sizeof(unsigned int)); + _(SNDCTL_DSP_SETPLAYVOL, READ, sizeof(unsigned int)); + _(SNDCTL_DSP_GETRECVOL, WRITE, sizeof(unsigned int)); + _(SNDCTL_DSP_SETRECVOL, READ, sizeof(unsigned int)); + _(SNDCTL_DSP_SKIP, NONE, 0); + _(SNDCTL_DSP_SILENCE, NONE, 0); + /* Entries from file: dev/filemon/filemon.h (compat <= 9.99.26) */ + _(FILEMON_SET_FD, READWRITE, sizeof(int)); + _(FILEMON_SET_PID, READWRITE, sizeof(int)); + /* Entries from file: dev/usb/urio.h (compat <= 9.99.43) */ + _(URIO_SEND_COMMAND, READWRITE, struct_urio_command_sz); + _(URIO_RECV_COMMAND, READWRITE, struct_urio_command_sz); +#undef _ +} + +static bool ioctl_initialized = false; + +struct ioctl_desc_compare { + bool operator()(const ioctl_desc &left, const ioctl_desc &right) const { + return left.req < right.req; + } +}; + +static void ioctl_init() { + ioctl_table_fill(); + Sort(ioctl_table, ioctl_table_size, ioctl_desc_compare()); + + bool bad = false; + for (unsigned i = 0; i < ioctl_table_size - 1; ++i) { + if (ioctl_table[i].req >= ioctl_table[i + 1].req) { + Printf("Duplicate or unsorted ioctl request id %x >= %x (%s vs %s)\n", + ioctl_table[i].req, ioctl_table[i + 1].req, ioctl_table[i].name, + ioctl_table[i + 1].name); + bad = true; + } + } + + if (bad) + Die(); + + ioctl_initialized = true; +} + +static const ioctl_desc *ioctl_table_lookup(unsigned req) { + int left = 0; + int right = ioctl_table_size; + while (left < right) { + int mid = (left + right) / 2; + if (ioctl_table[mid].req < req) + left = mid + 1; + else + right = mid; + } + if (left == right && ioctl_table[left].req == req) + return ioctl_table + left; + else + return nullptr; +} + +static bool ioctl_decode(unsigned req, ioctl_desc *desc) { + CHECK(desc); + desc->req = req; + desc->name = "<DECODED_IOCTL>"; + desc->size = IOC_SIZE(req); + // Sanity check. + if (desc->size > 0xFFFF) + return false; + unsigned dir = IOC_DIR(req); + switch (dir) { + case IOC_NONE: + desc->type = ioctl_desc::NONE; + break; + case IOC_READ | IOC_WRITE: + desc->type = ioctl_desc::READWRITE; + break; + case IOC_READ: + desc->type = ioctl_desc::WRITE; + break; + case IOC_WRITE: + desc->type = ioctl_desc::READ; + break; + default: + return false; + } + // Size can be 0 iff type is NONE. + if ((desc->type == IOC_NONE) != (desc->size == 0)) + return false; + // Sanity check. + if (IOC_TYPE(req) == 0) + return false; + return true; +} + +static const ioctl_desc *ioctl_lookup(unsigned req) { + const ioctl_desc *desc = ioctl_table_lookup(req); + if (desc) + return desc; + + // Try stripping access size from the request id. + desc = ioctl_table_lookup(req & ~(IOC_SIZEMASK << IOC_SIZESHIFT)); + // Sanity check: requests that encode access size are either read or write and + // have size of 0 in the table. + if (desc && desc->size == 0 && + (desc->type == ioctl_desc::READWRITE || desc->type == ioctl_desc::WRITE || + desc->type == ioctl_desc::READ)) + return desc; + return nullptr; +} + +static void ioctl_common_pre(void *ctx, const ioctl_desc *desc, int d, + unsigned request, void *arg) { + if (desc->type == ioctl_desc::READ || desc->type == ioctl_desc::READWRITE) { + unsigned size = desc->size ? desc->size : IOC_SIZE(request); + COMMON_INTERCEPTOR_READ_RANGE(ctx, arg, size); + } + if (desc->type != ioctl_desc::CUSTOM) + return; + if (request == IOCTL_SIOCGIFCONF) { + struct __sanitizer_ifconf *ifc = (__sanitizer_ifconf *)arg; + COMMON_INTERCEPTOR_READ_RANGE(ctx, (char *)&ifc->ifc_len, + sizeof(ifc->ifc_len)); + } +} + +static void ioctl_common_post(void *ctx, const ioctl_desc *desc, int res, int d, + unsigned request, void *arg) { + if (desc->type == ioctl_desc::WRITE || desc->type == ioctl_desc::READWRITE) { + // FIXME: add verbose output + unsigned size = desc->size ? desc->size : IOC_SIZE(request); + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, arg, size); + } + if (desc->type != ioctl_desc::CUSTOM) + return; + if (request == IOCTL_SIOCGIFCONF) { + struct __sanitizer_ifconf *ifc = (__sanitizer_ifconf *)arg; + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ifc->ifc_ifcu.ifcu_req, ifc->ifc_len); + } +} + +#endif // SANITIZER_NETBSD diff --git a/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_interface_internal.h b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_interface_internal.h new file mode 100644 index 0000000000..1600d31c30 --- /dev/null +++ b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_interface_internal.h @@ -0,0 +1,123 @@ +//===-- sanitizer_interface_internal.h --------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file is shared between run-time libraries of sanitizers. +// +// This header declares the sanitizer runtime interface functions. +// The runtime library has to define these functions so the instrumented program +// could call them. +// +// See also include/sanitizer/common_interface_defs.h +//===----------------------------------------------------------------------===// +#ifndef SANITIZER_INTERFACE_INTERNAL_H +#define SANITIZER_INTERFACE_INTERNAL_H + +#include "sanitizer_internal_defs.h" + +extern "C" { + // Tell the tools to write their reports to "path.<pid>" instead of stderr. + // The special values are "stdout" and "stderr". + SANITIZER_INTERFACE_ATTRIBUTE + void __sanitizer_set_report_path(const char *path); + // Tell the tools to write their reports to the provided file descriptor + // (casted to void *). + SANITIZER_INTERFACE_ATTRIBUTE + void __sanitizer_set_report_fd(void *fd); + // Get the current full report file path, if a path was specified by + // an earlier call to __sanitizer_set_report_path. Returns null otherwise. + SANITIZER_INTERFACE_ATTRIBUTE + const char *__sanitizer_get_report_path(); + + typedef struct { + int coverage_sandboxed; + __sanitizer::sptr coverage_fd; + unsigned int coverage_max_block_size; + } __sanitizer_sandbox_arguments; + + // Notify the tools that the sandbox is going to be turned on. + SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE void + __sanitizer_sandbox_on_notify(__sanitizer_sandbox_arguments *args); + + // This function is called by the tool when it has just finished reporting + // an error. 'error_summary' is a one-line string that summarizes + // the error message. This function can be overridden by the client. + SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE + void __sanitizer_report_error_summary(const char *error_summary); + + SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_cov_dump(); + SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_dump_coverage( + const __sanitizer::uptr *pcs, const __sanitizer::uptr len); + SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_dump_trace_pc_guard_coverage(); + + SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_cov(__sanitizer::u32 *guard); + + // Returns 1 on the first call, then returns 0 thereafter. Called by the tool + // to ensure only one report is printed when multiple errors occur + // simultaneously. + SANITIZER_INTERFACE_ATTRIBUTE int __sanitizer_acquire_crash_state(); + + SANITIZER_INTERFACE_ATTRIBUTE + void __sanitizer_annotate_contiguous_container(const void *beg, + const void *end, + const void *old_mid, + const void *new_mid); + SANITIZER_INTERFACE_ATTRIBUTE + int __sanitizer_verify_contiguous_container(const void *beg, const void *mid, + const void *end); + SANITIZER_INTERFACE_ATTRIBUTE + const void *__sanitizer_contiguous_container_find_bad_address( + const void *beg, const void *mid, const void *end); + + SANITIZER_INTERFACE_ATTRIBUTE + int __sanitizer_get_module_and_offset_for_pc( + __sanitizer::uptr pc, char *module_path, + __sanitizer::uptr module_path_len, __sanitizer::uptr *pc_offset); + + SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE + void __sanitizer_cov_trace_cmp(); + SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE + void __sanitizer_cov_trace_cmp1(); + SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE + void __sanitizer_cov_trace_cmp2(); + SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE + void __sanitizer_cov_trace_cmp4(); + SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE + void __sanitizer_cov_trace_cmp8(); + SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE + void __sanitizer_cov_trace_const_cmp1(); + SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE + void __sanitizer_cov_trace_const_cmp2(); + SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE + void __sanitizer_cov_trace_const_cmp4(); + SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE + void __sanitizer_cov_trace_const_cmp8(); + SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE + void __sanitizer_cov_trace_switch(); + SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE + void __sanitizer_cov_trace_div4(); + SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE + void __sanitizer_cov_trace_div8(); + SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE + void __sanitizer_cov_trace_gep(); + SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE + void __sanitizer_cov_trace_pc_indir(); + SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE + void __sanitizer_cov_trace_pc_guard(__sanitizer::u32*); + SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE + void __sanitizer_cov_trace_pc_guard_init(__sanitizer::u32*, + __sanitizer::u32*); + SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE void + __sanitizer_cov_8bit_counters_init(char *, char *); + SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE void + __sanitizer_cov_bool_flag_init(); + SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE void + __sanitizer_cov_pcs_init(const __sanitizer::uptr *, + const __sanitizer::uptr *); +} // extern "C" + +#endif // SANITIZER_INTERFACE_INTERNAL_H diff --git a/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_internal_defs.h b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_internal_defs.h new file mode 100644 index 0000000000..d0db0129d4 --- /dev/null +++ b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_internal_defs.h @@ -0,0 +1,480 @@ +//===-- sanitizer_internal_defs.h -------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// 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_platform.h" + +#ifndef SANITIZER_DEBUG +# define SANITIZER_DEBUG 0 +#endif + +#define SANITIZER_STRINGIFY_(S) #S +#define SANITIZER_STRINGIFY(S) SANITIZER_STRINGIFY_(S) + +// Only use SANITIZER_*ATTRIBUTE* before the function return type! +#if SANITIZER_WINDOWS +#if SANITIZER_IMPORT_INTERFACE +# define SANITIZER_INTERFACE_ATTRIBUTE __declspec(dllimport) +#else +# define SANITIZER_INTERFACE_ATTRIBUTE __declspec(dllexport) +#endif +# define SANITIZER_WEAK_ATTRIBUTE +#elif 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 + +// TLS is handled differently on different platforms +#if SANITIZER_LINUX || SANITIZER_NETBSD || \ + SANITIZER_FREEBSD +# define SANITIZER_TLS_INITIAL_EXEC_ATTRIBUTE \ + __attribute__((tls_model("initial-exec"))) thread_local +#else +# define SANITIZER_TLS_INITIAL_EXEC_ATTRIBUTE +#endif + +//--------------------------- WEAK FUNCTIONS ---------------------------------// +// When working with weak functions, to simplify the code and make it more +// portable, when possible define a default implementation using this macro: +// +// SANITIZER_INTERFACE_WEAK_DEF(<return_type>, <name>, <parameter list>) +// +// For example: +// SANITIZER_INTERFACE_WEAK_DEF(bool, compare, int a, int b) { return a > b; } +// +#if SANITIZER_WINDOWS +#include "sanitizer_win_defs.h" +# define SANITIZER_INTERFACE_WEAK_DEF(ReturnType, Name, ...) \ + WIN_WEAK_EXPORT_DEF(ReturnType, Name, __VA_ARGS__) +#else +# define SANITIZER_INTERFACE_WEAK_DEF(ReturnType, Name, ...) \ + extern "C" SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE \ + ReturnType Name(__VA_ARGS__) +#endif + +// SANITIZER_SUPPORTS_WEAK_HOOKS means that we support real weak functions that +// will evaluate to a null pointer when not defined. +#ifndef SANITIZER_SUPPORTS_WEAK_HOOKS +#if (SANITIZER_LINUX || SANITIZER_SOLARIS) && !SANITIZER_GO +# define SANITIZER_SUPPORTS_WEAK_HOOKS 1 +// Before Xcode 4.5, the Darwin linker doesn't reliably support undefined +// weak symbols. Mac OS X 10.9/Darwin 13 is the first release only supported +// by Xcode >= 4.5. +#elif SANITIZER_MAC && \ + __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ >= 1090 && !SANITIZER_GO +# define SANITIZER_SUPPORTS_WEAK_HOOKS 1 +#else +# define SANITIZER_SUPPORTS_WEAK_HOOKS 0 +#endif +#endif // SANITIZER_SUPPORTS_WEAK_HOOKS +// For some weak hooks that will be called very often and we want to avoid the +// overhead of executing the default implementation when it is not necessary, +// we can use the flag SANITIZER_SUPPORTS_WEAK_HOOKS to only define the default +// implementation for platforms that doesn't support weak symbols. For example: +// +// #if !SANITIZER_SUPPORT_WEAK_HOOKS +// SANITIZER_INTERFACE_WEAK_DEF(bool, compare_hook, int a, int b) { +// return a > b; +// } +// #endif +// +// And then use it as: if (compare_hook) compare_hook(a, b); +//----------------------------------------------------------------------------// + + +// We can use .preinit_array section on Linux to call sanitizer initialization +// functions very early in the process startup (unless PIC macro is defined). +// +// On FreeBSD, .preinit_array functions are called with rtld_bind_lock writer +// lock held. It will lead to dead lock if unresolved PLT functions (which helds +// rtld_bind_lock reader lock) are called inside .preinit_array functions. +// +// FIXME: do we have anything like this on Mac? +#ifndef SANITIZER_CAN_USE_PREINIT_ARRAY +#if (SANITIZER_LINUX || SANITIZER_FUCHSIA || SANITIZER_NETBSD) && !defined(PIC) +#define SANITIZER_CAN_USE_PREINIT_ARRAY 1 +// Before Solaris 11.4, .preinit_array is fully supported only with GNU ld. +// FIXME: Check for those conditions. +#elif SANITIZER_SOLARIS && !defined(PIC) +# define SANITIZER_CAN_USE_PREINIT_ARRAY 1 +#else +# define SANITIZER_CAN_USE_PREINIT_ARRAY 0 +#endif +#endif // SANITIZER_CAN_USE_PREINIT_ARRAY + +// GCC does not understand __has_feature +#if !defined(__has_feature) +# define __has_feature(x) 0 +#endif + +// Older GCCs do not understand __has_attribute. +#if !defined(__has_attribute) +# define __has_attribute(x) 0 +#endif + +#if !defined(__has_cpp_attribute) +# define __has_cpp_attribute(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 { + +#if defined(_WIN64) +// 64-bit Windows uses LLP64 data model. +typedef unsigned long long uptr; +typedef signed long long sptr; +#else +# if (SANITIZER_WORDSIZE == 64) || SANITIZER_MAC || SANITIZER_WINDOWS +typedef unsigned long uptr; +typedef signed long sptr; +# else +typedef unsigned int uptr; +typedef signed int sptr; +# endif +#endif // defined(_WIN64) +#if defined(__x86_64__) +// Since x32 uses ILP32 data model in 64-bit hardware mode, we must use +// 64-bit pointer to unwind stack frame. +typedef unsigned long long uhwptr; +#else +typedef uptr uhwptr; +#endif +typedef unsigned char u8; +typedef unsigned short u16; +typedef unsigned int u32; +typedef unsigned long long u64; +typedef signed char s8; +typedef signed short s16; +typedef signed int s32; +typedef signed long long s64; +#if SANITIZER_WINDOWS +// On Windows, files are HANDLE, which is a synonim of void*. +// Use void* to avoid including <windows.h> everywhere. +typedef void* fd_t; +typedef unsigned error_t; +#else +typedef int fd_t; +typedef int error_t; +#endif +#if SANITIZER_SOLARIS && !defined(_LP64) +typedef long pid_t; +#else +typedef int pid_t; +#endif + +#if SANITIZER_FREEBSD || SANITIZER_NETBSD || SANITIZER_MAC || \ + (SANITIZER_SOLARIS && (defined(_LP64) || _FILE_OFFSET_BITS == 64)) || \ + (SANITIZER_LINUX && (defined(__x86_64__) || defined(__hexagon__))) +typedef u64 OFF_T; +#else +typedef uptr OFF_T; +#endif +typedef u64 OFF64_T; + +#if (SANITIZER_WORDSIZE == 64) || SANITIZER_MAC +typedef uptr operator_new_size_type; +#else +# if defined(__s390__) && !defined(__s390x__) +// Special case: 31-bit s390 has unsigned long as size_t. +typedef unsigned long operator_new_size_type; +# else +typedef u32 operator_new_size_type; +# endif +#endif + +typedef u64 tid_t; + +// ----------- ATTENTION ------------- +// This header should NOT include any other headers to avoid portability issues. + +// Common defs. +#define INTERFACE_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE +#define SANITIZER_WEAK_DEFAULT_IMPL \ + extern "C" SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE NOINLINE +#define SANITIZER_WEAK_CXX_DEFAULT_IMPL \ + extern "C++" SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE NOINLINE + +// Platform-specific defs. +#if defined(_MSC_VER) +# define ALWAYS_INLINE __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 LIKELY(x) (x) +# define UNLIKELY(x) (x) +# define PREFETCH(x) /* _mm_prefetch(x, _MM_HINT_NTA) */ (void)0 +# define WARN_UNUSED_RESULT +#else // _MSC_VER +# define ALWAYS_INLINE inline __attribute__((always_inline)) +# define ALIAS(x) __attribute__((alias(x))) +// Please only use the ALIGNED macro before the type. +// Using ALIGNED after the variable declaration is not portable! +# 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 +# define LIKELY(x) __builtin_expect(!!(x), 1) +# define UNLIKELY(x) __builtin_expect(!!(x), 0) +# if defined(__i386__) || defined(__x86_64__) +// __builtin_prefetch(x) generates prefetchnt0 on x86 +# define PREFETCH(x) __asm__("prefetchnta (%0)" : : "r" (x)) +# else +# define PREFETCH(x) __builtin_prefetch(x) +# endif +# define WARN_UNUSED_RESULT __attribute__((warn_unused_result)) +#endif // _MSC_VER + +#if !defined(_MSC_VER) || defined(__clang__) +# define UNUSED __attribute__((unused)) +# define USED __attribute__((used)) +#else +# define UNUSED +# define USED +#endif + +#if !defined(_MSC_VER) || defined(__clang__) || MSC_PREREQ(1900) +# define NOEXCEPT noexcept +#else +# define NOEXCEPT throw() +#endif + +#if __has_cpp_attribute(clang::fallthrough) +# define FALLTHROUGH [[clang::fallthrough]] +#else +# define FALLTHROUGH +#endif + +// Unaligned versions of basic types. +typedef ALIGNED(1) u16 uu16; +typedef ALIGNED(1) u32 uu32; +typedef ALIGNED(1) u64 uu64; +typedef ALIGNED(1) s16 us16; +typedef ALIGNED(1) s32 us32; +typedef ALIGNED(1) s64 us64; + +#if SANITIZER_WINDOWS +} // namespace __sanitizer +typedef unsigned long DWORD; +namespace __sanitizer { +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); + +// NOTE: Functions below must be defined in each run-time. +void NORETURN Die(); + +void NORETURN CheckFailed(const char *file, int line, const char *cond, + u64 v1, u64 v2); + +// Check macro +#define RAW_CHECK_MSG(expr, msg, ...) \ + do { \ + if (UNLIKELY(!(expr))) { \ + const char* msgs[] = {msg, __VA_ARGS__}; \ + for (const char* m : msgs) RawWrite(m); \ + Die(); \ + } \ + } while (0) + +#define RAW_CHECK(expr) RAW_CHECK_MSG(expr, #expr "\n", ) +#define RAW_CHECK_VA(expr, ...) RAW_CHECK_MSG(expr, #expr "\n", __VA_ARGS__) + +#define CHECK_IMPL(c1, op, c2) \ + do { \ + __sanitizer::u64 v1 = (__sanitizer::u64)(c1); \ + __sanitizer::u64 v2 = (__sanitizer::u64)(c2); \ + if (UNLIKELY(!(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 SANITIZER_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 UNREACHABLE(msg) do { \ + CHECK(0 && msg); \ + Die(); \ +} while (0) + +#define UNIMPLEMENTED() UNREACHABLE("unimplemented") + +#define COMPILER_CHECK(pred) static_assert(pred, "") + +#define ARRAY_SIZE(a) (sizeof(a)/sizeof((a)[0])) + +// Limits for integral types. We have to redefine it in case we don't +// have stdint.h (like in Visual Studio 9). +#undef __INT64_C +#undef __UINT64_C +#if SANITIZER_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 // SANITIZER_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)) +#undef UINTPTR_MAX +#if SANITIZER_WORDSIZE == 64 +# define UINTPTR_MAX (18446744073709551615UL) +#else +# define UINTPTR_MAX (4294967295U) +#endif // SANITIZER_WORDSIZE == 64 + +enum LinkerInitialized { LINKER_INITIALIZED = 0 }; + +#if !defined(_MSC_VER) || defined(__clang__) +#if SANITIZER_S390_31 +#define GET_CALLER_PC() \ + (__sanitizer::uptr) __builtin_extract_return_addr(__builtin_return_address(0)) +#else +#define GET_CALLER_PC() (__sanitizer::uptr) __builtin_return_address(0) +#endif +#define GET_CURRENT_FRAME() (__sanitizer::uptr) __builtin_frame_address(0) +inline void Trap() { + __builtin_trap(); +} +#else +extern "C" void* _ReturnAddress(void); +extern "C" void* _AddressOfReturnAddress(void); +# pragma intrinsic(_ReturnAddress) +# pragma intrinsic(_AddressOfReturnAddress) +#define GET_CALLER_PC() (__sanitizer::uptr) _ReturnAddress() +// CaptureStackBackTrace doesn't need to know BP on Windows. +#define GET_CURRENT_FRAME() \ + (((__sanitizer::uptr)_AddressOfReturnAddress()) + sizeof(__sanitizer::uptr)) + +extern "C" void __ud2(void); +# pragma intrinsic(__ud2) +inline void Trap() { + __ud2(); +} +#endif + +#define HANDLE_EINTR(res, f) \ + { \ + int rverrno; \ + do { \ + res = (f); \ + } while (internal_iserror(res, &rverrno) && rverrno == EINTR); \ + } + +// Forces the compiler to generate a frame pointer in the function. +#define ENABLE_FRAME_POINTER \ + do { \ + volatile __sanitizer::uptr enable_fp; \ + enable_fp = GET_CURRENT_FRAME(); \ + (void)enable_fp; \ + } while (0) + +// Internal thread identifier allocated by ThreadRegistry. +typedef u32 Tid; +constexpr Tid kInvalidTid = -1; +constexpr Tid kMainTid = 0; + +// Stack depot stack identifier. +typedef u32 StackID; +const StackID kInvalidStackID = 0; + +} // namespace __sanitizer + +namespace __asan { +using namespace __sanitizer; +} +namespace __dsan { +using namespace __sanitizer; +} +namespace __dfsan { +using namespace __sanitizer; +} +namespace __lsan { +using namespace __sanitizer; +} +namespace __msan { +using namespace __sanitizer; +} +namespace __hwasan { +using namespace __sanitizer; +} +namespace __tsan { +using namespace __sanitizer; +} +namespace __scudo { +using namespace __sanitizer; +} +namespace __ubsan { +using namespace __sanitizer; +} +namespace __xray { +using namespace __sanitizer; +} +namespace __interception { +using namespace __sanitizer; +} +namespace __hwasan { +using namespace __sanitizer; +} +namespace __memprof { +using namespace __sanitizer; +} + +#endif // SANITIZER_DEFS_H diff --git a/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_leb128.h b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_leb128.h new file mode 100644 index 0000000000..553550d295 --- /dev/null +++ b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_leb128.h @@ -0,0 +1,87 @@ +//===-- sanitizer_leb128.h --------------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef SANITIZER_LEB128_H +#define SANITIZER_LEB128_H + +#include "sanitizer_common.h" +#include "sanitizer_internal_defs.h" + +namespace __sanitizer { + +template <typename T, typename It> +It EncodeSLEB128(T value, It begin, It end) { + bool more; + do { + u8 byte = value & 0x7f; + // NOTE: this assumes that this signed shift is an arithmetic right shift. + value >>= 7; + more = !((((value == 0) && ((byte & 0x40) == 0)) || + ((value == -1) && ((byte & 0x40) != 0)))); + if (more) + byte |= 0x80; + if (UNLIKELY(begin == end)) + break; + *(begin++) = byte; + } while (more); + return begin; +} + +template <typename T, typename It> +It DecodeSLEB128(It begin, It end, T* v) { + T value = 0; + unsigned shift = 0; + u8 byte; + do { + if (UNLIKELY(begin == end)) + return begin; + byte = *(begin++); + T slice = byte & 0x7f; + value |= slice << shift; + shift += 7; + } while (byte >= 128); + if (shift < 64 && (byte & 0x40)) + value |= (-1ULL) << shift; + *v = value; + return begin; +} + +template <typename T, typename It> +It EncodeULEB128(T value, It begin, It end) { + do { + u8 byte = value & 0x7f; + value >>= 7; + if (value) + byte |= 0x80; + if (UNLIKELY(begin == end)) + break; + *(begin++) = byte; + } while (value); + return begin; +} + +template <typename T, typename It> +It DecodeULEB128(It begin, It end, T* v) { + T value = 0; + unsigned shift = 0; + u8 byte; + do { + if (UNLIKELY(begin == end)) + return begin; + byte = *(begin++); + T slice = byte & 0x7f; + value += slice << shift; + shift += 7; + } while (byte >= 128); + *v = value; + return begin; +} + +} // namespace __sanitizer + +#endif // SANITIZER_LEB128_H diff --git a/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_lfstack.h b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_lfstack.h new file mode 100644 index 0000000000..af2ca55ec3 --- /dev/null +++ b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_lfstack.h @@ -0,0 +1,72 @@ +//===-- sanitizer_lfstack.h -=-----------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// Lock-free stack. +// Uses 32/17 bits as ABA-counter on 32/64-bit platforms. +// The memory passed to Push() must not be ever munmap'ed. +// The type T must contain T *next field. +// +//===----------------------------------------------------------------------===// + +#ifndef SANITIZER_LFSTACK_H +#define SANITIZER_LFSTACK_H + +#include "sanitizer_internal_defs.h" +#include "sanitizer_common.h" +#include "sanitizer_atomic.h" + +namespace __sanitizer { + +template<typename T> +struct LFStack { + void Clear() { + atomic_store(&head_, 0, memory_order_relaxed); + } + + bool Empty() const { + return (atomic_load(&head_, memory_order_relaxed) & kPtrMask) == 0; + } + + void Push(T *p) { + u64 cmp = atomic_load(&head_, memory_order_relaxed); + for (;;) { + u64 cnt = (cmp & kCounterMask) + kCounterInc; + u64 xch = (u64)(uptr)p | cnt; + p->next = (T*)(uptr)(cmp & kPtrMask); + if (atomic_compare_exchange_weak(&head_, &cmp, xch, + memory_order_release)) + break; + } + } + + T *Pop() { + u64 cmp = atomic_load(&head_, memory_order_acquire); + for (;;) { + T *cur = (T*)(uptr)(cmp & kPtrMask); + if (!cur) + return nullptr; + T *nxt = cur->next; + u64 cnt = (cmp & kCounterMask); + u64 xch = (u64)(uptr)nxt | cnt; + if (atomic_compare_exchange_weak(&head_, &cmp, xch, + memory_order_acquire)) + return cur; + } + } + + // private: + static const int kCounterBits = FIRST_32_SECOND_64(32, 17); + static const u64 kPtrMask = ((u64)-1) >> kCounterBits; + static const u64 kCounterMask = ~kPtrMask; + static const u64 kCounterInc = kPtrMask + 1; + + atomic_uint64_t head_; +}; +} // namespace __sanitizer + +#endif // SANITIZER_LFSTACK_H diff --git a/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_libc.cpp b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_libc.cpp new file mode 100644 index 0000000000..d3076f0da4 --- /dev/null +++ b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_libc.cpp @@ -0,0 +1,292 @@ +//===-- sanitizer_libc.cpp ------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file is shared between AddressSanitizer and ThreadSanitizer +// run-time libraries. See sanitizer_libc.h for details. +//===----------------------------------------------------------------------===// + +#include "sanitizer_allocator_internal.h" +#include "sanitizer_common.h" +#include "sanitizer_libc.h" + +namespace __sanitizer { + +s64 internal_atoll(const char *nptr) { + return internal_simple_strtoll(nptr, nullptr, 10); +} + +void *internal_memchr(const void *s, int c, uptr n) { + const char *t = (const char *)s; + for (uptr i = 0; i < n; ++i, ++t) + if (*t == c) + return reinterpret_cast<void *>(const_cast<char *>(t)); + return nullptr; +} + +void *internal_memrchr(const void *s, int c, uptr n) { + const char *t = (const char *)s; + void *res = nullptr; + for (uptr i = 0; i < n; ++i, ++t) { + if (*t == c) res = reinterpret_cast<void *>(const_cast<char *>(t)); + } + return res; +} + +int internal_memcmp(const void* s1, const void* s2, uptr n) { + const char *t1 = (const char *)s1; + const char *t2 = (const 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; + const char *s = (const char *)src; + for (uptr i = 0; i < n; ++i) + d[i] = s[i]; + return dest; +} + +void *internal_memmove(void *dest, const void *src, uptr n) { + char *d = (char*)dest; + const char *s = (const char *)src; + sptr i, signed_n = (sptr)n; + CHECK_GE(signed_n, 0); + if (d < s) { + for (i = 0; i < signed_n; ++i) + d[i] = s[i]; + } else { + if (d > s && signed_n > 0) { + for (i = signed_n - 1; i >= 0; --i) { + d[i] = s[i]; + } + } + } + return dest; +} + +void *internal_memset(void* s, int c, uptr n) { + // Optimize for the most performance-critical case: + if ((reinterpret_cast<uptr>(s) % 16) == 0 && (n % 16) == 0) { + u64 *p = reinterpret_cast<u64*>(s); + u64 *e = p + n / 8; + u64 v = c; + v |= v << 8; + v |= v << 16; + v |= v << 32; + for (; p < e; p += 2) + p[0] = p[1] = v; + return s; + } + // 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; +} + +uptr internal_strcspn(const char *s, const char *reject) { + uptr i; + for (i = 0; s[i]; i++) { + if (internal_strchr(reject, s[i])) + return i; + } + return i; +} + +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 const_cast<char *>(s); + if (*s == 0) + return nullptr; + s++; + } +} + +char *internal_strchrnul(const char *s, int c) { + char *res = internal_strchr(s, c); + if (!res) + res = const_cast<char *>(s) + internal_strlen(s); + return res; +} + +char *internal_strrchr(const char *s, int c) { + const char *res = nullptr; + for (uptr i = 0; s[i]; i++) { + if (s[i] == c) res = s + i; + } + return const_cast<char *>(res); +} + +uptr internal_strlen(const char *s) { + uptr i = 0; + while (s[i]) i++; + return i; +} + +uptr internal_strlcat(char *dst, const char *src, uptr maxlen) { + const uptr srclen = internal_strlen(src); + const uptr dstlen = internal_strnlen(dst, maxlen); + if (dstlen == maxlen) return maxlen + srclen; + if (srclen < maxlen - dstlen) { + internal_memmove(dst + dstlen, src, srclen + 1); + } else { + internal_memmove(dst + dstlen, src, maxlen - dstlen - 1); + dst[maxlen - 1] = '\0'; + } + return dstlen + srclen; +} + +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; +} + +uptr internal_strlcpy(char *dst, const char *src, uptr maxlen) { + const uptr srclen = internal_strlen(src); + if (srclen < maxlen) { + internal_memmove(dst, src, srclen + 1); + } else if (maxlen != 0) { + internal_memmove(dst, src, maxlen - 1); + dst[maxlen - 1] = '\0'; + } + return srclen; +} + +char *internal_strncpy(char *dst, const char *src, uptr n) { + uptr i; + for (i = 0; i < n && src[i]; i++) + dst[i] = src[i]; + internal_memset(dst + i, '\0', n - i); + 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 nullptr; + for (uptr pos = 0; pos <= len1 - len2; pos++) { + if (internal_memcmp(haystack + pos, needle, len2) == 0) + return const_cast<char *>(haystack) + pos; + } + return nullptr; +} + +s64 internal_simple_strtoll(const char *nptr, const 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 = const_cast<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) { + *endptr = (have_digits) ? const_cast<char *>(nptr) : old_nptr; + } + if (sgn > 0) { + return (s64)(Min((u64)INT64_MAX, res)); + } else { + return (res > INT64_MAX) ? INT64_MIN : ((s64)res * -1); + } +} + +uptr internal_wcslen(const wchar_t *s) { + uptr i = 0; + while (s[i]) i++; + return i; +} + +uptr internal_wcsnlen(const wchar_t *s, uptr maxlen) { + uptr i = 0; + while (i < maxlen && s[i]) i++; + return i; +} + +bool mem_is_zero(const char *beg, uptr size) { + CHECK_LE(size, 1ULL << FIRST_32_SECOND_64(30, 40)); // Sanity check. + const char *end = beg + size; + uptr *aligned_beg = (uptr *)RoundUpTo((uptr)beg, sizeof(uptr)); + uptr *aligned_end = (uptr *)RoundDownTo((uptr)end, sizeof(uptr)); + uptr all = 0; + // Prologue. + for (const char *mem = beg; mem < (char*)aligned_beg && mem < end; mem++) + all |= *mem; + // Aligned loop. + for (; aligned_beg < aligned_end; aligned_beg++) + all |= *aligned_beg; + // Epilogue. + if ((char *)aligned_end >= beg) { + for (const char *mem = (char *)aligned_end; mem < end; mem++) all |= *mem; + } + return all == 0; +} + +} // namespace __sanitizer diff --git a/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_libc.h b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_libc.h new file mode 100644 index 0000000000..39a212665d --- /dev/null +++ b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_libc.h @@ -0,0 +1,89 @@ +//===-- sanitizer_libc.h ----------------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// 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. +// FIXME: Some of functions declared in this file are in fact POSIX, not libc. +//===----------------------------------------------------------------------===// + +#ifndef SANITIZER_LIBC_H +#define SANITIZER_LIBC_H + +// ----------- ATTENTION ------------- +// This header should NOT include any other headers from sanitizer runtime. +#include "sanitizer_internal_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); +void *internal_memrchr(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); +void *internal_memmove(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); +char *internal_strchrnul(const char *s, int c); +int internal_strcmp(const char *s1, const char *s2); +uptr internal_strcspn(const char *s, const char *reject); +char *internal_strdup(const char *s); +uptr internal_strlen(const char *s); +uptr internal_strlcat(char *dst, const char *src, uptr maxlen); +char *internal_strncat(char *dst, const char *src, uptr n); +int internal_strncmp(const char *s1, const char *s2, uptr n); +uptr internal_strlcpy(char *dst, const char *src, uptr maxlen); +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); +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, const char **endptr, int base); +int internal_snprintf(char *buffer, uptr length, const char *format, ...) + FORMAT(3, 4); +uptr internal_wcslen(const wchar_t *s); +uptr internal_wcsnlen(const wchar_t *s, uptr maxlen); + +// Return true if all bytes in [mem, mem+size) are zero. +// Optimized for the case when the result is true. +bool mem_is_zero(const char *mem, uptr size); + +// I/O +// Define these as macros so we can use them in linker initialized global +// structs without dynamic initialization. +#define kInvalidFd ((fd_t)-1) +#define kStdinFd ((fd_t)0) +#define kStdoutFd ((fd_t)1) +#define kStderrFd ((fd_t)2) + +uptr internal_ftruncate(fd_t fd, uptr size); + +// OS +void NORETURN internal__exit(int exitcode); +void internal_sleep(unsigned seconds); +void internal_usleep(u64 useconds); + +uptr internal_getpid(); +uptr internal_getppid(); + +int internal_dlinfo(void *handle, int request, void *p); + +// Threading +uptr internal_sched_yield(); + +// Error handling +bool internal_iserror(uptr retval, int *rverrno = nullptr); + +} // namespace __sanitizer + +#endif // SANITIZER_LIBC_H diff --git a/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_libignore.cpp b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_libignore.cpp new file mode 100644 index 0000000000..caaba3155a --- /dev/null +++ b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_libignore.cpp @@ -0,0 +1,129 @@ +//===-- sanitizer_libignore.cpp -------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "sanitizer_platform.h" + +#if SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_MAC || \ + SANITIZER_NETBSD + +#include "sanitizer_libignore.h" +#include "sanitizer_flags.h" +#include "sanitizer_posix.h" +#include "sanitizer_procmaps.h" + +namespace __sanitizer { + +LibIgnore::LibIgnore(LinkerInitialized) { +} + +void LibIgnore::AddIgnoredLibrary(const char *name_templ) { + Lock lock(&mutex_); + if (count_ >= kMaxLibs) { + Report("%s: too many ignored libraries (max: %zu)\n", SanitizerToolName, + kMaxLibs); + Die(); + } + Lib *lib = &libs_[count_++]; + lib->templ = internal_strdup(name_templ); + lib->name = nullptr; + lib->real_name = nullptr; + lib->loaded = false; +} + +void LibIgnore::OnLibraryLoaded(const char *name) { + Lock lock(&mutex_); + // Try to match suppressions with symlink target. + InternalMmapVector<char> buf(kMaxPathLength); + if (name && internal_readlink(name, buf.data(), buf.size() - 1) > 0 && + buf[0]) { + for (uptr i = 0; i < count_; i++) { + Lib *lib = &libs_[i]; + if (!lib->loaded && (!lib->real_name) && + TemplateMatch(lib->templ, name)) + lib->real_name = internal_strdup(buf.data()); + } + } + + // Scan suppressions list and find newly loaded and unloaded libraries. + ListOfModules modules; + modules.init(); + for (uptr i = 0; i < count_; i++) { + Lib *lib = &libs_[i]; + bool loaded = false; + for (const auto &mod : modules) { + for (const auto &range : mod.ranges()) { + if (!range.executable) + continue; + if (!TemplateMatch(lib->templ, mod.full_name()) && + !(lib->real_name && + internal_strcmp(lib->real_name, mod.full_name()) == 0)) + continue; + if (loaded) { + Report("%s: called_from_lib suppression '%s' is matched against" + " 2 libraries: '%s' and '%s'\n", + SanitizerToolName, lib->templ, lib->name, mod.full_name()); + Die(); + } + loaded = true; + if (lib->loaded) + continue; + VReport(1, + "Matched called_from_lib suppression '%s' against library" + " '%s'\n", + lib->templ, mod.full_name()); + lib->loaded = true; + lib->name = internal_strdup(mod.full_name()); + const uptr idx = + atomic_load(&ignored_ranges_count_, memory_order_relaxed); + CHECK_LT(idx, ARRAY_SIZE(ignored_code_ranges_)); + ignored_code_ranges_[idx].begin = range.beg; + ignored_code_ranges_[idx].end = range.end; + atomic_store(&ignored_ranges_count_, idx + 1, memory_order_release); + break; + } + } + if (lib->loaded && !loaded) { + Report("%s: library '%s' that was matched against called_from_lib" + " suppression '%s' is unloaded\n", + SanitizerToolName, lib->name, lib->templ); + Die(); + } + } + + // Track instrumented ranges. + if (track_instrumented_libs_) { + for (const auto &mod : modules) { + if (!mod.instrumented()) + continue; + for (const auto &range : mod.ranges()) { + if (!range.executable) + continue; + if (IsPcInstrumented(range.beg) && IsPcInstrumented(range.end - 1)) + continue; + VReport(1, "Adding instrumented range 0x%zx-0x%zx from library '%s'\n", + range.beg, range.end, mod.full_name()); + const uptr idx = + atomic_load(&instrumented_ranges_count_, memory_order_relaxed); + CHECK_LT(idx, ARRAY_SIZE(instrumented_code_ranges_)); + instrumented_code_ranges_[idx].begin = range.beg; + instrumented_code_ranges_[idx].end = range.end; + atomic_store(&instrumented_ranges_count_, idx + 1, + memory_order_release); + } + } + } +} + +void LibIgnore::OnLibraryUnloaded() { + OnLibraryLoaded(nullptr); +} + +} // namespace __sanitizer + +#endif // SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_MAC || + // SANITIZER_NETBSD diff --git a/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_libignore.h b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_libignore.h new file mode 100644 index 0000000000..18e4d83ed7 --- /dev/null +++ b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_libignore.h @@ -0,0 +1,115 @@ +//===-- sanitizer_libignore.h -----------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// LibIgnore allows to ignore all interceptors called from a particular set +// of dynamic libraries. LibIgnore can be initialized with several templates +// of names of libraries to be ignored. It finds code ranges for the libraries; +// and checks whether the provided PC value belongs to the code ranges. +// +//===----------------------------------------------------------------------===// + +#ifndef SANITIZER_LIBIGNORE_H +#define SANITIZER_LIBIGNORE_H + +#include "sanitizer_internal_defs.h" +#include "sanitizer_common.h" +#include "sanitizer_atomic.h" +#include "sanitizer_mutex.h" + +namespace __sanitizer { + +class LibIgnore { + public: + explicit LibIgnore(LinkerInitialized); + + // Must be called during initialization. + void AddIgnoredLibrary(const char *name_templ); + void IgnoreNoninstrumentedModules(bool enable) { + track_instrumented_libs_ = enable; + } + + // Must be called after a new dynamic library is loaded. + void OnLibraryLoaded(const char *name); + + // Must be called after a dynamic library is unloaded. + void OnLibraryUnloaded(); + + // Checks whether the provided PC belongs to one of the ignored libraries or + // the PC should be ignored because it belongs to an non-instrumented module + // (when ignore_noninstrumented_modules=1). Also returns true via + // "pc_in_ignored_lib" if the PC is in an ignored library, false otherwise. + bool IsIgnored(uptr pc, bool *pc_in_ignored_lib) const; + + // Checks whether the provided PC belongs to an instrumented module. + bool IsPcInstrumented(uptr pc) const; + + private: + struct Lib { + char *templ; + char *name; + char *real_name; // target of symlink + bool loaded; + }; + + struct LibCodeRange { + uptr begin; + uptr end; + }; + + inline bool IsInRange(uptr pc, const LibCodeRange &range) const { + return (pc >= range.begin && pc < range.end); + } + + static const uptr kMaxIgnoredRanges = 128; + static const uptr kMaxInstrumentedRanges = 1024; + static const uptr kMaxLibs = 1024; + + // Hot part: + atomic_uintptr_t ignored_ranges_count_; + LibCodeRange ignored_code_ranges_[kMaxIgnoredRanges]; + + atomic_uintptr_t instrumented_ranges_count_; + LibCodeRange instrumented_code_ranges_[kMaxInstrumentedRanges]; + + // Cold part: + Mutex mutex_; + uptr count_; + Lib libs_[kMaxLibs]; + bool track_instrumented_libs_; + + // Disallow copying of LibIgnore objects. + LibIgnore(const LibIgnore&); // not implemented + void operator = (const LibIgnore&); // not implemented +}; + +inline bool LibIgnore::IsIgnored(uptr pc, bool *pc_in_ignored_lib) const { + const uptr n = atomic_load(&ignored_ranges_count_, memory_order_acquire); + for (uptr i = 0; i < n; i++) { + if (IsInRange(pc, ignored_code_ranges_[i])) { + *pc_in_ignored_lib = true; + return true; + } + } + *pc_in_ignored_lib = false; + if (track_instrumented_libs_ && !IsPcInstrumented(pc)) + return true; + return false; +} + +inline bool LibIgnore::IsPcInstrumented(uptr pc) const { + const uptr n = atomic_load(&instrumented_ranges_count_, memory_order_acquire); + for (uptr i = 0; i < n; i++) { + if (IsInRange(pc, instrumented_code_ranges_[i])) + return true; + } + return false; +} + +} // namespace __sanitizer + +#endif // SANITIZER_LIBIGNORE_H diff --git a/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_linux.cpp b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_linux.cpp new file mode 100644 index 0000000000..a24a313067 --- /dev/null +++ b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_linux.cpp @@ -0,0 +1,2291 @@ +//===-- sanitizer_linux.cpp -----------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file is shared between AddressSanitizer and ThreadSanitizer +// run-time libraries and implements linux-specific functions from +// sanitizer_libc.h. +//===----------------------------------------------------------------------===// + +#include "sanitizer_platform.h" + +#if SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD || \ + SANITIZER_SOLARIS + +#include "sanitizer_common.h" +#include "sanitizer_flags.h" +#include "sanitizer_getauxval.h" +#include "sanitizer_internal_defs.h" +#include "sanitizer_libc.h" +#include "sanitizer_linux.h" +#include "sanitizer_mutex.h" +#include "sanitizer_placement_new.h" +#include "sanitizer_procmaps.h" + +#if SANITIZER_LINUX && !SANITIZER_GO +#include <asm/param.h> +#endif + +// For mips64, syscall(__NR_stat) fills the buffer in the 'struct kernel_stat' +// format. Struct kernel_stat is defined as 'struct stat' in asm/stat.h. To +// access stat from asm/stat.h, without conflicting with definition in +// sys/stat.h, we use this trick. +#if defined(__mips64) +#include <asm/unistd.h> +#include <sys/types.h> +#define stat kernel_stat +#if SANITIZER_GO +#undef st_atime +#undef st_mtime +#undef st_ctime +#define st_atime st_atim +#define st_mtime st_mtim +#define st_ctime st_ctim +#endif +#include <asm/stat.h> +#undef stat +#endif + +#include <dlfcn.h> +#include <errno.h> +#include <fcntl.h> +#include <link.h> +#include <pthread.h> +#include <sched.h> +#include <signal.h> +#include <sys/mman.h> +#include <sys/param.h> +#if !SANITIZER_SOLARIS +#include <sys/ptrace.h> +#endif +#include <sys/resource.h> +#include <sys/stat.h> +#include <sys/syscall.h> +#include <sys/time.h> +#include <sys/types.h> +#include <ucontext.h> +#include <unistd.h> + +#if SANITIZER_LINUX +#include <sys/utsname.h> +#endif + +#if SANITIZER_LINUX && !SANITIZER_ANDROID +#include <sys/personality.h> +#endif + +#if SANITIZER_FREEBSD +#include <sys/exec.h> +#error #include <sys/procctl.h> +#include <sys/sysctl.h> +#include <machine/atomic.h> +extern "C" { +// <sys/umtx.h> must be included after <errno.h> and <sys/types.h> on +// FreeBSD 9.2 and 10.0. +#include <sys/umtx.h> +} +#include <sys/thr.h> +#endif // SANITIZER_FREEBSD + +#if SANITIZER_NETBSD +#include <limits.h> // For NAME_MAX +#include <sys/sysctl.h> +#include <sys/exec.h> +extern struct ps_strings *__ps_strings; +#endif // SANITIZER_NETBSD + +#if SANITIZER_SOLARIS +#include <stdlib.h> +#include <thread.h> +#define environ _environ +#endif + +extern char **environ; + +#if SANITIZER_LINUX +// <linux/time.h> +struct kernel_timeval { + long tv_sec; + long tv_usec; +}; + +// <linux/futex.h> is broken on some linux distributions. +const int FUTEX_WAIT = 0; +const int FUTEX_WAKE = 1; +const int FUTEX_PRIVATE_FLAG = 128; +const int FUTEX_WAIT_PRIVATE = FUTEX_WAIT | FUTEX_PRIVATE_FLAG; +const int FUTEX_WAKE_PRIVATE = FUTEX_WAKE | FUTEX_PRIVATE_FLAG; +#endif // SANITIZER_LINUX + +// Are we using 32-bit or 64-bit Linux syscalls? +// x32 (which defines __x86_64__) has SANITIZER_WORDSIZE == 32 +// but it still needs to use 64-bit syscalls. +#if SANITIZER_LINUX && (defined(__x86_64__) || defined(__powerpc64__) || \ + SANITIZER_WORDSIZE == 64) +# define SANITIZER_LINUX_USES_64BIT_SYSCALLS 1 +#else +# define SANITIZER_LINUX_USES_64BIT_SYSCALLS 0 +#endif + +// Note : FreeBSD had implemented both +// Linux apis, available from +// future 12.x version most likely +#if SANITIZER_LINUX && defined(__NR_getrandom) +# if !defined(GRND_NONBLOCK) +# define GRND_NONBLOCK 1 +# endif +# define SANITIZER_USE_GETRANDOM 1 +#else +# define SANITIZER_USE_GETRANDOM 0 +#endif // SANITIZER_LINUX && defined(__NR_getrandom) + +#if SANITIZER_FREEBSD && __FreeBSD_version >= 1200000 +# define SANITIZER_USE_GETENTROPY 1 +#else +# define SANITIZER_USE_GETENTROPY 0 +#endif + +namespace __sanitizer { + +void SetSigProcMask(__sanitizer_sigset_t *set, __sanitizer_sigset_t *old) { + CHECK_EQ(0, internal_sigprocmask(SIG_SETMASK, set, old)); +} + +ScopedBlockSignals::ScopedBlockSignals(__sanitizer_sigset_t *copy) { + __sanitizer_sigset_t set; + internal_sigfillset(&set); +# if SANITIZER_LINUX && !SANITIZER_ANDROID + // Glibc uses SIGSETXID signal during setuid call. If this signal is blocked + // on any thread, setuid call hangs. + // See test/sanitizer_common/TestCases/Linux/setuid.c. + internal_sigdelset(&set, 33); +# endif +# if SANITIZER_LINUX + // Seccomp-BPF-sandboxed processes rely on SIGSYS to handle trapped syscalls. + // If this signal is blocked, such calls cannot be handled and the process may + // hang. + internal_sigdelset(&set, 31); +# endif + SetSigProcMask(&set, &saved_); + if (copy) + internal_memcpy(copy, &saved_, sizeof(saved_)); +} + +ScopedBlockSignals::~ScopedBlockSignals() { SetSigProcMask(&saved_, nullptr); } + +# if SANITIZER_LINUX && defined(__x86_64__) +# include "sanitizer_syscall_linux_x86_64.inc" +# elif SANITIZER_LINUX && SANITIZER_RISCV64 +# include "sanitizer_syscall_linux_riscv64.inc" +# elif SANITIZER_LINUX && defined(__aarch64__) +# include "sanitizer_syscall_linux_aarch64.inc" +# elif SANITIZER_LINUX && defined(__arm__) +# include "sanitizer_syscall_linux_arm.inc" +# elif SANITIZER_LINUX && defined(__hexagon__) +# include "sanitizer_syscall_linux_hexagon.inc" +# else +# include "sanitizer_syscall_generic.inc" +# endif + +// --------------- sanitizer_libc.h +#if !SANITIZER_SOLARIS && !SANITIZER_NETBSD +#if !SANITIZER_S390 +uptr internal_mmap(void *addr, uptr length, int prot, int flags, int fd, + u64 offset) { +#if SANITIZER_FREEBSD || SANITIZER_LINUX_USES_64BIT_SYSCALLS + return internal_syscall(SYSCALL(mmap), (uptr)addr, length, prot, flags, fd, + offset); +#else + // mmap2 specifies file offset in 4096-byte units. + CHECK(IsAligned(offset, 4096)); + return internal_syscall(SYSCALL(mmap2), addr, length, prot, flags, fd, + offset / 4096); +#endif +} +#endif // !SANITIZER_S390 + +uptr internal_munmap(void *addr, uptr length) { + return internal_syscall(SYSCALL(munmap), (uptr)addr, length); +} + +#if SANITIZER_LINUX +uptr internal_mremap(void *old_address, uptr old_size, uptr new_size, int flags, + void *new_address) { + return internal_syscall(SYSCALL(mremap), (uptr)old_address, old_size, + new_size, flags, (uptr)new_address); +} +#endif + +int internal_mprotect(void *addr, uptr length, int prot) { + return internal_syscall(SYSCALL(mprotect), (uptr)addr, length, prot); +} + +int internal_madvise(uptr addr, uptr length, int advice) { + return internal_syscall(SYSCALL(madvise), addr, length, advice); +} + +uptr internal_close(fd_t fd) { + return internal_syscall(SYSCALL(close), fd); +} + +uptr internal_open(const char *filename, int flags) { +#if SANITIZER_USES_CANONICAL_LINUX_SYSCALLS + return internal_syscall(SYSCALL(openat), AT_FDCWD, (uptr)filename, flags); +#else + return internal_syscall(SYSCALL(open), (uptr)filename, flags); +#endif +} + +uptr internal_open(const char *filename, int flags, u32 mode) { +#if SANITIZER_USES_CANONICAL_LINUX_SYSCALLS + return internal_syscall(SYSCALL(openat), AT_FDCWD, (uptr)filename, flags, + mode); +#else + return internal_syscall(SYSCALL(open), (uptr)filename, flags, mode); +#endif +} + +uptr internal_read(fd_t fd, void *buf, uptr count) { + sptr res; + HANDLE_EINTR(res, + (sptr)internal_syscall(SYSCALL(read), fd, (uptr)buf, count)); + return res; +} + +uptr internal_write(fd_t fd, const void *buf, uptr count) { + sptr res; + HANDLE_EINTR(res, + (sptr)internal_syscall(SYSCALL(write), fd, (uptr)buf, count)); + return res; +} + +uptr internal_ftruncate(fd_t fd, uptr size) { + sptr res; + HANDLE_EINTR(res, (sptr)internal_syscall(SYSCALL(ftruncate), fd, + (OFF_T)size)); + return res; +} + +#if !SANITIZER_LINUX_USES_64BIT_SYSCALLS && SANITIZER_LINUX +static void stat64_to_stat(struct stat64 *in, struct stat *out) { + internal_memset(out, 0, sizeof(*out)); + out->st_dev = in->st_dev; + out->st_ino = in->st_ino; + out->st_mode = in->st_mode; + out->st_nlink = in->st_nlink; + out->st_uid = in->st_uid; + out->st_gid = in->st_gid; + out->st_rdev = in->st_rdev; + out->st_size = in->st_size; + out->st_blksize = in->st_blksize; + out->st_blocks = in->st_blocks; + out->st_atime = in->st_atime; + out->st_mtime = in->st_mtime; + out->st_ctime = in->st_ctime; +} +#endif + +#if defined(__mips64) +// Undefine compatibility macros from <sys/stat.h> +// so that they would not clash with the kernel_stat +// st_[a|m|c]time fields +#if !SANITIZER_GO +#undef st_atime +#undef st_mtime +#undef st_ctime +#endif +#if defined(SANITIZER_ANDROID) +// Bionic sys/stat.h defines additional macros +// for compatibility with the old NDKs and +// they clash with the kernel_stat structure +// st_[a|m|c]time_nsec fields. +#undef st_atime_nsec +#undef st_mtime_nsec +#undef st_ctime_nsec +#endif +static void kernel_stat_to_stat(struct kernel_stat *in, struct stat *out) { + internal_memset(out, 0, sizeof(*out)); + out->st_dev = in->st_dev; + out->st_ino = in->st_ino; + out->st_mode = in->st_mode; + out->st_nlink = in->st_nlink; + out->st_uid = in->st_uid; + out->st_gid = in->st_gid; + out->st_rdev = in->st_rdev; + out->st_size = in->st_size; + out->st_blksize = in->st_blksize; + out->st_blocks = in->st_blocks; +#if defined(__USE_MISC) || \ + defined(__USE_XOPEN2K8) || \ + defined(SANITIZER_ANDROID) + out->st_atim.tv_sec = in->st_atime; + out->st_atim.tv_nsec = in->st_atime_nsec; + out->st_mtim.tv_sec = in->st_mtime; + out->st_mtim.tv_nsec = in->st_mtime_nsec; + out->st_ctim.tv_sec = in->st_ctime; + out->st_ctim.tv_nsec = in->st_ctime_nsec; +#else + out->st_atime = in->st_atime; + out->st_atimensec = in->st_atime_nsec; + out->st_mtime = in->st_mtime; + out->st_mtimensec = in->st_mtime_nsec; + out->st_ctime = in->st_ctime; + out->st_atimensec = in->st_ctime_nsec; +#endif +} +#endif + +uptr internal_stat(const char *path, void *buf) { +#if SANITIZER_FREEBSD + return internal_syscall(SYSCALL(fstatat), AT_FDCWD, (uptr)path, (uptr)buf, 0); +#elif SANITIZER_USES_CANONICAL_LINUX_SYSCALLS + return internal_syscall(SYSCALL(newfstatat), AT_FDCWD, (uptr)path, (uptr)buf, + 0); +#elif SANITIZER_LINUX_USES_64BIT_SYSCALLS +# if defined(__mips64) + // For mips64, stat syscall fills buffer in the format of kernel_stat + struct kernel_stat kbuf; + int res = internal_syscall(SYSCALL(stat), path, &kbuf); + kernel_stat_to_stat(&kbuf, (struct stat *)buf); + return res; +# else + return internal_syscall(SYSCALL(stat), (uptr)path, (uptr)buf); +# endif +#else + struct stat64 buf64; + int res = internal_syscall(SYSCALL(stat64), path, &buf64); + stat64_to_stat(&buf64, (struct stat *)buf); + return res; +#endif +} + +uptr internal_lstat(const char *path, void *buf) { +#if SANITIZER_FREEBSD + return internal_syscall(SYSCALL(fstatat), AT_FDCWD, (uptr)path, (uptr)buf, + AT_SYMLINK_NOFOLLOW); +#elif SANITIZER_USES_CANONICAL_LINUX_SYSCALLS + return internal_syscall(SYSCALL(newfstatat), AT_FDCWD, (uptr)path, (uptr)buf, + AT_SYMLINK_NOFOLLOW); +#elif SANITIZER_LINUX_USES_64BIT_SYSCALLS +# if SANITIZER_MIPS64 + // For mips64, lstat syscall fills buffer in the format of kernel_stat + struct kernel_stat kbuf; + int res = internal_syscall(SYSCALL(lstat), path, &kbuf); + kernel_stat_to_stat(&kbuf, (struct stat *)buf); + return res; +# else + return internal_syscall(SYSCALL(lstat), (uptr)path, (uptr)buf); +# endif +#else + struct stat64 buf64; + int res = internal_syscall(SYSCALL(lstat64), path, &buf64); + stat64_to_stat(&buf64, (struct stat *)buf); + return res; +#endif +} + +uptr internal_fstat(fd_t fd, void *buf) { +#if SANITIZER_FREEBSD || SANITIZER_LINUX_USES_64BIT_SYSCALLS +#if SANITIZER_MIPS64 + // For mips64, fstat syscall fills buffer in the format of kernel_stat + struct kernel_stat kbuf; + int res = internal_syscall(SYSCALL(fstat), fd, &kbuf); + kernel_stat_to_stat(&kbuf, (struct stat *)buf); + return res; +# else + return internal_syscall(SYSCALL(fstat), fd, (uptr)buf); +# endif +#else + struct stat64 buf64; + int res = internal_syscall(SYSCALL(fstat64), fd, &buf64); + stat64_to_stat(&buf64, (struct stat *)buf); + return res; +#endif +} + +uptr internal_filesize(fd_t fd) { + struct stat st; + if (internal_fstat(fd, &st)) + return -1; + return (uptr)st.st_size; +} + +uptr internal_dup(int oldfd) { + return internal_syscall(SYSCALL(dup), oldfd); +} + +uptr internal_dup2(int oldfd, int newfd) { +#if SANITIZER_USES_CANONICAL_LINUX_SYSCALLS + return internal_syscall(SYSCALL(dup3), oldfd, newfd, 0); +#else + return internal_syscall(SYSCALL(dup2), oldfd, newfd); +#endif +} + +uptr internal_readlink(const char *path, char *buf, uptr bufsize) { +#if SANITIZER_USES_CANONICAL_LINUX_SYSCALLS + return internal_syscall(SYSCALL(readlinkat), AT_FDCWD, (uptr)path, (uptr)buf, + bufsize); +#else + return internal_syscall(SYSCALL(readlink), (uptr)path, (uptr)buf, bufsize); +#endif +} + +uptr internal_unlink(const char *path) { +#if SANITIZER_USES_CANONICAL_LINUX_SYSCALLS + return internal_syscall(SYSCALL(unlinkat), AT_FDCWD, (uptr)path, 0); +#else + return internal_syscall(SYSCALL(unlink), (uptr)path); +#endif +} + +uptr internal_rename(const char *oldpath, const char *newpath) { +#if defined(__riscv) && defined(__linux__) + return internal_syscall(SYSCALL(renameat2), AT_FDCWD, (uptr)oldpath, AT_FDCWD, + (uptr)newpath, 0); +#elif SANITIZER_USES_CANONICAL_LINUX_SYSCALLS + return internal_syscall(SYSCALL(renameat), AT_FDCWD, (uptr)oldpath, AT_FDCWD, + (uptr)newpath); +#else + return internal_syscall(SYSCALL(rename), (uptr)oldpath, (uptr)newpath); +#endif +} + +uptr internal_sched_yield() { + return internal_syscall(SYSCALL(sched_yield)); +} + +void internal_usleep(u64 useconds) { + struct timespec ts; + ts.tv_sec = useconds / 1000000; + ts.tv_nsec = (useconds % 1000000) * 1000; + internal_syscall(SYSCALL(nanosleep), &ts, &ts); +} + +uptr internal_execve(const char *filename, char *const argv[], + char *const envp[]) { + return internal_syscall(SYSCALL(execve), (uptr)filename, (uptr)argv, + (uptr)envp); +} +#endif // !SANITIZER_SOLARIS && !SANITIZER_NETBSD + +#if !SANITIZER_NETBSD +void internal__exit(int exitcode) { +#if SANITIZER_FREEBSD || SANITIZER_SOLARIS + internal_syscall(SYSCALL(exit), exitcode); +#else + internal_syscall(SYSCALL(exit_group), exitcode); +#endif + Die(); // Unreachable. +} +#endif // !SANITIZER_NETBSD + +// ----------------- sanitizer_common.h +bool FileExists(const char *filename) { + if (ShouldMockFailureToOpen(filename)) + return false; + struct stat st; +#if SANITIZER_USES_CANONICAL_LINUX_SYSCALLS + if (internal_syscall(SYSCALL(newfstatat), AT_FDCWD, filename, &st, 0)) +#else + if (internal_stat(filename, &st)) +#endif + return false; + // Sanity check: filename is a regular file. + return S_ISREG(st.st_mode); +} + +#if !SANITIZER_NETBSD +tid_t GetTid() { +#if SANITIZER_FREEBSD + long Tid; + thr_self(&Tid); + return Tid; +#elif SANITIZER_SOLARIS + return thr_self(); +#else + return internal_syscall(SYSCALL(gettid)); +#endif +} + +int TgKill(pid_t pid, tid_t tid, int sig) { +#if SANITIZER_LINUX + return internal_syscall(SYSCALL(tgkill), pid, tid, sig); +#elif SANITIZER_FREEBSD + return internal_syscall(SYSCALL(thr_kill2), pid, tid, sig); +#elif SANITIZER_SOLARIS + (void)pid; + return thr_kill(tid, sig); +#endif +} +#endif + +#if SANITIZER_GLIBC +u64 NanoTime() { + kernel_timeval tv; + internal_memset(&tv, 0, sizeof(tv)); + internal_syscall(SYSCALL(gettimeofday), &tv, 0); + return (u64)tv.tv_sec * 1000 * 1000 * 1000 + tv.tv_usec * 1000; +} +// Used by real_clock_gettime. +uptr internal_clock_gettime(__sanitizer_clockid_t clk_id, void *tp) { + return internal_syscall(SYSCALL(clock_gettime), clk_id, tp); +} +#elif !SANITIZER_SOLARIS && !SANITIZER_NETBSD +u64 NanoTime() { + struct timespec ts; + clock_gettime(CLOCK_REALTIME, &ts); + return (u64)ts.tv_sec * 1000 * 1000 * 1000 + ts.tv_nsec; +} +#endif + +// Like getenv, but reads env directly from /proc (on Linux) or parses the +// 'environ' array (on some others) and does not use libc. This function +// should be called first inside __asan_init. +const char *GetEnv(const char *name) { +#if SANITIZER_FREEBSD || SANITIZER_NETBSD || SANITIZER_SOLARIS + if (::environ != 0) { + uptr NameLen = internal_strlen(name); + for (char **Env = ::environ; *Env != 0; Env++) { + if (internal_strncmp(*Env, name, NameLen) == 0 && (*Env)[NameLen] == '=') + return (*Env) + NameLen + 1; + } + } + return 0; // Not found. +#elif SANITIZER_LINUX + static char *environ; + static uptr len; + static bool inited; + if (!inited) { + inited = true; + uptr environ_size; + if (!ReadFileToBuffer("/proc/self/environ", &environ, &environ_size, &len)) + environ = nullptr; + } + if (!environ || len == 0) return nullptr; + 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) // this entry isn't NUL terminated + return nullptr; + else if (!internal_memcmp(p, name, namelen) && p[namelen] == '=') // Match. + return p + namelen + 1; // point after = + p = endp + 1; + } + return nullptr; // Not found. +#else +#error "Unsupported platform" +#endif +} + +#if !SANITIZER_FREEBSD && !SANITIZER_NETBSD && !SANITIZER_GO +extern "C" { +SANITIZER_WEAK_ATTRIBUTE extern void *__libc_stack_end; +} +#endif + +#if !SANITIZER_FREEBSD && !SANITIZER_NETBSD +static void ReadNullSepFileToArray(const char *path, char ***arr, + int arr_size) { + char *buff; + uptr buff_size; + uptr buff_len; + *arr = (char **)MmapOrDie(arr_size * sizeof(char *), "NullSepFileArray"); + if (!ReadFileToBuffer(path, &buff, &buff_size, &buff_len, 1024 * 1024)) { + (*arr)[0] = nullptr; + return; + } + (*arr)[0] = buff; + int count, i; + for (count = 1, i = 1; ; i++) { + if (buff[i] == 0) { + if (buff[i+1] == 0) break; + (*arr)[count] = &buff[i+1]; + CHECK_LE(count, arr_size - 1); // FIXME: make this more flexible. + count++; + } + } + (*arr)[count] = nullptr; +} +#endif + +static void GetArgsAndEnv(char ***argv, char ***envp) { +#if SANITIZER_FREEBSD + // On FreeBSD, retrieving the argument and environment arrays is done via the + // kern.ps_strings sysctl, which returns a pointer to a structure containing + // this information. See also <sys/exec.h>. + ps_strings *pss; + uptr sz = sizeof(pss); + if (internal_sysctlbyname("kern.ps_strings", &pss, &sz, NULL, 0) == -1) { + Printf("sysctl kern.ps_strings failed\n"); + Die(); + } + *argv = pss->ps_argvstr; + *envp = pss->ps_envstr; +#elif SANITIZER_NETBSD + *argv = __ps_strings->ps_argvstr; + *envp = __ps_strings->ps_envstr; +#else // SANITIZER_FREEBSD +#if !SANITIZER_GO + if (&__libc_stack_end) { + uptr* stack_end = (uptr*)__libc_stack_end; + // Normally argc can be obtained from *stack_end, however, on ARM glibc's + // _start clobbers it: + // https://sourceware.org/git/?p=glibc.git;a=blob;f=sysdeps/arm/start.S;hb=refs/heads/release/2.31/master#l75 + // Do not special-case ARM and infer argc from argv everywhere. + int argc = 0; + while (stack_end[argc + 1]) argc++; + *argv = (char**)(stack_end + 1); + *envp = (char**)(stack_end + argc + 2); + } else { +#endif // !SANITIZER_GO + static const int kMaxArgv = 2000, kMaxEnvp = 2000; + ReadNullSepFileToArray("/proc/self/cmdline", argv, kMaxArgv); + ReadNullSepFileToArray("/proc/self/environ", envp, kMaxEnvp); +#if !SANITIZER_GO + } +#endif // !SANITIZER_GO +#endif // SANITIZER_FREEBSD +} + +char **GetArgv() { + char **argv, **envp; + GetArgsAndEnv(&argv, &envp); + return argv; +} + +char **GetEnviron() { + char **argv, **envp; + GetArgsAndEnv(&argv, &envp); + return envp; +} + +#if !SANITIZER_SOLARIS +void FutexWait(atomic_uint32_t *p, u32 cmp) { +# if SANITIZER_FREEBSD + _umtx_op(p, UMTX_OP_WAIT_UINT, cmp, 0, 0); +# elif SANITIZER_NETBSD + sched_yield(); /* No userspace futex-like synchronization */ +# else + internal_syscall(SYSCALL(futex), (uptr)p, FUTEX_WAIT_PRIVATE, cmp, 0, 0, 0); +# endif +} + +void FutexWake(atomic_uint32_t *p, u32 count) { +# if SANITIZER_FREEBSD + _umtx_op(p, UMTX_OP_WAKE, count, 0, 0); +# elif SANITIZER_NETBSD + /* No userspace futex-like synchronization */ +# else + internal_syscall(SYSCALL(futex), (uptr)p, FUTEX_WAKE_PRIVATE, count, 0, 0, 0); +# endif +} + +# endif // !SANITIZER_SOLARIS + +// ----------------- sanitizer_linux.h +// The actual size of this structure is specified by d_reclen. +// Note that getdents64 uses a different structure format. We only provide the +// 32-bit syscall here. +#if SANITIZER_NETBSD +// Not used +#else +struct linux_dirent { +#if SANITIZER_X32 || defined(__aarch64__) || SANITIZER_RISCV64 + u64 d_ino; + u64 d_off; +#else + unsigned long d_ino; + unsigned long d_off; +#endif + unsigned short d_reclen; +#if defined(__aarch64__) || SANITIZER_RISCV64 + unsigned char d_type; +#endif + char d_name[256]; +}; +#endif + +#if !SANITIZER_SOLARIS && !SANITIZER_NETBSD +// Syscall wrappers. +uptr internal_ptrace(int request, int pid, void *addr, void *data) { + return internal_syscall(SYSCALL(ptrace), request, pid, (uptr)addr, + (uptr)data); +} + +uptr internal_waitpid(int pid, int *status, int options) { + return internal_syscall(SYSCALL(wait4), pid, (uptr)status, options, + 0 /* rusage */); +} + +uptr internal_getpid() { + return internal_syscall(SYSCALL(getpid)); +} + +uptr internal_getppid() { + return internal_syscall(SYSCALL(getppid)); +} + +int internal_dlinfo(void *handle, int request, void *p) { +#if SANITIZER_FREEBSD + return dlinfo(handle, request, p); +#else + UNIMPLEMENTED(); +#endif +} + +uptr internal_getdents(fd_t fd, struct linux_dirent *dirp, unsigned int count) { +#if SANITIZER_FREEBSD + return internal_syscall(SYSCALL(getdirentries), fd, (uptr)dirp, count, NULL); +#elif SANITIZER_USES_CANONICAL_LINUX_SYSCALLS + return internal_syscall(SYSCALL(getdents64), fd, (uptr)dirp, count); +#else + return internal_syscall(SYSCALL(getdents), fd, (uptr)dirp, count); +#endif +} + +uptr internal_lseek(fd_t fd, OFF_T offset, int whence) { + return internal_syscall(SYSCALL(lseek), fd, offset, whence); +} + +#if SANITIZER_LINUX +uptr internal_prctl(int option, uptr arg2, uptr arg3, uptr arg4, uptr arg5) { + return internal_syscall(SYSCALL(prctl), option, arg2, arg3, arg4, arg5); +} +#endif + +uptr internal_sigaltstack(const void *ss, void *oss) { + return internal_syscall(SYSCALL(sigaltstack), (uptr)ss, (uptr)oss); +} + +int internal_fork() { +#if SANITIZER_USES_CANONICAL_LINUX_SYSCALLS + return internal_syscall(SYSCALL(clone), SIGCHLD, 0); +#else + return internal_syscall(SYSCALL(fork)); +#endif +} + +#if SANITIZER_FREEBSD +int internal_sysctl(const int *name, unsigned int namelen, void *oldp, + uptr *oldlenp, const void *newp, uptr newlen) { + return internal_syscall(SYSCALL(__sysctl), name, namelen, oldp, + (size_t *)oldlenp, newp, (size_t)newlen); +} + +int internal_sysctlbyname(const char *sname, void *oldp, uptr *oldlenp, + const void *newp, uptr newlen) { + // Note: this function can be called during startup, so we need to avoid + // calling any interceptable functions. On FreeBSD >= 1300045 sysctlbyname() + // is a real syscall, but for older versions it calls sysctlnametomib() + // followed by sysctl(). To avoid calling the intercepted version and + // asserting if this happens during startup, call the real sysctlnametomib() + // followed by internal_sysctl() if the syscall is not available. +#ifdef SYS___sysctlbyname + return internal_syscall(SYSCALL(__sysctlbyname), sname, + internal_strlen(sname), oldp, (size_t *)oldlenp, newp, + (size_t)newlen); +#else + static decltype(sysctlnametomib) *real_sysctlnametomib = nullptr; + if (!real_sysctlnametomib) + real_sysctlnametomib = + (decltype(sysctlnametomib) *)dlsym(RTLD_NEXT, "sysctlnametomib"); + CHECK(real_sysctlnametomib); + + int oid[CTL_MAXNAME]; + size_t len = CTL_MAXNAME; + if (real_sysctlnametomib(sname, oid, &len) == -1) + return (-1); + return internal_sysctl(oid, len, oldp, oldlenp, newp, newlen); +#endif +} +#endif + +#if SANITIZER_LINUX +#define SA_RESTORER 0x04000000 +// Doesn't set sa_restorer if the caller did not set it, so use with caution +//(see below). +int internal_sigaction_norestorer(int signum, const void *act, void *oldact) { + __sanitizer_kernel_sigaction_t k_act, k_oldact; + internal_memset(&k_act, 0, sizeof(__sanitizer_kernel_sigaction_t)); + internal_memset(&k_oldact, 0, sizeof(__sanitizer_kernel_sigaction_t)); + const __sanitizer_sigaction *u_act = (const __sanitizer_sigaction *)act; + __sanitizer_sigaction *u_oldact = (__sanitizer_sigaction *)oldact; + if (u_act) { + k_act.handler = u_act->handler; + k_act.sigaction = u_act->sigaction; + internal_memcpy(&k_act.sa_mask, &u_act->sa_mask, + sizeof(__sanitizer_kernel_sigset_t)); + // Without SA_RESTORER kernel ignores the calls (probably returns EINVAL). + k_act.sa_flags = u_act->sa_flags | SA_RESTORER; + // FIXME: most often sa_restorer is unset, however the kernel requires it + // to point to a valid signal restorer that calls the rt_sigreturn syscall. + // If sa_restorer passed to the kernel is NULL, the program may crash upon + // signal delivery or fail to unwind the stack in the signal handler. + // libc implementation of sigaction() passes its own restorer to + // rt_sigaction, so we need to do the same (we'll need to reimplement the + // restorers; for x86_64 the restorer address can be obtained from + // oldact->sa_restorer upon a call to sigaction(xxx, NULL, oldact). +#if !SANITIZER_ANDROID || !SANITIZER_MIPS32 + k_act.sa_restorer = u_act->sa_restorer; +#endif + } + + uptr result = internal_syscall(SYSCALL(rt_sigaction), (uptr)signum, + (uptr)(u_act ? &k_act : nullptr), + (uptr)(u_oldact ? &k_oldact : nullptr), + (uptr)sizeof(__sanitizer_kernel_sigset_t)); + + if ((result == 0) && u_oldact) { + u_oldact->handler = k_oldact.handler; + u_oldact->sigaction = k_oldact.sigaction; + internal_memcpy(&u_oldact->sa_mask, &k_oldact.sa_mask, + sizeof(__sanitizer_kernel_sigset_t)); + u_oldact->sa_flags = k_oldact.sa_flags; +#if !SANITIZER_ANDROID || !SANITIZER_MIPS32 + u_oldact->sa_restorer = k_oldact.sa_restorer; +#endif + } + return result; +} +#endif // SANITIZER_LINUX + +uptr internal_sigprocmask(int how, __sanitizer_sigset_t *set, + __sanitizer_sigset_t *oldset) { +#if SANITIZER_FREEBSD + return internal_syscall(SYSCALL(sigprocmask), how, set, oldset); +#else + __sanitizer_kernel_sigset_t *k_set = (__sanitizer_kernel_sigset_t *)set; + __sanitizer_kernel_sigset_t *k_oldset = (__sanitizer_kernel_sigset_t *)oldset; + return internal_syscall(SYSCALL(rt_sigprocmask), (uptr)how, (uptr)k_set, + (uptr)k_oldset, sizeof(__sanitizer_kernel_sigset_t)); +#endif +} + +void internal_sigfillset(__sanitizer_sigset_t *set) { + internal_memset(set, 0xff, sizeof(*set)); +} + +void internal_sigemptyset(__sanitizer_sigset_t *set) { + internal_memset(set, 0, sizeof(*set)); +} + +#if SANITIZER_LINUX +void internal_sigdelset(__sanitizer_sigset_t *set, int signum) { + signum -= 1; + CHECK_GE(signum, 0); + CHECK_LT(signum, sizeof(*set) * 8); + __sanitizer_kernel_sigset_t *k_set = (__sanitizer_kernel_sigset_t *)set; + const uptr idx = signum / (sizeof(k_set->sig[0]) * 8); + const uptr bit = signum % (sizeof(k_set->sig[0]) * 8); + k_set->sig[idx] &= ~((uptr)1 << bit); +} + +bool internal_sigismember(__sanitizer_sigset_t *set, int signum) { + signum -= 1; + CHECK_GE(signum, 0); + CHECK_LT(signum, sizeof(*set) * 8); + __sanitizer_kernel_sigset_t *k_set = (__sanitizer_kernel_sigset_t *)set; + const uptr idx = signum / (sizeof(k_set->sig[0]) * 8); + const uptr bit = signum % (sizeof(k_set->sig[0]) * 8); + return k_set->sig[idx] & ((uptr)1 << bit); +} +#elif SANITIZER_FREEBSD +void internal_sigdelset(__sanitizer_sigset_t *set, int signum) { + sigset_t *rset = reinterpret_cast<sigset_t *>(set); + sigdelset(rset, signum); +} + +bool internal_sigismember(__sanitizer_sigset_t *set, int signum) { + sigset_t *rset = reinterpret_cast<sigset_t *>(set); + return sigismember(rset, signum); +} +#endif +#endif // !SANITIZER_SOLARIS + +#if !SANITIZER_NETBSD +// ThreadLister implementation. +ThreadLister::ThreadLister(pid_t pid) : pid_(pid), buffer_(4096) { + char task_directory_path[80]; + internal_snprintf(task_directory_path, sizeof(task_directory_path), + "/proc/%d/task/", pid); + descriptor_ = internal_open(task_directory_path, O_RDONLY | O_DIRECTORY); + if (internal_iserror(descriptor_)) { + Report("Can't open /proc/%d/task for reading.\n", pid); + } +} + +ThreadLister::Result ThreadLister::ListThreads( + InternalMmapVector<tid_t> *threads) { + if (internal_iserror(descriptor_)) + return Error; + internal_lseek(descriptor_, 0, SEEK_SET); + threads->clear(); + + Result result = Ok; + for (bool first_read = true;; first_read = false) { + // Resize to max capacity if it was downsized by IsAlive. + buffer_.resize(buffer_.capacity()); + CHECK_GE(buffer_.size(), 4096); + uptr read = internal_getdents( + descriptor_, (struct linux_dirent *)buffer_.data(), buffer_.size()); + if (!read) + return result; + if (internal_iserror(read)) { + Report("Can't read directory entries from /proc/%d/task.\n", pid_); + return Error; + } + + for (uptr begin = (uptr)buffer_.data(), end = begin + read; begin < end;) { + struct linux_dirent *entry = (struct linux_dirent *)begin; + begin += entry->d_reclen; + if (entry->d_ino == 1) { + // Inode 1 is for bad blocks and also can be a reason for early return. + // Should be emitted if kernel tried to output terminating thread. + // See proc_task_readdir implementation in Linux. + result = Incomplete; + } + if (entry->d_ino && *entry->d_name >= '0' && *entry->d_name <= '9') + threads->push_back(internal_atoll(entry->d_name)); + } + + // Now we are going to detect short-read or early EOF. In such cases Linux + // can return inconsistent list with missing alive threads. + // Code will just remember that the list can be incomplete but it will + // continue reads to return as much as possible. + if (!first_read) { + // The first one was a short-read by definition. + result = Incomplete; + } else if (read > buffer_.size() - 1024) { + // Read was close to the buffer size. So double the size and assume the + // worst. + buffer_.resize(buffer_.size() * 2); + result = Incomplete; + } else if (!threads->empty() && !IsAlive(threads->back())) { + // Maybe Linux early returned from read on terminated thread (!pid_alive) + // and failed to restore read position. + // See next_tid and proc_task_instantiate in Linux. + result = Incomplete; + } + } +} + +bool ThreadLister::IsAlive(int tid) { + // /proc/%d/task/%d/status uses same call to detect alive threads as + // proc_task_readdir. See task_state implementation in Linux. + char path[80]; + internal_snprintf(path, sizeof(path), "/proc/%d/task/%d/status", pid_, tid); + if (!ReadFileToVector(path, &buffer_) || buffer_.empty()) + return false; + buffer_.push_back(0); + static const char kPrefix[] = "\nPPid:"; + const char *field = internal_strstr(buffer_.data(), kPrefix); + if (!field) + return false; + field += internal_strlen(kPrefix); + return (int)internal_atoll(field) != 0; +} + +ThreadLister::~ThreadLister() { + if (!internal_iserror(descriptor_)) + internal_close(descriptor_); +} +#endif + +#if SANITIZER_WORDSIZE == 32 +// Take care of unusable kernel area in top gigabyte. +static uptr GetKernelAreaSize() { +#if SANITIZER_LINUX && !SANITIZER_X32 + const uptr gbyte = 1UL << 30; + + // Firstly check if there are writable segments + // mapped to top gigabyte (e.g. stack). + MemoryMappingLayout proc_maps(/*cache_enabled*/true); + if (proc_maps.Error()) + return 0; + MemoryMappedSegment segment; + while (proc_maps.Next(&segment)) { + if ((segment.end >= 3 * gbyte) && segment.IsWritable()) return 0; + } + +#if !SANITIZER_ANDROID + // Even if nothing is mapped, top Gb may still be accessible + // if we are running on 64-bit kernel. + // Uname may report misleading results if personality type + // is modified (e.g. under schroot) so check this as well. + struct utsname uname_info; + int pers = personality(0xffffffffUL); + if (!(pers & PER_MASK) && internal_uname(&uname_info) == 0 && + internal_strstr(uname_info.machine, "64")) + return 0; +#endif // SANITIZER_ANDROID + + // Top gigabyte is reserved for kernel. + return gbyte; +#else + return 0; +#endif // SANITIZER_LINUX && !SANITIZER_X32 +} +#endif // SANITIZER_WORDSIZE == 32 + +uptr GetMaxVirtualAddress() { +#if SANITIZER_NETBSD && defined(__x86_64__) + return 0x7f7ffffff000ULL; // (0x00007f8000000000 - PAGE_SIZE) +#elif SANITIZER_WORDSIZE == 64 +# if defined(__powerpc64__) || defined(__aarch64__) + // On PowerPC64 we have two different address space layouts: 44- and 46-bit. + // We somehow need to figure out which one we are using now and choose + // one of 0x00000fffffffffffUL and 0x00003fffffffffffUL. + // Note that with 'ulimit -s unlimited' the stack is moved away from the top + // of the address space, so simply checking the stack address is not enough. + // This should (does) work for both PowerPC64 Endian modes. + // Similarly, aarch64 has multiple address space layouts: 39, 42 and 47-bit. + return (1ULL << (MostSignificantSetBitIndex(GET_CURRENT_FRAME()) + 1)) - 1; +#elif SANITIZER_RISCV64 + return (1ULL << 38) - 1; +# elif defined(__mips64) + return (1ULL << 40) - 1; // 0x000000ffffffffffUL; +# elif defined(__s390x__) + return (1ULL << 53) - 1; // 0x001fffffffffffffUL; +#elif defined(__sparc__) + return ~(uptr)0; +# else + return (1ULL << 47) - 1; // 0x00007fffffffffffUL; +# endif +#else // SANITIZER_WORDSIZE == 32 +# if defined(__s390__) + return (1ULL << 31) - 1; // 0x7fffffff; +# else + return (1ULL << 32) - 1; // 0xffffffff; +# endif +#endif // SANITIZER_WORDSIZE +} + +uptr GetMaxUserVirtualAddress() { + uptr addr = GetMaxVirtualAddress(); +#if SANITIZER_WORDSIZE == 32 && !defined(__s390__) + if (!common_flags()->full_address_space) + addr -= GetKernelAreaSize(); + CHECK_LT(reinterpret_cast<uptr>(&addr), addr); +#endif + return addr; +} + +#if !SANITIZER_ANDROID +uptr GetPageSize() { +#if SANITIZER_LINUX && (defined(__x86_64__) || defined(__i386__)) && \ + defined(EXEC_PAGESIZE) + return EXEC_PAGESIZE; +#elif SANITIZER_FREEBSD || SANITIZER_NETBSD +// Use sysctl as sysconf can trigger interceptors internally. + int pz = 0; + uptr pzl = sizeof(pz); + int mib[2] = {CTL_HW, HW_PAGESIZE}; + int rv = internal_sysctl(mib, 2, &pz, &pzl, nullptr, 0); + CHECK_EQ(rv, 0); + return (uptr)pz; +#elif SANITIZER_USE_GETAUXVAL + return getauxval(AT_PAGESZ); +#else + return sysconf(_SC_PAGESIZE); // EXEC_PAGESIZE may not be trustworthy. +#endif +} +#endif // !SANITIZER_ANDROID + +uptr ReadBinaryName(/*out*/char *buf, uptr buf_len) { +#if SANITIZER_SOLARIS + const char *default_module_name = getexecname(); + CHECK_NE(default_module_name, NULL); + return internal_snprintf(buf, buf_len, "%s", default_module_name); +#else +#if SANITIZER_FREEBSD || SANITIZER_NETBSD +#if SANITIZER_FREEBSD + const int Mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1}; +#else + const int Mib[4] = {CTL_KERN, KERN_PROC_ARGS, -1, KERN_PROC_PATHNAME}; +#endif + const char *default_module_name = "kern.proc.pathname"; + uptr Size = buf_len; + bool IsErr = + (internal_sysctl(Mib, ARRAY_SIZE(Mib), buf, &Size, NULL, 0) != 0); + int readlink_error = IsErr ? errno : 0; + uptr module_name_len = Size; +#else + const char *default_module_name = "/proc/self/exe"; + uptr module_name_len = internal_readlink( + default_module_name, buf, buf_len); + int readlink_error; + bool IsErr = internal_iserror(module_name_len, &readlink_error); +#endif // SANITIZER_SOLARIS + if (IsErr) { + // We can't read binary name for some reason, assume it's unknown. + Report("WARNING: reading executable name failed with errno %d, " + "some stack frames may not be symbolized\n", readlink_error); + module_name_len = internal_snprintf(buf, buf_len, "%s", + default_module_name); + CHECK_LT(module_name_len, buf_len); + } + return module_name_len; +#endif +} + +uptr ReadLongProcessName(/*out*/ char *buf, uptr buf_len) { +#if SANITIZER_LINUX + char *tmpbuf; + uptr tmpsize; + uptr tmplen; + if (ReadFileToBuffer("/proc/self/cmdline", &tmpbuf, &tmpsize, &tmplen, + 1024 * 1024)) { + internal_strncpy(buf, tmpbuf, buf_len); + UnmapOrDie(tmpbuf, tmpsize); + return internal_strlen(buf); + } +#endif + return ReadBinaryName(buf, buf_len); +} + +// Match full names of the form /path/to/base_name{-,.}* +bool LibraryNameIs(const char *full_name, const char *base_name) { + const char *name = full_name; + // Strip path. + while (*name != '\0') name++; + while (name > full_name && *name != '/') name--; + if (*name == '/') name++; + uptr base_name_length = internal_strlen(base_name); + if (internal_strncmp(name, base_name, base_name_length)) return false; + return (name[base_name_length] == '-' || name[base_name_length] == '.'); +} + +#if !SANITIZER_ANDROID +// Call cb for each region mapped by map. +void ForEachMappedRegion(link_map *map, void (*cb)(const void *, uptr)) { + CHECK_NE(map, nullptr); +#if !SANITIZER_FREEBSD + typedef ElfW(Phdr) Elf_Phdr; + typedef ElfW(Ehdr) Elf_Ehdr; +#endif // !SANITIZER_FREEBSD + char *base = (char *)map->l_addr; + Elf_Ehdr *ehdr = (Elf_Ehdr *)base; + char *phdrs = base + ehdr->e_phoff; + char *phdrs_end = phdrs + ehdr->e_phnum * ehdr->e_phentsize; + + // Find the segment with the minimum base so we can "relocate" the p_vaddr + // fields. Typically ET_DYN objects (DSOs) have base of zero and ET_EXEC + // objects have a non-zero base. + uptr preferred_base = (uptr)-1; + for (char *iter = phdrs; iter != phdrs_end; iter += ehdr->e_phentsize) { + Elf_Phdr *phdr = (Elf_Phdr *)iter; + if (phdr->p_type == PT_LOAD && preferred_base > (uptr)phdr->p_vaddr) + preferred_base = (uptr)phdr->p_vaddr; + } + + // Compute the delta from the real base to get a relocation delta. + sptr delta = (uptr)base - preferred_base; + // Now we can figure out what the loader really mapped. + for (char *iter = phdrs; iter != phdrs_end; iter += ehdr->e_phentsize) { + Elf_Phdr *phdr = (Elf_Phdr *)iter; + if (phdr->p_type == PT_LOAD) { + uptr seg_start = phdr->p_vaddr + delta; + uptr seg_end = seg_start + phdr->p_memsz; + // None of these values are aligned. We consider the ragged edges of the + // load command as defined, since they are mapped from the file. + seg_start = RoundDownTo(seg_start, GetPageSizeCached()); + seg_end = RoundUpTo(seg_end, GetPageSizeCached()); + cb((void *)seg_start, seg_end - seg_start); + } + } +} +#endif + +#if SANITIZER_LINUX +#if defined(__x86_64__) +// We cannot use glibc's clone wrapper, because it messes with the child +// task's TLS. It writes the PID and TID of the child task to its thread +// descriptor, but in our case the child task shares the thread descriptor with +// the parent (because we don't know how to allocate a new thread +// descriptor to keep glibc happy). So the stock version of clone(), when +// used with CLONE_VM, would end up corrupting the parent's thread descriptor. +uptr internal_clone(int (*fn)(void *), void *child_stack, int flags, void *arg, + int *parent_tidptr, void *newtls, int *child_tidptr) { + long long res; + if (!fn || !child_stack) + return -EINVAL; + CHECK_EQ(0, (uptr)child_stack % 16); + child_stack = (char *)child_stack - 2 * sizeof(unsigned long long); + ((unsigned long long *)child_stack)[0] = (uptr)fn; + ((unsigned long long *)child_stack)[1] = (uptr)arg; + register void *r8 __asm__("r8") = newtls; + register int *r10 __asm__("r10") = child_tidptr; + __asm__ __volatile__( + /* %rax = syscall(%rax = SYSCALL(clone), + * %rdi = flags, + * %rsi = child_stack, + * %rdx = parent_tidptr, + * %r8 = new_tls, + * %r10 = child_tidptr) + */ + "syscall\n" + + /* if (%rax != 0) + * return; + */ + "testq %%rax,%%rax\n" + "jnz 1f\n" + + /* In the child. Terminate unwind chain. */ + // XXX: We should also terminate the CFI unwind chain + // here. Unfortunately clang 3.2 doesn't support the + // necessary CFI directives, so we skip that part. + "xorq %%rbp,%%rbp\n" + + /* Call "fn(arg)". */ + "popq %%rax\n" + "popq %%rdi\n" + "call *%%rax\n" + + /* Call _exit(%rax). */ + "movq %%rax,%%rdi\n" + "movq %2,%%rax\n" + "syscall\n" + + /* Return to parent. */ + "1:\n" + : "=a" (res) + : "a"(SYSCALL(clone)), "i"(SYSCALL(exit)), + "S"(child_stack), + "D"(flags), + "d"(parent_tidptr), + "r"(r8), + "r"(r10) + : "memory", "r11", "rcx"); + return res; +} +#elif defined(__mips__) +uptr internal_clone(int (*fn)(void *), void *child_stack, int flags, void *arg, + int *parent_tidptr, void *newtls, int *child_tidptr) { + long long res; + if (!fn || !child_stack) + return -EINVAL; + CHECK_EQ(0, (uptr)child_stack % 16); + child_stack = (char *)child_stack - 2 * sizeof(unsigned long long); + ((unsigned long long *)child_stack)[0] = (uptr)fn; + ((unsigned long long *)child_stack)[1] = (uptr)arg; + register void *a3 __asm__("$7") = newtls; + register int *a4 __asm__("$8") = child_tidptr; + // We don't have proper CFI directives here because it requires alot of code + // for very marginal benefits. + __asm__ __volatile__( + /* $v0 = syscall($v0 = __NR_clone, + * $a0 = flags, + * $a1 = child_stack, + * $a2 = parent_tidptr, + * $a3 = new_tls, + * $a4 = child_tidptr) + */ + ".cprestore 16;\n" + "move $4,%1;\n" + "move $5,%2;\n" + "move $6,%3;\n" + "move $7,%4;\n" + /* Store the fifth argument on stack + * if we are using 32-bit abi. + */ +#if SANITIZER_WORDSIZE == 32 + "lw %5,16($29);\n" +#else + "move $8,%5;\n" +#endif + "li $2,%6;\n" + "syscall;\n" + + /* if ($v0 != 0) + * return; + */ + "bnez $2,1f;\n" + + /* Call "fn(arg)". */ +#if SANITIZER_WORDSIZE == 32 +#ifdef __BIG_ENDIAN__ + "lw $25,4($29);\n" + "lw $4,12($29);\n" +#else + "lw $25,0($29);\n" + "lw $4,8($29);\n" +#endif +#else + "ld $25,0($29);\n" + "ld $4,8($29);\n" +#endif + "jal $25;\n" + + /* Call _exit($v0). */ + "move $4,$2;\n" + "li $2,%7;\n" + "syscall;\n" + + /* Return to parent. */ + "1:\n" + : "=r" (res) + : "r"(flags), + "r"(child_stack), + "r"(parent_tidptr), + "r"(a3), + "r"(a4), + "i"(__NR_clone), + "i"(__NR_exit) + : "memory", "$29" ); + return res; +} +#elif SANITIZER_RISCV64 +uptr internal_clone(int (*fn)(void *), void *child_stack, int flags, void *arg, + int *parent_tidptr, void *newtls, int *child_tidptr) { + if (!fn || !child_stack) + return -EINVAL; + + CHECK_EQ(0, (uptr)child_stack % 16); + + register int res __asm__("a0"); + register int __flags __asm__("a0") = flags; + register void *__stack __asm__("a1") = child_stack; + register int *__ptid __asm__("a2") = parent_tidptr; + register void *__tls __asm__("a3") = newtls; + register int *__ctid __asm__("a4") = child_tidptr; + register int (*__fn)(void *) __asm__("a5") = fn; + register void *__arg __asm__("a6") = arg; + register int nr_clone __asm__("a7") = __NR_clone; + + __asm__ __volatile__( + "ecall\n" + + /* if (a0 != 0) + * return a0; + */ + "bnez a0, 1f\n" + + // In the child, now. Call "fn(arg)". + "mv a0, a6\n" + "jalr a5\n" + + // Call _exit(a0). + "addi a7, zero, %9\n" + "ecall\n" + "1:\n" + + : "=r"(res) + : "0"(__flags), "r"(__stack), "r"(__ptid), "r"(__tls), "r"(__ctid), + "r"(__fn), "r"(__arg), "r"(nr_clone), "i"(__NR_exit) + : "memory"); + return res; +} +#elif defined(__aarch64__) +uptr internal_clone(int (*fn)(void *), void *child_stack, int flags, void *arg, + int *parent_tidptr, void *newtls, int *child_tidptr) { + register long long res __asm__("x0"); + if (!fn || !child_stack) + return -EINVAL; + CHECK_EQ(0, (uptr)child_stack % 16); + child_stack = (char *)child_stack - 2 * sizeof(unsigned long long); + ((unsigned long long *)child_stack)[0] = (uptr)fn; + ((unsigned long long *)child_stack)[1] = (uptr)arg; + + register int (*__fn)(void *) __asm__("x0") = fn; + register void *__stack __asm__("x1") = child_stack; + register int __flags __asm__("x2") = flags; + register void *__arg __asm__("x3") = arg; + register int *__ptid __asm__("x4") = parent_tidptr; + register void *__tls __asm__("x5") = newtls; + register int *__ctid __asm__("x6") = child_tidptr; + + __asm__ __volatile__( + "mov x0,x2\n" /* flags */ + "mov x2,x4\n" /* ptid */ + "mov x3,x5\n" /* tls */ + "mov x4,x6\n" /* ctid */ + "mov x8,%9\n" /* clone */ + + "svc 0x0\n" + + /* if (%r0 != 0) + * return %r0; + */ + "cmp x0, #0\n" + "bne 1f\n" + + /* In the child, now. Call "fn(arg)". */ + "ldp x1, x0, [sp], #16\n" + "blr x1\n" + + /* Call _exit(%r0). */ + "mov x8, %10\n" + "svc 0x0\n" + "1:\n" + + : "=r" (res) + : "i"(-EINVAL), + "r"(__fn), "r"(__stack), "r"(__flags), "r"(__arg), + "r"(__ptid), "r"(__tls), "r"(__ctid), + "i"(__NR_clone), "i"(__NR_exit) + : "x30", "memory"); + return res; +} +#elif defined(__powerpc64__) +uptr internal_clone(int (*fn)(void *), void *child_stack, int flags, void *arg, + int *parent_tidptr, void *newtls, int *child_tidptr) { + long long res; +// Stack frame structure. +#if SANITIZER_PPC64V1 +// Back chain == 0 (SP + 112) +// Frame (112 bytes): +// Parameter save area (SP + 48), 8 doublewords +// TOC save area (SP + 40) +// Link editor doubleword (SP + 32) +// Compiler doubleword (SP + 24) +// LR save area (SP + 16) +// CR save area (SP + 8) +// Back chain (SP + 0) +# define FRAME_SIZE 112 +# define FRAME_TOC_SAVE_OFFSET 40 +#elif SANITIZER_PPC64V2 +// Back chain == 0 (SP + 32) +// Frame (32 bytes): +// TOC save area (SP + 24) +// LR save area (SP + 16) +// CR save area (SP + 8) +// Back chain (SP + 0) +# define FRAME_SIZE 32 +# define FRAME_TOC_SAVE_OFFSET 24 +#else +# error "Unsupported PPC64 ABI" +#endif + if (!fn || !child_stack) + return -EINVAL; + CHECK_EQ(0, (uptr)child_stack % 16); + + register int (*__fn)(void *) __asm__("r3") = fn; + register void *__cstack __asm__("r4") = child_stack; + register int __flags __asm__("r5") = flags; + register void *__arg __asm__("r6") = arg; + register int *__ptidptr __asm__("r7") = parent_tidptr; + register void *__newtls __asm__("r8") = newtls; + register int *__ctidptr __asm__("r9") = child_tidptr; + + __asm__ __volatile__( + /* fn and arg are saved across the syscall */ + "mr 28, %5\n\t" + "mr 27, %8\n\t" + + /* syscall + r0 == __NR_clone + r3 == flags + r4 == child_stack + r5 == parent_tidptr + r6 == newtls + r7 == child_tidptr */ + "mr 3, %7\n\t" + "mr 5, %9\n\t" + "mr 6, %10\n\t" + "mr 7, %11\n\t" + "li 0, %3\n\t" + "sc\n\t" + + /* Test if syscall was successful */ + "cmpdi cr1, 3, 0\n\t" + "crandc cr1*4+eq, cr1*4+eq, cr0*4+so\n\t" + "bne- cr1, 1f\n\t" + + /* Set up stack frame */ + "li 29, 0\n\t" + "stdu 29, -8(1)\n\t" + "stdu 1, -%12(1)\n\t" + /* Do the function call */ + "std 2, %13(1)\n\t" +#if SANITIZER_PPC64V1 + "ld 0, 0(28)\n\t" + "ld 2, 8(28)\n\t" + "mtctr 0\n\t" +#elif SANITIZER_PPC64V2 + "mr 12, 28\n\t" + "mtctr 12\n\t" +#else +# error "Unsupported PPC64 ABI" +#endif + "mr 3, 27\n\t" + "bctrl\n\t" + "ld 2, %13(1)\n\t" + + /* Call _exit(r3) */ + "li 0, %4\n\t" + "sc\n\t" + + /* Return to parent */ + "1:\n\t" + "mr %0, 3\n\t" + : "=r" (res) + : "0" (-1), + "i" (EINVAL), + "i" (__NR_clone), + "i" (__NR_exit), + "r" (__fn), + "r" (__cstack), + "r" (__flags), + "r" (__arg), + "r" (__ptidptr), + "r" (__newtls), + "r" (__ctidptr), + "i" (FRAME_SIZE), + "i" (FRAME_TOC_SAVE_OFFSET) + : "cr0", "cr1", "memory", "ctr", "r0", "r27", "r28", "r29"); + return res; +} +#elif defined(__i386__) +uptr internal_clone(int (*fn)(void *), void *child_stack, int flags, void *arg, + int *parent_tidptr, void *newtls, int *child_tidptr) { + int res; + if (!fn || !child_stack) + return -EINVAL; + CHECK_EQ(0, (uptr)child_stack % 16); + child_stack = (char *)child_stack - 7 * sizeof(unsigned int); + ((unsigned int *)child_stack)[0] = (uptr)flags; + ((unsigned int *)child_stack)[1] = (uptr)0; + ((unsigned int *)child_stack)[2] = (uptr)fn; + ((unsigned int *)child_stack)[3] = (uptr)arg; + __asm__ __volatile__( + /* %eax = syscall(%eax = SYSCALL(clone), + * %ebx = flags, + * %ecx = child_stack, + * %edx = parent_tidptr, + * %esi = new_tls, + * %edi = child_tidptr) + */ + + /* Obtain flags */ + "movl (%%ecx), %%ebx\n" + /* Do the system call */ + "pushl %%ebx\n" + "pushl %%esi\n" + "pushl %%edi\n" + /* Remember the flag value. */ + "movl %%ebx, (%%ecx)\n" + "int $0x80\n" + "popl %%edi\n" + "popl %%esi\n" + "popl %%ebx\n" + + /* if (%eax != 0) + * return; + */ + + "test %%eax,%%eax\n" + "jnz 1f\n" + + /* terminate the stack frame */ + "xorl %%ebp,%%ebp\n" + /* Call FN. */ + "call *%%ebx\n" +#ifdef PIC + "call here\n" + "here:\n" + "popl %%ebx\n" + "addl $_GLOBAL_OFFSET_TABLE_+[.-here], %%ebx\n" +#endif + /* Call exit */ + "movl %%eax, %%ebx\n" + "movl %2, %%eax\n" + "int $0x80\n" + "1:\n" + : "=a" (res) + : "a"(SYSCALL(clone)), "i"(SYSCALL(exit)), + "c"(child_stack), + "d"(parent_tidptr), + "S"(newtls), + "D"(child_tidptr) + : "memory"); + return res; +} +#elif defined(__arm__) +uptr internal_clone(int (*fn)(void *), void *child_stack, int flags, void *arg, + int *parent_tidptr, void *newtls, int *child_tidptr) { + unsigned int res; + if (!fn || !child_stack) + return -EINVAL; + child_stack = (char *)child_stack - 2 * sizeof(unsigned int); + ((unsigned int *)child_stack)[0] = (uptr)fn; + ((unsigned int *)child_stack)[1] = (uptr)arg; + register int r0 __asm__("r0") = flags; + register void *r1 __asm__("r1") = child_stack; + register int *r2 __asm__("r2") = parent_tidptr; + register void *r3 __asm__("r3") = newtls; + register int *r4 __asm__("r4") = child_tidptr; + register int r7 __asm__("r7") = __NR_clone; + +#if __ARM_ARCH > 4 || defined (__ARM_ARCH_4T__) +# define ARCH_HAS_BX +#endif +#if __ARM_ARCH > 4 +# define ARCH_HAS_BLX +#endif + +#ifdef ARCH_HAS_BX +# ifdef ARCH_HAS_BLX +# define BLX(R) "blx " #R "\n" +# else +# define BLX(R) "mov lr, pc; bx " #R "\n" +# endif +#else +# define BLX(R) "mov lr, pc; mov pc," #R "\n" +#endif + + __asm__ __volatile__( + /* %r0 = syscall(%r7 = SYSCALL(clone), + * %r0 = flags, + * %r1 = child_stack, + * %r2 = parent_tidptr, + * %r3 = new_tls, + * %r4 = child_tidptr) + */ + + /* Do the system call */ + "swi 0x0\n" + + /* if (%r0 != 0) + * return %r0; + */ + "cmp r0, #0\n" + "bne 1f\n" + + /* In the child, now. Call "fn(arg)". */ + "ldr r0, [sp, #4]\n" + "ldr ip, [sp], #8\n" + BLX(ip) + /* Call _exit(%r0). */ + "mov r7, %7\n" + "swi 0x0\n" + "1:\n" + "mov %0, r0\n" + : "=r"(res) + : "r"(r0), "r"(r1), "r"(r2), "r"(r3), "r"(r4), "r"(r7), + "i"(__NR_exit) + : "memory"); + return res; +} +#endif +#endif // SANITIZER_LINUX + +#if SANITIZER_LINUX +int internal_uname(struct utsname *buf) { + return internal_syscall(SYSCALL(uname), buf); +} +#endif + +#if SANITIZER_ANDROID +#if __ANDROID_API__ < 21 +extern "C" __attribute__((weak)) int dl_iterate_phdr( + int (*)(struct dl_phdr_info *, size_t, void *), void *); +#endif + +static int dl_iterate_phdr_test_cb(struct dl_phdr_info *info, size_t size, + void *data) { + // Any name starting with "lib" indicates a bug in L where library base names + // are returned instead of paths. + if (info->dlpi_name && info->dlpi_name[0] == 'l' && + info->dlpi_name[1] == 'i' && info->dlpi_name[2] == 'b') { + *(bool *)data = true; + return 1; + } + return 0; +} + +static atomic_uint32_t android_api_level; + +static AndroidApiLevel AndroidDetectApiLevelStatic() { +#if __ANDROID_API__ <= 19 + return ANDROID_KITKAT; +#elif __ANDROID_API__ <= 22 + return ANDROID_LOLLIPOP_MR1; +#else + return ANDROID_POST_LOLLIPOP; +#endif +} + +static AndroidApiLevel AndroidDetectApiLevel() { + if (!&dl_iterate_phdr) + return ANDROID_KITKAT; // K or lower + bool base_name_seen = false; + dl_iterate_phdr(dl_iterate_phdr_test_cb, &base_name_seen); + if (base_name_seen) + return ANDROID_LOLLIPOP_MR1; // L MR1 + return ANDROID_POST_LOLLIPOP; // post-L + // Plain L (API level 21) is completely broken wrt ASan and not very + // interesting to detect. +} + +extern "C" __attribute__((weak)) void* _DYNAMIC; + +AndroidApiLevel AndroidGetApiLevel() { + AndroidApiLevel level = + (AndroidApiLevel)atomic_load(&android_api_level, memory_order_relaxed); + if (level) return level; + level = &_DYNAMIC == nullptr ? AndroidDetectApiLevelStatic() + : AndroidDetectApiLevel(); + atomic_store(&android_api_level, level, memory_order_relaxed); + return level; +} + +#endif + +static HandleSignalMode GetHandleSignalModeImpl(int signum) { + switch (signum) { + case SIGABRT: + return common_flags()->handle_abort; + case SIGILL: + return common_flags()->handle_sigill; + case SIGTRAP: + return common_flags()->handle_sigtrap; + case SIGFPE: + return common_flags()->handle_sigfpe; + case SIGSEGV: + return common_flags()->handle_segv; + case SIGBUS: + return common_flags()->handle_sigbus; + } + return kHandleSignalNo; +} + +HandleSignalMode GetHandleSignalMode(int signum) { + HandleSignalMode result = GetHandleSignalModeImpl(signum); + if (result == kHandleSignalYes && !common_flags()->allow_user_segv_handler) + return kHandleSignalExclusive; + return result; +} + +#if !SANITIZER_GO +void *internal_start_thread(void *(*func)(void *arg), void *arg) { + if (&real_pthread_create == 0) + return nullptr; + // Start the thread with signals blocked, otherwise it can steal user signals. + ScopedBlockSignals block(nullptr); + void *th; + real_pthread_create(&th, nullptr, func, arg); + return th; +} + +void internal_join_thread(void *th) { + if (&real_pthread_join) + real_pthread_join(th, nullptr); +} +#else +void *internal_start_thread(void *(*func)(void *), void *arg) { return 0; } + +void internal_join_thread(void *th) {} +#endif + +#if defined(__aarch64__) +// Android headers in the older NDK releases miss this definition. +struct __sanitizer_esr_context { + struct _aarch64_ctx head; + uint64_t esr; +}; + +static bool Aarch64GetESR(ucontext_t *ucontext, u64 *esr) { + static const u32 kEsrMagic = 0x45535201; + u8 *aux = reinterpret_cast<u8 *>(ucontext->uc_mcontext.__reserved); + while (true) { + _aarch64_ctx *ctx = (_aarch64_ctx *)aux; + if (ctx->size == 0) break; + if (ctx->magic == kEsrMagic) { + *esr = ((__sanitizer_esr_context *)ctx)->esr; + return true; + } + aux += ctx->size; + } + return false; +} +#endif + +using Context = ucontext_t; + +SignalContext::WriteFlag SignalContext::GetWriteFlag() const { + Context *ucontext = (Context *)context; +#if defined(__x86_64__) || defined(__i386__) + static const uptr PF_WRITE = 1U << 1; +#if SANITIZER_FREEBSD + uptr err = ucontext->uc_mcontext.mc_err; +#elif SANITIZER_NETBSD + uptr err = ucontext->uc_mcontext.__gregs[_REG_ERR]; +#elif SANITIZER_SOLARIS && defined(__i386__) + const int Err = 13; + uptr err = ucontext->uc_mcontext.gregs[Err]; +#else + uptr err = ucontext->uc_mcontext.gregs[REG_ERR]; +#endif // SANITIZER_FREEBSD + return err & PF_WRITE ? Write : Read; +#elif defined(__mips__) + uint32_t *exception_source; + uint32_t faulty_instruction; + uint32_t op_code; + + exception_source = (uint32_t *)ucontext->uc_mcontext.pc; + faulty_instruction = (uint32_t)(*exception_source); + + op_code = (faulty_instruction >> 26) & 0x3f; + + // FIXME: Add support for FPU, microMIPS, DSP, MSA memory instructions. + switch (op_code) { + case 0x28: // sb + case 0x29: // sh + case 0x2b: // sw + case 0x3f: // sd +#if __mips_isa_rev < 6 + case 0x2c: // sdl + case 0x2d: // sdr + case 0x2a: // swl + case 0x2e: // swr +#endif + return SignalContext::Write; + + case 0x20: // lb + case 0x24: // lbu + case 0x21: // lh + case 0x25: // lhu + case 0x23: // lw + case 0x27: // lwu + case 0x37: // ld +#if __mips_isa_rev < 6 + case 0x1a: // ldl + case 0x1b: // ldr + case 0x22: // lwl + case 0x26: // lwr +#endif + return SignalContext::Read; +#if __mips_isa_rev == 6 + case 0x3b: // pcrel + op_code = (faulty_instruction >> 19) & 0x3; + switch (op_code) { + case 0x1: // lwpc + case 0x2: // lwupc + return SignalContext::Read; + } +#endif + } + return SignalContext::Unknown; +#elif defined(__arm__) + static const uptr FSR_WRITE = 1U << 11; + uptr fsr = ucontext->uc_mcontext.error_code; + return fsr & FSR_WRITE ? Write : Read; +#elif defined(__aarch64__) + static const u64 ESR_ELx_WNR = 1U << 6; + u64 esr; + if (!Aarch64GetESR(ucontext, &esr)) return Unknown; + return esr & ESR_ELx_WNR ? Write : Read; +#elif defined(__sparc__) + // Decode the instruction to determine the access type. + // From OpenSolaris $SRC/uts/sun4/os/trap.c (get_accesstype). +#if SANITIZER_SOLARIS + uptr pc = ucontext->uc_mcontext.gregs[REG_PC]; +#else + // Historical BSDism here. + struct sigcontext *scontext = (struct sigcontext *)context; +#if defined(__arch64__) + uptr pc = scontext->sigc_regs.tpc; +#else + uptr pc = scontext->si_regs.pc; +#endif +#endif + u32 instr = *(u32 *)pc; + return (instr >> 21) & 1 ? Write: Read; +#elif defined(__riscv) +#if SANITIZER_FREEBSD + unsigned long pc = ucontext->uc_mcontext.mc_gpregs.gp_sepc; +#else + unsigned long pc = ucontext->uc_mcontext.__gregs[REG_PC]; +#endif + unsigned faulty_instruction = *(uint16_t *)pc; + +#if defined(__riscv_compressed) + if ((faulty_instruction & 0x3) != 0x3) { // it's a compressed instruction + // set op_bits to the instruction bits [1, 0, 15, 14, 13] + unsigned op_bits = + ((faulty_instruction & 0x3) << 3) | (faulty_instruction >> 13); + unsigned rd = faulty_instruction & 0xF80; // bits 7-11, inclusive + switch (op_bits) { + case 0b10'010: // c.lwsp (rd != x0) +#if __riscv_xlen == 64 + case 0b10'011: // c.ldsp (rd != x0) +#endif + return rd ? SignalContext::Read : SignalContext::Unknown; + case 0b00'010: // c.lw +#if __riscv_flen >= 32 && __riscv_xlen == 32 + case 0b10'011: // c.flwsp +#endif +#if __riscv_flen >= 32 || __riscv_xlen == 64 + case 0b00'011: // c.flw / c.ld +#endif +#if __riscv_flen == 64 + case 0b00'001: // c.fld + case 0b10'001: // c.fldsp +#endif + return SignalContext::Read; + case 0b00'110: // c.sw + case 0b10'110: // c.swsp +#if __riscv_flen >= 32 || __riscv_xlen == 64 + case 0b00'111: // c.fsw / c.sd + case 0b10'111: // c.fswsp / c.sdsp +#endif +#if __riscv_flen == 64 + case 0b00'101: // c.fsd + case 0b10'101: // c.fsdsp +#endif + return SignalContext::Write; + default: + return SignalContext::Unknown; + } + } +#endif + + unsigned opcode = faulty_instruction & 0x7f; // lower 7 bits + unsigned funct3 = (faulty_instruction >> 12) & 0x7; // bits 12-14, inclusive + switch (opcode) { + case 0b0000011: // loads + switch (funct3) { + case 0b000: // lb + case 0b001: // lh + case 0b010: // lw +#if __riscv_xlen == 64 + case 0b011: // ld +#endif + case 0b100: // lbu + case 0b101: // lhu + return SignalContext::Read; + default: + return SignalContext::Unknown; + } + case 0b0100011: // stores + switch (funct3) { + case 0b000: // sb + case 0b001: // sh + case 0b010: // sw +#if __riscv_xlen == 64 + case 0b011: // sd +#endif + return SignalContext::Write; + default: + return SignalContext::Unknown; + } +#if __riscv_flen >= 32 + case 0b0000111: // floating-point loads + switch (funct3) { + case 0b010: // flw +#if __riscv_flen == 64 + case 0b011: // fld +#endif + return SignalContext::Read; + default: + return SignalContext::Unknown; + } + case 0b0100111: // floating-point stores + switch (funct3) { + case 0b010: // fsw +#if __riscv_flen == 64 + case 0b011: // fsd +#endif + return SignalContext::Write; + default: + return SignalContext::Unknown; + } +#endif + default: + return SignalContext::Unknown; + } +#else + (void)ucontext; + return Unknown; // FIXME: Implement. +#endif +} + +bool SignalContext::IsTrueFaultingAddress() const { + auto si = static_cast<const siginfo_t *>(siginfo); + // SIGSEGV signals without a true fault address have si_code set to 128. + return si->si_signo == SIGSEGV && si->si_code != 128; +} + +void SignalContext::DumpAllRegisters(void *context) { + // FIXME: Implement this. +} + +static void GetPcSpBp(void *context, uptr *pc, uptr *sp, uptr *bp) { +#if SANITIZER_NETBSD + // This covers all NetBSD architectures + ucontext_t *ucontext = (ucontext_t *)context; + *pc = _UC_MACHINE_PC(ucontext); + *bp = _UC_MACHINE_FP(ucontext); + *sp = _UC_MACHINE_SP(ucontext); +#elif defined(__arm__) + ucontext_t *ucontext = (ucontext_t*)context; + *pc = ucontext->uc_mcontext.arm_pc; + *bp = ucontext->uc_mcontext.arm_fp; + *sp = ucontext->uc_mcontext.arm_sp; +#elif defined(__aarch64__) + ucontext_t *ucontext = (ucontext_t*)context; + *pc = ucontext->uc_mcontext.pc; + *bp = ucontext->uc_mcontext.regs[29]; + *sp = ucontext->uc_mcontext.sp; +#elif defined(__hppa__) + ucontext_t *ucontext = (ucontext_t*)context; + *pc = ucontext->uc_mcontext.sc_iaoq[0]; + /* GCC uses %r3 whenever a frame pointer is needed. */ + *bp = ucontext->uc_mcontext.sc_gr[3]; + *sp = ucontext->uc_mcontext.sc_gr[30]; +#elif defined(__x86_64__) +# if SANITIZER_FREEBSD + ucontext_t *ucontext = (ucontext_t*)context; + *pc = ucontext->uc_mcontext.mc_rip; + *bp = ucontext->uc_mcontext.mc_rbp; + *sp = ucontext->uc_mcontext.mc_rsp; +# else + ucontext_t *ucontext = (ucontext_t*)context; + *pc = ucontext->uc_mcontext.gregs[REG_RIP]; + *bp = ucontext->uc_mcontext.gregs[REG_RBP]; + *sp = ucontext->uc_mcontext.gregs[REG_RSP]; +# endif +#elif defined(__i386__) +# if SANITIZER_FREEBSD + ucontext_t *ucontext = (ucontext_t*)context; + *pc = ucontext->uc_mcontext.mc_eip; + *bp = ucontext->uc_mcontext.mc_ebp; + *sp = ucontext->uc_mcontext.mc_esp; +# else + ucontext_t *ucontext = (ucontext_t*)context; +# if SANITIZER_SOLARIS + /* Use the numeric values: the symbolic ones are undefined by llvm + include/llvm/Support/Solaris.h. */ +# ifndef REG_EIP +# define REG_EIP 14 // REG_PC +# endif +# ifndef REG_EBP +# define REG_EBP 6 // REG_FP +# endif +# ifndef REG_UESP +# define REG_UESP 17 // REG_SP +# endif +# endif + *pc = ucontext->uc_mcontext.gregs[REG_EIP]; + *bp = ucontext->uc_mcontext.gregs[REG_EBP]; + *sp = ucontext->uc_mcontext.gregs[REG_UESP]; +# endif +#elif defined(__powerpc__) || defined(__powerpc64__) + ucontext_t *ucontext = (ucontext_t*)context; + *pc = ucontext->uc_mcontext.regs->nip; + *sp = ucontext->uc_mcontext.regs->gpr[PT_R1]; + // The powerpc{,64}-linux ABIs do not specify r31 as the frame + // pointer, but GCC always uses r31 when we need a frame pointer. + *bp = ucontext->uc_mcontext.regs->gpr[PT_R31]; +#elif defined(__sparc__) +#if defined(__arch64__) || defined(__sparcv9) +#define STACK_BIAS 2047 +#else +#define STACK_BIAS 0 +# endif +# if SANITIZER_SOLARIS + ucontext_t *ucontext = (ucontext_t *)context; + *pc = ucontext->uc_mcontext.gregs[REG_PC]; + *sp = ucontext->uc_mcontext.gregs[REG_O6] + STACK_BIAS; +#else + // Historical BSDism here. + struct sigcontext *scontext = (struct sigcontext *)context; +#if defined(__arch64__) + *pc = scontext->sigc_regs.tpc; + *sp = scontext->sigc_regs.u_regs[14] + STACK_BIAS; +#else + *pc = scontext->si_regs.pc; + *sp = scontext->si_regs.u_regs[14]; +#endif +# endif + *bp = (uptr)((uhwptr *)*sp)[14] + STACK_BIAS; +#elif defined(__mips__) + ucontext_t *ucontext = (ucontext_t*)context; + *pc = ucontext->uc_mcontext.pc; + *bp = ucontext->uc_mcontext.gregs[30]; + *sp = ucontext->uc_mcontext.gregs[29]; +#elif defined(__s390__) + ucontext_t *ucontext = (ucontext_t*)context; +# if defined(__s390x__) + *pc = ucontext->uc_mcontext.psw.addr; +# else + *pc = ucontext->uc_mcontext.psw.addr & 0x7fffffff; +# endif + *bp = ucontext->uc_mcontext.gregs[11]; + *sp = ucontext->uc_mcontext.gregs[15]; +#elif defined(__riscv) + ucontext_t *ucontext = (ucontext_t*)context; +# if SANITIZER_FREEBSD + *pc = ucontext->uc_mcontext.mc_gpregs.gp_sepc; + *bp = ucontext->uc_mcontext.mc_gpregs.gp_s[0]; + *sp = ucontext->uc_mcontext.mc_gpregs.gp_sp; +# else + *pc = ucontext->uc_mcontext.__gregs[REG_PC]; + *bp = ucontext->uc_mcontext.__gregs[REG_S0]; + *sp = ucontext->uc_mcontext.__gregs[REG_SP]; +# endif +# elif defined(__hexagon__) + ucontext_t *ucontext = (ucontext_t *)context; + *pc = ucontext->uc_mcontext.pc; + *bp = ucontext->uc_mcontext.r30; + *sp = ucontext->uc_mcontext.r29; +# else +# error "Unsupported arch" +# endif +} + +void SignalContext::InitPcSpBp() { GetPcSpBp(context, &pc, &sp, &bp); } + +void InitializePlatformEarly() { + // Do nothing. +} + +void MaybeReexec() { + // No need to re-exec on Linux. +} + +void CheckASLR() { +#if SANITIZER_NETBSD + int mib[3]; + int paxflags; + uptr len = sizeof(paxflags); + + mib[0] = CTL_PROC; + mib[1] = internal_getpid(); + mib[2] = PROC_PID_PAXFLAGS; + + if (UNLIKELY(internal_sysctl(mib, 3, &paxflags, &len, NULL, 0) == -1)) { + Printf("sysctl failed\n"); + Die(); + } + + if (UNLIKELY(paxflags & CTL_PROC_PAXFLAGS_ASLR)) { + Printf("This sanitizer is not compatible with enabled ASLR.\n" + "To disable ASLR, please run \"paxctl +a %s\" and try again.\n", + GetArgv()[0]); + Die(); + } +#elif SANITIZER_PPC64V2 + // Disable ASLR for Linux PPC64LE. + int old_personality = personality(0xffffffff); + if (old_personality != -1 && (old_personality & ADDR_NO_RANDOMIZE) == 0) { + VReport(1, "WARNING: Program is being run with address space layout " + "randomization (ASLR) enabled which prevents the thread and " + "memory sanitizers from working on powerpc64le.\n" + "ASLR will be disabled and the program re-executed.\n"); + CHECK_NE(personality(old_personality | ADDR_NO_RANDOMIZE), -1); + ReExec(); + } +#elif SANITIZER_FREEBSD + int aslr_status; + if (UNLIKELY(procctl(P_PID, 0, PROC_ASLR_STATUS, &aslr_status) == -1)) { + // We're making things less 'dramatic' here since + // the cmd is not necessarily guaranteed to be here + // just yet regarding FreeBSD release + return; + } + if ((aslr_status & PROC_ASLR_ACTIVE) != 0) { + Printf("This sanitizer is not compatible with enabled ASLR " + "and binaries compiled with PIE\n"); + Die(); + } +#else + // Do nothing +#endif +} + +void CheckMPROTECT() { +#if SANITIZER_NETBSD + int mib[3]; + int paxflags; + uptr len = sizeof(paxflags); + + mib[0] = CTL_PROC; + mib[1] = internal_getpid(); + mib[2] = PROC_PID_PAXFLAGS; + + if (UNLIKELY(internal_sysctl(mib, 3, &paxflags, &len, NULL, 0) == -1)) { + Printf("sysctl failed\n"); + Die(); + } + + if (UNLIKELY(paxflags & CTL_PROC_PAXFLAGS_MPROTECT)) { + Printf("This sanitizer is not compatible with enabled MPROTECT\n"); + Die(); + } +#else + // Do nothing +#endif +} + +void CheckNoDeepBind(const char *filename, int flag) { +#ifdef RTLD_DEEPBIND + if (flag & RTLD_DEEPBIND) { + Report( + "You are trying to dlopen a %s shared library with RTLD_DEEPBIND flag" + " which is incompatible with sanitizer runtime " + "(see https://github.com/google/sanitizers/issues/611 for details" + "). If you want to run %s library under sanitizers please remove " + "RTLD_DEEPBIND from dlopen flags.\n", + filename, filename); + Die(); + } +#endif +} + +uptr FindAvailableMemoryRange(uptr size, uptr alignment, uptr left_padding, + uptr *largest_gap_found, + uptr *max_occupied_addr) { + UNREACHABLE("FindAvailableMemoryRange is not available"); + return 0; +} + +bool GetRandom(void *buffer, uptr length, bool blocking) { + if (!buffer || !length || length > 256) + return false; +#if SANITIZER_USE_GETENTROPY + uptr rnd = getentropy(buffer, length); + int rverrno = 0; + if (internal_iserror(rnd, &rverrno) && rverrno == EFAULT) + return false; + else if (rnd == 0) + return true; +#endif // SANITIZER_USE_GETENTROPY + +#if SANITIZER_USE_GETRANDOM + static atomic_uint8_t skip_getrandom_syscall; + if (!atomic_load_relaxed(&skip_getrandom_syscall)) { + // Up to 256 bytes, getrandom will not be interrupted. + uptr res = internal_syscall(SYSCALL(getrandom), buffer, length, + blocking ? 0 : GRND_NONBLOCK); + int rverrno = 0; + if (internal_iserror(res, &rverrno) && rverrno == ENOSYS) + atomic_store_relaxed(&skip_getrandom_syscall, 1); + else if (res == length) + return true; + } +#endif // SANITIZER_USE_GETRANDOM + // Up to 256 bytes, a read off /dev/urandom will not be interrupted. + // blocking is moot here, O_NONBLOCK has no effect when opening /dev/urandom. + uptr fd = internal_open("/dev/urandom", O_RDONLY); + if (internal_iserror(fd)) + return false; + uptr res = internal_read(fd, buffer, length); + if (internal_iserror(res)) + return false; + internal_close(fd); + return true; +} + +} // namespace __sanitizer + +#endif diff --git a/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_linux.h b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_linux.h new file mode 100644 index 0000000000..ebd60e0b10 --- /dev/null +++ b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_linux.h @@ -0,0 +1,175 @@ +//===-- sanitizer_linux.h ---------------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// Linux-specific syscall wrappers and classes. +// +//===----------------------------------------------------------------------===// +#ifndef SANITIZER_LINUX_H +#define SANITIZER_LINUX_H + +#include "sanitizer_platform.h" +#if SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD || \ + SANITIZER_SOLARIS +#include "sanitizer_common.h" +#include "sanitizer_internal_defs.h" +#include "sanitizer_platform_limits_freebsd.h" +#include "sanitizer_platform_limits_netbsd.h" +#include "sanitizer_platform_limits_posix.h" +#include "sanitizer_platform_limits_solaris.h" +#include "sanitizer_posix.h" + +struct link_map; // Opaque type returned by dlopen(). +struct utsname; + +namespace __sanitizer { +// Dirent structure for getdents(). Note that this structure is different from +// the one in <dirent.h>, which is used by readdir(). +struct linux_dirent; + +struct ProcSelfMapsBuff { + char *data; + uptr mmaped_size; + uptr len; +}; + +struct MemoryMappingLayoutData { + ProcSelfMapsBuff proc_self_maps; + const char *current; +}; + +void ReadProcMaps(ProcSelfMapsBuff *proc_maps); + +// Syscall wrappers. +uptr internal_getdents(fd_t fd, struct linux_dirent *dirp, unsigned int count); +uptr internal_sigaltstack(const void* ss, void* oss); +uptr internal_sigprocmask(int how, __sanitizer_sigset_t *set, + __sanitizer_sigset_t *oldset); + +void SetSigProcMask(__sanitizer_sigset_t *set, __sanitizer_sigset_t *oldset); +struct ScopedBlockSignals { + explicit ScopedBlockSignals(__sanitizer_sigset_t *copy); + ~ScopedBlockSignals(); + + ScopedBlockSignals &operator=(const ScopedBlockSignals &) = delete; + ScopedBlockSignals(const ScopedBlockSignals &) = delete; + + private: + __sanitizer_sigset_t saved_; +}; + +# if SANITIZER_GLIBC +uptr internal_clock_gettime(__sanitizer_clockid_t clk_id, void *tp); +#endif + +// Linux-only syscalls. +#if SANITIZER_LINUX +uptr internal_prctl(int option, uptr arg2, uptr arg3, uptr arg4, uptr arg5); +// Used only by sanitizer_stoptheworld. Signal handlers that are actually used +// (like the process-wide error reporting SEGV handler) must use +// internal_sigaction instead. +int internal_sigaction_norestorer(int signum, const void *act, void *oldact); +void internal_sigdelset(__sanitizer_sigset_t *set, int signum); +#if defined(__x86_64__) || defined(__mips__) || defined(__aarch64__) || \ + defined(__powerpc64__) || defined(__s390__) || defined(__i386__) || \ + defined(__arm__) || SANITIZER_RISCV64 +uptr internal_clone(int (*fn)(void *), void *child_stack, int flags, void *arg, + int *parent_tidptr, void *newtls, int *child_tidptr); +#endif +int internal_uname(struct utsname *buf); +#elif SANITIZER_FREEBSD +void internal_sigdelset(__sanitizer_sigset_t *set, int signum); +#elif SANITIZER_NETBSD +void internal_sigdelset(__sanitizer_sigset_t *set, int signum); +uptr internal_clone(int (*fn)(void *), void *child_stack, int flags, void *arg); +#endif // SANITIZER_LINUX + +// This class reads thread IDs from /proc/<pid>/task using only syscalls. +class ThreadLister { + public: + explicit ThreadLister(pid_t pid); + ~ThreadLister(); + enum Result { + Error, + Incomplete, + Ok, + }; + Result ListThreads(InternalMmapVector<tid_t> *threads); + + private: + bool IsAlive(int tid); + + pid_t pid_; + int descriptor_ = -1; + InternalMmapVector<char> buffer_; +}; + +// Exposed for testing. +uptr ThreadDescriptorSize(); +uptr ThreadSelf(); + +// Matches a library's file name against a base name (stripping path and version +// information). +bool LibraryNameIs(const char *full_name, const char *base_name); + +// Call cb for each region mapped by map. +void ForEachMappedRegion(link_map *map, void (*cb)(const void *, uptr)); + +// Releases memory pages entirely within the [beg, end] address range. +// The pages no longer count toward RSS; reads are guaranteed to return 0. +// Requires (but does not verify!) that pages are MAP_PRIVATE. +inline void ReleaseMemoryPagesToOSAndZeroFill(uptr beg, uptr end) { + // man madvise on Linux promises zero-fill for anonymous private pages. + // Testing shows the same behaviour for private (but not anonymous) mappings + // of shm_open() files, as long as the underlying file is untouched. + CHECK(SANITIZER_LINUX); + ReleaseMemoryPagesToOS(beg, end); +} + +#if SANITIZER_ANDROID + +#if defined(__aarch64__) +# define __get_tls() \ + ({ void** __v; __asm__("mrs %0, tpidr_el0" : "=r"(__v)); __v; }) +#elif defined(__arm__) +# define __get_tls() \ + ({ void** __v; __asm__("mrc p15, 0, %0, c13, c0, 3" : "=r"(__v)); __v; }) +#elif defined(__mips__) +// On mips32r1, this goes via a kernel illegal instruction trap that's +// optimized for v1. +# define __get_tls() \ + ({ register void** __v asm("v1"); \ + __asm__(".set push\n" \ + ".set mips32r2\n" \ + "rdhwr %0,$29\n" \ + ".set pop\n" : "=r"(__v)); \ + __v; }) +#elif defined(__i386__) +# define __get_tls() \ + ({ void** __v; __asm__("movl %%gs:0, %0" : "=r"(__v)); __v; }) +#elif defined(__x86_64__) +# define __get_tls() \ + ({ void** __v; __asm__("mov %%fs:0, %0" : "=r"(__v)); __v; }) +#else +#error "Unsupported architecture." +#endif + +// The Android Bionic team has allocated a TLS slot for sanitizers starting +// with Q, given that Android currently doesn't support ELF TLS. It is used to +// store sanitizer thread specific data. +static const int TLS_SLOT_SANITIZER = 6; + +ALWAYS_INLINE uptr *get_android_tls_ptr() { + return reinterpret_cast<uptr *>(&__get_tls()[TLS_SLOT_SANITIZER]); +} + +#endif // SANITIZER_ANDROID + +} // namespace __sanitizer + +#endif +#endif // SANITIZER_LINUX_H diff --git a/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_linux_libcdep.cpp b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_linux_libcdep.cpp new file mode 100644 index 0000000000..c790ba179e --- /dev/null +++ b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_linux_libcdep.cpp @@ -0,0 +1,1037 @@ +//===-- sanitizer_linux_libcdep.cpp ---------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file is shared between AddressSanitizer and ThreadSanitizer +// run-time libraries and implements linux-specific functions from +// sanitizer_libc.h. +//===----------------------------------------------------------------------===// + +#include "sanitizer_platform.h" + +#if SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD || \ + SANITIZER_SOLARIS + +#include "sanitizer_allocator_internal.h" +#include "sanitizer_atomic.h" +#include "sanitizer_common.h" +#include "sanitizer_file.h" +#include "sanitizer_flags.h" +#include "sanitizer_freebsd.h" +#include "sanitizer_getauxval.h" +#include "sanitizer_glibc_version.h" +#include "sanitizer_linux.h" +#include "sanitizer_placement_new.h" +#include "sanitizer_procmaps.h" + +#if SANITIZER_NETBSD +#define _RTLD_SOURCE // for __lwp_gettcb_fast() / __lwp_getprivate_fast() +#endif + +#include <dlfcn.h> // for dlsym() +#include <link.h> +#include <pthread.h> +#include <signal.h> +#include <sys/mman.h> +#include <sys/resource.h> +#include <syslog.h> + +#if !defined(ElfW) +#define ElfW(type) Elf_##type +#endif + +#if SANITIZER_FREEBSD +#include <pthread_np.h> +#include <osreldate.h> +#include <sys/sysctl.h> +#define pthread_getattr_np pthread_attr_get_np +// The MAP_NORESERVE define has been removed in FreeBSD 11.x, and even before +// that, it was never implemented. So just define it to zero. +#undef MAP_NORESERVE +#define MAP_NORESERVE 0 +#endif + +#if SANITIZER_NETBSD +#include <sys/sysctl.h> +#error #include <sys/tls.h> +#include <lwp.h> +#endif + +#if SANITIZER_SOLARIS +#include <stdlib.h> +#include <thread.h> +#endif + +#if SANITIZER_ANDROID +#include <android/api-level.h> +#if !defined(CPU_COUNT) && !defined(__aarch64__) +#include <dirent.h> +#include <fcntl.h> +struct __sanitizer::linux_dirent { + long d_ino; + off_t d_off; + unsigned short d_reclen; + char d_name[]; +}; +#endif +#endif + +#if !SANITIZER_ANDROID +#include <elf.h> +#include <unistd.h> +#endif + +namespace __sanitizer { + +SANITIZER_WEAK_ATTRIBUTE int +real_sigaction(int signum, const void *act, void *oldact); + +int internal_sigaction(int signum, const void *act, void *oldact) { +#if !SANITIZER_GO + if (&real_sigaction) + return real_sigaction(signum, act, oldact); +#endif + return sigaction(signum, (const struct sigaction *)act, + (struct sigaction *)oldact); +} + +void GetThreadStackTopAndBottom(bool at_initialization, uptr *stack_top, + uptr *stack_bottom) { + 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. + MemoryMappingLayout proc_maps(/*cache_enabled*/true); + if (proc_maps.Error()) { + *stack_top = *stack_bottom = 0; + return; + } + MemoryMappedSegment segment; + uptr prev_end = 0; + while (proc_maps.Next(&segment)) { + if ((uptr)&rl < segment.end) break; + prev_end = segment.end; + } + CHECK((uptr)&rl >= segment.start && (uptr)&rl < segment.end); + + // Get stacksize from rlimit, but clip it so that it does not overlap + // with other mappings. + uptr stacksize = rl.rlim_cur; + if (stacksize > segment.end - prev_end) stacksize = segment.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 = segment.end; + *stack_bottom = segment.end - stacksize; + return; + } + uptr stacksize = 0; + void *stackaddr = nullptr; +#if SANITIZER_SOLARIS + stack_t ss; + CHECK_EQ(thr_stksegment(&ss), 0); + stacksize = ss.ss_size; + stackaddr = (char *)ss.ss_sp - stacksize; +#else // !SANITIZER_SOLARIS + pthread_attr_t attr; + pthread_attr_init(&attr); + CHECK_EQ(pthread_getattr_np(pthread_self(), &attr), 0); + my_pthread_attr_getstack(&attr, &stackaddr, &stacksize); + pthread_attr_destroy(&attr); +#endif // SANITIZER_SOLARIS + + *stack_top = (uptr)stackaddr + stacksize; + *stack_bottom = (uptr)stackaddr; +} + +#if !SANITIZER_GO +bool SetEnv(const char *name, const char *value) { + void *f = dlsym(RTLD_NEXT, "setenv"); + if (!f) + return false; + typedef int(*setenv_ft)(const char *name, const char *value, int overwrite); + setenv_ft setenv_f; + CHECK_EQ(sizeof(setenv_f), sizeof(f)); + internal_memcpy(&setenv_f, &f, sizeof(f)); + return setenv_f(name, value, 1) == 0; +} +#endif + +__attribute__((unused)) static bool GetLibcVersion(int *major, int *minor, + int *patch) { +#ifdef _CS_GNU_LIBC_VERSION + char buf[64]; + uptr len = confstr(_CS_GNU_LIBC_VERSION, buf, sizeof(buf)); + if (len >= sizeof(buf)) + return false; + buf[len] = 0; + static const char kGLibC[] = "glibc "; + if (internal_strncmp(buf, kGLibC, sizeof(kGLibC) - 1) != 0) + return false; + const char *p = buf + sizeof(kGLibC) - 1; + *major = internal_simple_strtoll(p, &p, 10); + *minor = (*p == '.') ? internal_simple_strtoll(p + 1, &p, 10) : 0; + *patch = (*p == '.') ? internal_simple_strtoll(p + 1, &p, 10) : 0; + return true; +#else + return false; +#endif +} + +// True if we can use dlpi_tls_data. glibc before 2.25 may leave NULL (BZ +// #19826) so dlpi_tls_data cannot be used. +// +// musl before 1.2.3 and FreeBSD as of 12.2 incorrectly set dlpi_tls_data to +// the TLS initialization image +// https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=254774 +__attribute__((unused)) static int g_use_dlpi_tls_data; + +#if SANITIZER_GLIBC && !SANITIZER_GO +__attribute__((unused)) static size_t g_tls_size; +void InitTlsSize() { + int major, minor, patch; + g_use_dlpi_tls_data = + GetLibcVersion(&major, &minor, &patch) && major == 2 && minor >= 25; + +#if defined(__aarch64__) || defined(__x86_64__) || defined(__powerpc64__) + void *get_tls_static_info = dlsym(RTLD_NEXT, "_dl_get_tls_static_info"); + size_t tls_align; + ((void (*)(size_t *, size_t *))get_tls_static_info)(&g_tls_size, &tls_align); +#endif +} +#else +void InitTlsSize() { } +#endif // SANITIZER_GLIBC && !SANITIZER_GO + +// On glibc x86_64, ThreadDescriptorSize() needs to be precise due to the usage +// of g_tls_size. On other targets, ThreadDescriptorSize() is only used by lsan +// to get the pointer to thread-specific data keys in the thread control block. +#if (SANITIZER_FREEBSD || SANITIZER_LINUX) && !SANITIZER_ANDROID && !SANITIZER_GO +// sizeof(struct pthread) from glibc. +static atomic_uintptr_t thread_descriptor_size; + +static uptr ThreadDescriptorSizeFallback() { + uptr val = 0; +#if defined(__x86_64__) || defined(__i386__) || defined(__arm__) + int major; + int minor; + int patch; + if (GetLibcVersion(&major, &minor, &patch) && major == 2) { + /* sizeof(struct pthread) values from various glibc versions. */ + if (SANITIZER_X32) + val = 1728; // Assume only one particular version for x32. + // For ARM sizeof(struct pthread) changed in Glibc 2.23. + else if (SANITIZER_ARM) + val = minor <= 22 ? 1120 : 1216; + else if (minor <= 3) + val = FIRST_32_SECOND_64(1104, 1696); + else if (minor == 4) + val = FIRST_32_SECOND_64(1120, 1728); + else if (minor == 5) + val = FIRST_32_SECOND_64(1136, 1728); + else if (minor <= 9) + val = FIRST_32_SECOND_64(1136, 1712); + else if (minor == 10) + val = FIRST_32_SECOND_64(1168, 1776); + else if (minor == 11 || (minor == 12 && patch == 1)) + val = FIRST_32_SECOND_64(1168, 2288); + else if (minor <= 14) + val = FIRST_32_SECOND_64(1168, 2304); + else if (minor < 32) // Unknown version + val = FIRST_32_SECOND_64(1216, 2304); + else // minor == 32 + val = FIRST_32_SECOND_64(1344, 2496); + } +#elif defined(__s390__) || defined(__sparc__) + // The size of a prefix of TCB including pthread::{specific_1stblock,specific} + // suffices. Just return offsetof(struct pthread, specific_used), which hasn't + // changed since 2007-05. Technically this applies to i386/x86_64 as well but + // we call _dl_get_tls_static_info and need the precise size of struct + // pthread. + return FIRST_32_SECOND_64(524, 1552); +#elif defined(__mips__) + // TODO(sagarthakur): add more values as per different glibc versions. + val = FIRST_32_SECOND_64(1152, 1776); +#elif SANITIZER_RISCV64 + int major; + int minor; + int patch; + if (GetLibcVersion(&major, &minor, &patch) && major == 2) { + // TODO: consider adding an optional runtime check for an unknown (untested) + // glibc version + if (minor <= 28) // WARNING: the highest tested version is 2.29 + val = 1772; // no guarantees for this one + else if (minor <= 31) + val = 1772; // tested against glibc 2.29, 2.31 + else + val = 1936; // tested against glibc 2.32 + } + +#elif defined(__aarch64__) + // The sizeof (struct pthread) is the same from GLIBC 2.17 to 2.22. + val = 1776; +#elif defined(__powerpc64__) + val = 1776; // from glibc.ppc64le 2.20-8.fc21 +#endif + return val; +} + +uptr ThreadDescriptorSize() { + uptr val = atomic_load_relaxed(&thread_descriptor_size); + if (val) + return val; + // _thread_db_sizeof_pthread is a GLIBC_PRIVATE symbol that is exported in + // glibc 2.34 and later. + if (unsigned *psizeof = static_cast<unsigned *>( + dlsym(RTLD_DEFAULT, "_thread_db_sizeof_pthread"))) + val = *psizeof; + if (!val) + val = ThreadDescriptorSizeFallback(); + atomic_store_relaxed(&thread_descriptor_size, val); + return val; +} + +#if defined(__mips__) || defined(__powerpc64__) || SANITIZER_RISCV64 +// TlsPreTcbSize includes size of struct pthread_descr and size of tcb +// head structure. It lies before the static tls blocks. +static uptr TlsPreTcbSize() { +#if defined(__mips__) + const uptr kTcbHead = 16; // sizeof (tcbhead_t) +#elif defined(__powerpc64__) + const uptr kTcbHead = 88; // sizeof (tcbhead_t) +#elif SANITIZER_RISCV64 + const uptr kTcbHead = 16; // sizeof (tcbhead_t) +#endif + const uptr kTlsAlign = 16; + const uptr kTlsPreTcbSize = + RoundUpTo(ThreadDescriptorSize() + kTcbHead, kTlsAlign); + return kTlsPreTcbSize; +} +#endif + +namespace { +struct TlsBlock { + uptr begin, end, align; + size_t tls_modid; + bool operator<(const TlsBlock &rhs) const { return begin < rhs.begin; } +}; +} // namespace + +#ifdef __s390__ +extern "C" uptr __tls_get_offset(void *arg); + +static uptr TlsGetOffset(uptr ti_module, uptr ti_offset) { + // The __tls_get_offset ABI requires %r12 to point to GOT and %r2 to be an + // offset of a struct tls_index inside GOT. We don't possess either of the + // two, so violate the letter of the "ELF Handling For Thread-Local + // Storage" document and assume that the implementation just dereferences + // %r2 + %r12. + uptr tls_index[2] = {ti_module, ti_offset}; + register uptr r2 asm("2") = 0; + register void *r12 asm("12") = tls_index; + asm("basr %%r14, %[__tls_get_offset]" + : "+r"(r2) + : [__tls_get_offset] "r"(__tls_get_offset), "r"(r12) + : "memory", "cc", "0", "1", "3", "4", "5", "14"); + return r2; +} +#else +extern "C" void *__tls_get_addr(size_t *); +#endif + +static int CollectStaticTlsBlocks(struct dl_phdr_info *info, size_t size, + void *data) { + if (!info->dlpi_tls_modid) + return 0; + uptr begin = (uptr)info->dlpi_tls_data; + if (!g_use_dlpi_tls_data) { + // Call __tls_get_addr as a fallback. This forces TLS allocation on glibc + // and FreeBSD. +#ifdef __s390__ + begin = (uptr)__builtin_thread_pointer() + + TlsGetOffset(info->dlpi_tls_modid, 0); +#else + size_t mod_and_off[2] = {info->dlpi_tls_modid, 0}; + begin = (uptr)__tls_get_addr(mod_and_off); +#endif + } + for (unsigned i = 0; i != info->dlpi_phnum; ++i) + if (info->dlpi_phdr[i].p_type == PT_TLS) { + static_cast<InternalMmapVector<TlsBlock> *>(data)->push_back( + TlsBlock{begin, begin + info->dlpi_phdr[i].p_memsz, + info->dlpi_phdr[i].p_align, info->dlpi_tls_modid}); + break; + } + return 0; +} + +__attribute__((unused)) static void GetStaticTlsBoundary(uptr *addr, uptr *size, + uptr *align) { + InternalMmapVector<TlsBlock> ranges; + dl_iterate_phdr(CollectStaticTlsBlocks, &ranges); + uptr len = ranges.size(); + Sort(ranges.begin(), len); + // Find the range with tls_modid=1. For glibc, because libc.so uses PT_TLS, + // this module is guaranteed to exist and is one of the initially loaded + // modules. + uptr one = 0; + while (one != len && ranges[one].tls_modid != 1) ++one; + if (one == len) { + // This may happen with musl if no module uses PT_TLS. + *addr = 0; + *size = 0; + *align = 1; + return; + } + // Find the maximum consecutive ranges. We consider two modules consecutive if + // the gap is smaller than the alignment. The dynamic loader places static TLS + // blocks this way not to waste space. + uptr l = one; + *align = ranges[l].align; + while (l != 0 && ranges[l].begin < ranges[l - 1].end + ranges[l - 1].align) + *align = Max(*align, ranges[--l].align); + uptr r = one + 1; + while (r != len && ranges[r].begin < ranges[r - 1].end + ranges[r - 1].align) + *align = Max(*align, ranges[r++].align); + *addr = ranges[l].begin; + *size = ranges[r - 1].end - ranges[l].begin; +} +#endif // (x86_64 || i386 || mips || ...) && (SANITIZER_FREEBSD || + // SANITIZER_LINUX) && !SANITIZER_ANDROID && !SANITIZER_GO + +#if SANITIZER_NETBSD +static struct tls_tcb * ThreadSelfTlsTcb() { + struct tls_tcb *tcb = nullptr; +#ifdef __HAVE___LWP_GETTCB_FAST + tcb = (struct tls_tcb *)__lwp_gettcb_fast(); +#elif defined(__HAVE___LWP_GETPRIVATE_FAST) + tcb = (struct tls_tcb *)__lwp_getprivate_fast(); +#endif + return tcb; +} + +uptr ThreadSelf() { + return (uptr)ThreadSelfTlsTcb()->tcb_pthread; +} + +int GetSizeFromHdr(struct dl_phdr_info *info, size_t size, void *data) { + const Elf_Phdr *hdr = info->dlpi_phdr; + const Elf_Phdr *last_hdr = hdr + info->dlpi_phnum; + + for (; hdr != last_hdr; ++hdr) { + if (hdr->p_type == PT_TLS && info->dlpi_tls_modid == 1) { + *(uptr*)data = hdr->p_memsz; + break; + } + } + return 0; +} +#endif // SANITIZER_NETBSD + +#if SANITIZER_ANDROID +// Bionic provides this API since S. +extern "C" SANITIZER_WEAK_ATTRIBUTE void __libc_get_static_tls_bounds(void **, + void **); +#endif + +#if !SANITIZER_GO +static void GetTls(uptr *addr, uptr *size) { +#if SANITIZER_ANDROID + if (&__libc_get_static_tls_bounds) { + void *start_addr; + void *end_addr; + __libc_get_static_tls_bounds(&start_addr, &end_addr); + *addr = reinterpret_cast<uptr>(start_addr); + *size = + reinterpret_cast<uptr>(end_addr) - reinterpret_cast<uptr>(start_addr); + } else { + *addr = 0; + *size = 0; + } +#elif SANITIZER_GLIBC && defined(__x86_64__) + // For aarch64 and x86-64, use an O(1) approach which requires relatively + // precise ThreadDescriptorSize. g_tls_size was initialized in InitTlsSize. + asm("mov %%fs:16,%0" : "=r"(*addr)); + *size = g_tls_size; + *addr -= *size; + *addr += ThreadDescriptorSize(); +#elif SANITIZER_GLIBC && defined(__aarch64__) + *addr = reinterpret_cast<uptr>(__builtin_thread_pointer()) - + ThreadDescriptorSize(); + *size = g_tls_size + ThreadDescriptorSize(); +#elif SANITIZER_GLIBC && defined(__powerpc64__) + // Workaround for glibc<2.25(?). 2.27 is known to not need this. + uptr tp; + asm("addi %0,13,-0x7000" : "=r"(tp)); + const uptr pre_tcb_size = TlsPreTcbSize(); + *addr = tp - pre_tcb_size; + *size = g_tls_size + pre_tcb_size; +#elif SANITIZER_FREEBSD || SANITIZER_LINUX + uptr align; + GetStaticTlsBoundary(addr, size, &align); +#if defined(__x86_64__) || defined(__i386__) || defined(__s390__) || \ + defined(__sparc__) + if (SANITIZER_GLIBC) { +#if defined(__x86_64__) || defined(__i386__) + align = Max<uptr>(align, 64); +#else + align = Max<uptr>(align, 16); +#endif + } + const uptr tp = RoundUpTo(*addr + *size, align); + + // lsan requires the range to additionally cover the static TLS surplus + // (elf/dl-tls.c defines 1664). Otherwise there may be false positives for + // allocations only referenced by tls in dynamically loaded modules. + if (SANITIZER_GLIBC) + *size += 1644; + else if (SANITIZER_FREEBSD) + *size += 128; // RTLD_STATIC_TLS_EXTRA + + // Extend the range to include the thread control block. On glibc, lsan needs + // the range to include pthread::{specific_1stblock,specific} so that + // allocations only referenced by pthread_setspecific can be scanned. This may + // underestimate by at most TLS_TCB_ALIGN-1 bytes but it should be fine + // because the number of bytes after pthread::specific is larger. + *addr = tp - RoundUpTo(*size, align); + *size = tp - *addr + ThreadDescriptorSize(); +#else + if (SANITIZER_GLIBC) + *size += 1664; + else if (SANITIZER_FREEBSD) + *size += 128; // RTLD_STATIC_TLS_EXTRA +#if defined(__mips__) || defined(__powerpc64__) || SANITIZER_RISCV64 + const uptr pre_tcb_size = TlsPreTcbSize(); + *addr -= pre_tcb_size; + *size += pre_tcb_size; +#else + // arm and aarch64 reserve two words at TP, so this underestimates the range. + // However, this is sufficient for the purpose of finding the pointers to + // thread-specific data keys. + const uptr tcb_size = ThreadDescriptorSize(); + *addr -= tcb_size; + *size += tcb_size; +#endif +#endif +#elif SANITIZER_NETBSD + struct tls_tcb * const tcb = ThreadSelfTlsTcb(); + *addr = 0; + *size = 0; + if (tcb != 0) { + // Find size (p_memsz) of dlpi_tls_modid 1 (TLS block of the main program). + // ld.elf_so hardcodes the index 1. + dl_iterate_phdr(GetSizeFromHdr, size); + + if (*size != 0) { + // The block has been found and tcb_dtv[1] contains the base address + *addr = (uptr)tcb->tcb_dtv[1]; + } + } +#elif SANITIZER_SOLARIS + // FIXME + *addr = 0; + *size = 0; +#else +#error "Unknown OS" +#endif +} +#endif + +#if !SANITIZER_GO +uptr GetTlsSize() { +#if SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD || \ + SANITIZER_SOLARIS + uptr addr, size; + GetTls(&addr, &size); + return size; +#else + return 0; +#endif +} +#endif + +void GetThreadStackAndTls(bool main, uptr *stk_addr, uptr *stk_size, + uptr *tls_addr, uptr *tls_size) { +#if SANITIZER_GO + // Stub implementation for Go. + *stk_addr = *stk_size = *tls_addr = *tls_size = 0; +#else + GetTls(tls_addr, tls_size); + + uptr stack_top, stack_bottom; + GetThreadStackTopAndBottom(main, &stack_top, &stack_bottom); + *stk_addr = stack_bottom; + *stk_size = stack_top - stack_bottom; + + if (!main) { + // If stack and tls intersect, make them non-intersecting. + if (*tls_addr > *stk_addr && *tls_addr < *stk_addr + *stk_size) { + if (*stk_addr + *stk_size < *tls_addr + *tls_size) + *tls_size = *stk_addr + *stk_size - *tls_addr; + *stk_size = *tls_addr - *stk_addr; + } + } +#endif +} + +#if !SANITIZER_FREEBSD +typedef ElfW(Phdr) Elf_Phdr; +#elif SANITIZER_WORDSIZE == 32 && __FreeBSD_version <= 902001 // v9.2 +#define Elf_Phdr XElf32_Phdr +#define dl_phdr_info xdl_phdr_info +#define dl_iterate_phdr(c, b) xdl_iterate_phdr((c), (b)) +#endif // !SANITIZER_FREEBSD + +struct DlIteratePhdrData { + InternalMmapVectorNoCtor<LoadedModule> *modules; + bool first; +}; + +static int AddModuleSegments(const char *module_name, dl_phdr_info *info, + InternalMmapVectorNoCtor<LoadedModule> *modules) { + if (module_name[0] == '\0') + return 0; + LoadedModule cur_module; + cur_module.set(module_name, info->dlpi_addr); + for (int i = 0; i < (int)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; + bool executable = phdr->p_flags & PF_X; + bool writable = phdr->p_flags & PF_W; + cur_module.addAddressRange(cur_beg, cur_end, executable, + writable); + } else if (phdr->p_type == PT_NOTE) { +# ifdef NT_GNU_BUILD_ID + uptr off = 0; + while (off + sizeof(ElfW(Nhdr)) < phdr->p_memsz) { + auto *nhdr = reinterpret_cast<const ElfW(Nhdr) *>(info->dlpi_addr + + phdr->p_vaddr + off); + constexpr auto kGnuNamesz = 4; // "GNU" with NUL-byte. + static_assert(kGnuNamesz % 4 == 0, "kGnuNameSize is aligned to 4."); + if (nhdr->n_type == NT_GNU_BUILD_ID && nhdr->n_namesz == kGnuNamesz) { + if (off + sizeof(ElfW(Nhdr)) + nhdr->n_namesz + nhdr->n_descsz > + phdr->p_memsz) { + // Something is very wrong, bail out instead of reading potentially + // arbitrary memory. + break; + } + const char *name = + reinterpret_cast<const char *>(nhdr) + sizeof(*nhdr); + if (internal_memcmp(name, "GNU", 3) == 0) { + const char *value = reinterpret_cast<const char *>(nhdr) + + sizeof(*nhdr) + kGnuNamesz; + cur_module.setUuid(value, nhdr->n_descsz); + break; + } + } + off += sizeof(*nhdr) + RoundUpTo(nhdr->n_namesz, 4) + + RoundUpTo(nhdr->n_descsz, 4); + } +# endif + } + } + modules->push_back(cur_module); + return 0; +} + +static int dl_iterate_phdr_cb(dl_phdr_info *info, size_t size, void *arg) { + DlIteratePhdrData *data = (DlIteratePhdrData *)arg; + if (data->first) { + InternalMmapVector<char> module_name(kMaxPathLength); + data->first = false; + // First module is the binary itself. + ReadBinaryNameCached(module_name.data(), module_name.size()); + return AddModuleSegments(module_name.data(), info, data->modules); + } + + if (info->dlpi_name) { + InternalScopedString module_name; + module_name.append("%s", info->dlpi_name); + return AddModuleSegments(module_name.data(), info, data->modules); + } + + return 0; +} + +#if SANITIZER_ANDROID && __ANDROID_API__ < 21 +extern "C" __attribute__((weak)) int dl_iterate_phdr( + int (*)(struct dl_phdr_info *, size_t, void *), void *); +#endif + +static bool requiresProcmaps() { +#if SANITIZER_ANDROID && __ANDROID_API__ <= 22 + // Fall back to /proc/maps if dl_iterate_phdr is unavailable or broken. + // The runtime check allows the same library to work with + // both K and L (and future) Android releases. + return AndroidGetApiLevel() <= ANDROID_LOLLIPOP_MR1; +#else + return false; +#endif +} + +static void procmapsInit(InternalMmapVectorNoCtor<LoadedModule> *modules) { + MemoryMappingLayout memory_mapping(/*cache_enabled*/true); + memory_mapping.DumpListOfModules(modules); +} + +void ListOfModules::init() { + clearOrInit(); + if (requiresProcmaps()) { + procmapsInit(&modules_); + } else { + DlIteratePhdrData data = {&modules_, true}; + dl_iterate_phdr(dl_iterate_phdr_cb, &data); + } +} + +// When a custom loader is used, dl_iterate_phdr may not contain the full +// list of modules. Allow callers to fall back to using procmaps. +void ListOfModules::fallbackInit() { + if (!requiresProcmaps()) { + clearOrInit(); + procmapsInit(&modules_); + } else { + clear(); + } +} + +// getrusage does not give us the current RSS, only the max RSS. +// Still, this is better than nothing if /proc/self/statm is not available +// for some reason, e.g. due to a sandbox. +static uptr GetRSSFromGetrusage() { + struct rusage usage; + if (getrusage(RUSAGE_SELF, &usage)) // Failed, probably due to a sandbox. + return 0; + return usage.ru_maxrss << 10; // ru_maxrss is in Kb. +} + +uptr GetRSS() { + if (!common_flags()->can_use_proc_maps_statm) + return GetRSSFromGetrusage(); + fd_t fd = OpenFile("/proc/self/statm", RdOnly); + if (fd == kInvalidFd) + return GetRSSFromGetrusage(); + char buf[64]; + uptr len = internal_read(fd, buf, sizeof(buf) - 1); + internal_close(fd); + if ((sptr)len <= 0) + return 0; + buf[len] = 0; + // The format of the file is: + // 1084 89 69 11 0 79 0 + // We need the second number which is RSS in pages. + char *pos = buf; + // Skip the first number. + while (*pos >= '0' && *pos <= '9') + pos++; + // Skip whitespaces. + while (!(*pos >= '0' && *pos <= '9') && *pos != 0) + pos++; + // Read the number. + uptr rss = 0; + while (*pos >= '0' && *pos <= '9') + rss = rss * 10 + *pos++ - '0'; + return rss * GetPageSizeCached(); +} + +// sysconf(_SC_NPROCESSORS_{CONF,ONLN}) cannot be used on most platforms as +// they allocate memory. +u32 GetNumberOfCPUs() { +#if SANITIZER_FREEBSD || SANITIZER_NETBSD + u32 ncpu; + int req[2]; + uptr len = sizeof(ncpu); + req[0] = CTL_HW; + req[1] = HW_NCPU; + CHECK_EQ(internal_sysctl(req, 2, &ncpu, &len, NULL, 0), 0); + return ncpu; +#elif SANITIZER_ANDROID && !defined(CPU_COUNT) && !defined(__aarch64__) + // Fall back to /sys/devices/system/cpu on Android when cpu_set_t doesn't + // exist in sched.h. That is the case for toolchains generated with older + // NDKs. + // This code doesn't work on AArch64 because internal_getdents makes use of + // the 64bit getdents syscall, but cpu_set_t seems to always exist on AArch64. + uptr fd = internal_open("/sys/devices/system/cpu", O_RDONLY | O_DIRECTORY); + if (internal_iserror(fd)) + return 0; + InternalMmapVector<u8> buffer(4096); + uptr bytes_read = buffer.size(); + uptr n_cpus = 0; + u8 *d_type; + struct linux_dirent *entry = (struct linux_dirent *)&buffer[bytes_read]; + while (true) { + if ((u8 *)entry >= &buffer[bytes_read]) { + bytes_read = internal_getdents(fd, (struct linux_dirent *)buffer.data(), + buffer.size()); + if (internal_iserror(bytes_read) || !bytes_read) + break; + entry = (struct linux_dirent *)buffer.data(); + } + d_type = (u8 *)entry + entry->d_reclen - 1; + if (d_type >= &buffer[bytes_read] || + (u8 *)&entry->d_name[3] >= &buffer[bytes_read]) + break; + if (entry->d_ino != 0 && *d_type == DT_DIR) { + if (entry->d_name[0] == 'c' && entry->d_name[1] == 'p' && + entry->d_name[2] == 'u' && + entry->d_name[3] >= '0' && entry->d_name[3] <= '9') + n_cpus++; + } + entry = (struct linux_dirent *)(((u8 *)entry) + entry->d_reclen); + } + internal_close(fd); + return n_cpus; +#elif SANITIZER_SOLARIS + return sysconf(_SC_NPROCESSORS_ONLN); +#else + cpu_set_t CPUs; + CHECK_EQ(sched_getaffinity(0, sizeof(cpu_set_t), &CPUs), 0); + return CPU_COUNT(&CPUs); +#endif +} + +#if SANITIZER_LINUX + +#if SANITIZER_ANDROID +static atomic_uint8_t android_log_initialized; + +void AndroidLogInit() { + openlog(GetProcessName(), 0, LOG_USER); + atomic_store(&android_log_initialized, 1, memory_order_release); +} + +static bool ShouldLogAfterPrintf() { + return atomic_load(&android_log_initialized, memory_order_acquire); +} + +extern "C" SANITIZER_WEAK_ATTRIBUTE +int async_safe_write_log(int pri, const char* tag, const char* msg); +extern "C" SANITIZER_WEAK_ATTRIBUTE +int __android_log_write(int prio, const char* tag, const char* msg); + +// ANDROID_LOG_INFO is 4, but can't be resolved at runtime. +#define SANITIZER_ANDROID_LOG_INFO 4 + +// async_safe_write_log is a new public version of __libc_write_log that is +// used behind syslog. It is preferable to syslog as it will not do any dynamic +// memory allocation or formatting. +// If the function is not available, syslog is preferred for L+ (it was broken +// pre-L) as __android_log_write triggers a racey behavior with the strncpy +// interceptor. Fallback to __android_log_write pre-L. +void WriteOneLineToSyslog(const char *s) { + if (&async_safe_write_log) { + async_safe_write_log(SANITIZER_ANDROID_LOG_INFO, GetProcessName(), s); + } else if (AndroidGetApiLevel() > ANDROID_KITKAT) { + syslog(LOG_INFO, "%s", s); + } else { + CHECK(&__android_log_write); + __android_log_write(SANITIZER_ANDROID_LOG_INFO, nullptr, s); + } +} + +extern "C" SANITIZER_WEAK_ATTRIBUTE +void android_set_abort_message(const char *); + +void SetAbortMessage(const char *str) { + if (&android_set_abort_message) + android_set_abort_message(str); +} +#else +void AndroidLogInit() {} + +static bool ShouldLogAfterPrintf() { return true; } + +void WriteOneLineToSyslog(const char *s) { syslog(LOG_INFO, "%s", s); } + +void SetAbortMessage(const char *str) {} +#endif // SANITIZER_ANDROID + +void LogMessageOnPrintf(const char *str) { + if (common_flags()->log_to_syslog && ShouldLogAfterPrintf()) + WriteToSyslog(str); +} + +#endif // SANITIZER_LINUX + +#if SANITIZER_GLIBC && !SANITIZER_GO +// glibc crashes when using clock_gettime from a preinit_array function as the +// vDSO function pointers haven't been initialized yet. __progname is +// initialized after the vDSO function pointers, so if it exists, is not null +// and is not empty, we can use clock_gettime. +extern "C" SANITIZER_WEAK_ATTRIBUTE char *__progname; +inline bool CanUseVDSO() { return &__progname && __progname && *__progname; } + +// MonotonicNanoTime is a timing function that can leverage the vDSO by calling +// clock_gettime. real_clock_gettime only exists if clock_gettime is +// intercepted, so define it weakly and use it if available. +extern "C" SANITIZER_WEAK_ATTRIBUTE +int real_clock_gettime(u32 clk_id, void *tp); +u64 MonotonicNanoTime() { + timespec ts; + if (CanUseVDSO()) { + if (&real_clock_gettime) + real_clock_gettime(CLOCK_MONOTONIC, &ts); + else + clock_gettime(CLOCK_MONOTONIC, &ts); + } else { + internal_clock_gettime(CLOCK_MONOTONIC, &ts); + } + return (u64)ts.tv_sec * (1000ULL * 1000 * 1000) + ts.tv_nsec; +} +#else +// Non-glibc & Go always use the regular function. +u64 MonotonicNanoTime() { + timespec ts; + clock_gettime(CLOCK_MONOTONIC, &ts); + return (u64)ts.tv_sec * (1000ULL * 1000 * 1000) + ts.tv_nsec; +} +#endif // SANITIZER_GLIBC && !SANITIZER_GO + +void ReExec() { + const char *pathname = "/proc/self/exe"; + +#if SANITIZER_NETBSD + static const int name[] = { + CTL_KERN, + KERN_PROC_ARGS, + -1, + KERN_PROC_PATHNAME, + }; + char path[400]; + uptr len; + + len = sizeof(path); + if (internal_sysctl(name, ARRAY_SIZE(name), path, &len, NULL, 0) != -1) + pathname = path; +#elif SANITIZER_SOLARIS + pathname = getexecname(); + CHECK_NE(pathname, NULL); +#elif SANITIZER_USE_GETAUXVAL + // Calling execve with /proc/self/exe sets that as $EXEC_ORIGIN. Binaries that + // rely on that will fail to load shared libraries. Query AT_EXECFN instead. + pathname = reinterpret_cast<const char *>(getauxval(AT_EXECFN)); +#endif + + uptr rv = internal_execve(pathname, GetArgv(), GetEnviron()); + int rverrno; + CHECK_EQ(internal_iserror(rv, &rverrno), true); + Printf("execve failed, errno %d\n", rverrno); + Die(); +} + +void UnmapFromTo(uptr from, uptr to) { + if (to == from) + return; + CHECK(to >= from); + uptr res = internal_munmap(reinterpret_cast<void *>(from), to - from); + if (UNLIKELY(internal_iserror(res))) { + Report("ERROR: %s failed to unmap 0x%zx (%zd) bytes at address %p\n", + SanitizerToolName, to - from, to - from, (void *)from); + CHECK("unable to unmap" && 0); + } +} + +uptr MapDynamicShadow(uptr shadow_size_bytes, uptr shadow_scale, + uptr min_shadow_base_alignment, + UNUSED uptr &high_mem_end) { + const uptr granularity = GetMmapGranularity(); + const uptr alignment = + Max<uptr>(granularity << shadow_scale, 1ULL << min_shadow_base_alignment); + const uptr left_padding = + Max<uptr>(granularity, 1ULL << min_shadow_base_alignment); + + const uptr shadow_size = RoundUpTo(shadow_size_bytes, granularity); + const uptr map_size = shadow_size + left_padding + alignment; + + const uptr map_start = (uptr)MmapNoAccess(map_size); + CHECK_NE(map_start, ~(uptr)0); + + const uptr shadow_start = RoundUpTo(map_start + left_padding, alignment); + + UnmapFromTo(map_start, shadow_start - left_padding); + UnmapFromTo(shadow_start + shadow_size, map_start + map_size); + + return shadow_start; +} + +static uptr MmapSharedNoReserve(uptr addr, uptr size) { + return internal_mmap( + reinterpret_cast<void *>(addr), size, PROT_READ | PROT_WRITE, + MAP_FIXED | MAP_SHARED | MAP_ANONYMOUS | MAP_NORESERVE, -1, 0); +} + +static uptr MremapCreateAlias(uptr base_addr, uptr alias_addr, + uptr alias_size) { +#if SANITIZER_LINUX + return internal_mremap(reinterpret_cast<void *>(base_addr), 0, alias_size, + MREMAP_MAYMOVE | MREMAP_FIXED, + reinterpret_cast<void *>(alias_addr)); +#else + CHECK(false && "mremap is not supported outside of Linux"); + return 0; +#endif +} + +static void CreateAliases(uptr start_addr, uptr alias_size, uptr num_aliases) { + uptr total_size = alias_size * num_aliases; + uptr mapped = MmapSharedNoReserve(start_addr, total_size); + CHECK_EQ(mapped, start_addr); + + for (uptr i = 1; i < num_aliases; ++i) { + uptr alias_addr = start_addr + i * alias_size; + CHECK_EQ(MremapCreateAlias(start_addr, alias_addr, alias_size), alias_addr); + } +} + +uptr MapDynamicShadowAndAliases(uptr shadow_size, uptr alias_size, + uptr num_aliases, uptr ring_buffer_size) { + CHECK_EQ(alias_size & (alias_size - 1), 0); + CHECK_EQ(num_aliases & (num_aliases - 1), 0); + CHECK_EQ(ring_buffer_size & (ring_buffer_size - 1), 0); + + const uptr granularity = GetMmapGranularity(); + shadow_size = RoundUpTo(shadow_size, granularity); + CHECK_EQ(shadow_size & (shadow_size - 1), 0); + + const uptr alias_region_size = alias_size * num_aliases; + const uptr alignment = + 2 * Max(Max(shadow_size, alias_region_size), ring_buffer_size); + const uptr left_padding = ring_buffer_size; + + const uptr right_size = alignment; + const uptr map_size = left_padding + 2 * alignment; + + const uptr map_start = reinterpret_cast<uptr>(MmapNoAccess(map_size)); + CHECK_NE(map_start, static_cast<uptr>(-1)); + const uptr right_start = RoundUpTo(map_start + left_padding, alignment); + + UnmapFromTo(map_start, right_start - left_padding); + UnmapFromTo(right_start + right_size, map_start + map_size); + + CreateAliases(right_start + right_size / 2, alias_size, num_aliases); + + return right_start; +} + +void InitializePlatformCommonFlags(CommonFlags *cf) { +#if SANITIZER_ANDROID + if (&__libc_get_static_tls_bounds == nullptr) + cf->detect_leaks = false; +#endif +} + +} // namespace __sanitizer + +#endif diff --git a/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_linux_s390.cpp b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_linux_s390.cpp new file mode 100644 index 0000000000..74db831b0a --- /dev/null +++ b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_linux_s390.cpp @@ -0,0 +1,228 @@ +//===-- sanitizer_linux_s390.cpp ------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file is shared between AddressSanitizer and ThreadSanitizer +// run-time libraries and implements s390-linux-specific functions from +// sanitizer_libc.h. +//===----------------------------------------------------------------------===// + +#include "sanitizer_platform.h" + +#if SANITIZER_LINUX && SANITIZER_S390 + +#include <dlfcn.h> +#include <errno.h> +#include <sys/syscall.h> +#include <sys/utsname.h> +#include <unistd.h> + +#include "sanitizer_libc.h" +#include "sanitizer_linux.h" + +namespace __sanitizer { + +// --------------- sanitizer_libc.h +uptr internal_mmap(void *addr, uptr length, int prot, int flags, int fd, + u64 offset) { + struct s390_mmap_params { + unsigned long addr; + unsigned long length; + unsigned long prot; + unsigned long flags; + unsigned long fd; + unsigned long offset; + } params = { + (unsigned long)addr, + (unsigned long)length, + (unsigned long)prot, + (unsigned long)flags, + (unsigned long)fd, +# ifdef __s390x__ + (unsigned long)offset, +# else + (unsigned long)(offset / 4096), +# endif + }; +# ifdef __s390x__ + return syscall(__NR_mmap, ¶ms); +# else + return syscall(__NR_mmap2, ¶ms); +# endif +} + +uptr internal_clone(int (*fn)(void *), void *child_stack, int flags, void *arg, + int *parent_tidptr, void *newtls, int *child_tidptr) { + if (!fn || !child_stack) { + errno = EINVAL; + return -1; + } + CHECK_EQ(0, (uptr)child_stack % 16); + // Minimum frame size. +#ifdef __s390x__ + child_stack = (char *)child_stack - 160; +#else + child_stack = (char *)child_stack - 96; +#endif + // Terminate unwind chain. + ((unsigned long *)child_stack)[0] = 0; + // And pass parameters. + ((unsigned long *)child_stack)[1] = (uptr)fn; + ((unsigned long *)child_stack)[2] = (uptr)arg; + register uptr res __asm__("r2"); + register void *__cstack __asm__("r2") = child_stack; + register long __flags __asm__("r3") = flags; + register int * __ptidptr __asm__("r4") = parent_tidptr; + register int * __ctidptr __asm__("r5") = child_tidptr; + register void * __newtls __asm__("r6") = newtls; + + __asm__ __volatile__( + /* Clone. */ + "svc %1\n" + + /* if (%r2 != 0) + * return; + */ +#ifdef __s390x__ + "cghi %%r2, 0\n" +#else + "chi %%r2, 0\n" +#endif + "jne 1f\n" + + /* Call "fn(arg)". */ +#ifdef __s390x__ + "lmg %%r1, %%r2, 8(%%r15)\n" +#else + "lm %%r1, %%r2, 4(%%r15)\n" +#endif + "basr %%r14, %%r1\n" + + /* Call _exit(%r2). */ + "svc %2\n" + + /* Return to parent. */ + "1:\n" + : "=r" (res) + : "i"(__NR_clone), "i"(__NR_exit), + "r"(__cstack), + "r"(__flags), + "r"(__ptidptr), + "r"(__ctidptr), + "r"(__newtls) + : "memory", "cc"); + if (res >= (uptr)-4095) { + errno = -res; + return -1; + } + return res; +} + +#if SANITIZER_S390_64 +static bool FixedCVE_2016_2143() { + // Try to determine if the running kernel has a fix for CVE-2016-2143, + // return false if in doubt (better safe than sorry). Distros may want to + // adjust this for their own kernels. + struct utsname buf; + unsigned int major, minor, patch = 0; + // This should never fail, but just in case... + if (internal_uname(&buf)) + return false; + const char *ptr = buf.release; + major = internal_simple_strtoll(ptr, &ptr, 10); + // At least first 2 should be matched. + if (ptr[0] != '.') + return false; + minor = internal_simple_strtoll(ptr+1, &ptr, 10); + // Third is optional. + if (ptr[0] == '.') + patch = internal_simple_strtoll(ptr+1, &ptr, 10); + if (major < 3) { + if (major == 2 && minor == 6 && patch == 32 && ptr[0] == '-' && + internal_strstr(ptr, ".el6")) { + // Check RHEL6 + int r1 = internal_simple_strtoll(ptr+1, &ptr, 10); + if (r1 >= 657) // 2.6.32-657.el6 or later + return true; + if (r1 == 642 && ptr[0] == '.') { + int r2 = internal_simple_strtoll(ptr+1, &ptr, 10); + if (r2 >= 9) // 2.6.32-642.9.1.el6 or later + return true; + } + } + // <3.0 is bad. + return false; + } else if (major == 3) { + // 3.2.79+ is OK. + if (minor == 2 && patch >= 79) + return true; + // 3.12.58+ is OK. + if (minor == 12 && patch >= 58) + return true; + if (minor == 10 && patch == 0 && ptr[0] == '-' && + internal_strstr(ptr, ".el7")) { + // Check RHEL7 + int r1 = internal_simple_strtoll(ptr+1, &ptr, 10); + if (r1 >= 426) // 3.10.0-426.el7 or later + return true; + if (r1 == 327 && ptr[0] == '.') { + int r2 = internal_simple_strtoll(ptr+1, &ptr, 10); + if (r2 >= 27) // 3.10.0-327.27.1.el7 or later + return true; + } + } + // Otherwise, bad. + return false; + } else if (major == 4) { + // 4.1.21+ is OK. + if (minor == 1 && patch >= 21) + return true; + // 4.4.6+ is OK. + if (minor == 4 && patch >= 6) + return true; + if (minor == 4 && patch == 0 && ptr[0] == '-' && + internal_strstr(buf.version, "Ubuntu")) { + // Check Ubuntu 16.04 + int r1 = internal_simple_strtoll(ptr+1, &ptr, 10); + if (r1 >= 13) // 4.4.0-13 or later + return true; + } + // Otherwise, OK if 4.5+. + return minor >= 5; + } else { + // Linux 5 and up are fine. + return true; + } +} + +void AvoidCVE_2016_2143() { + // Older kernels are affected by CVE-2016-2143 - they will crash hard + // if someone uses 4-level page tables (ie. virtual addresses >= 4TB) + // and fork() in the same process. Unfortunately, sanitizers tend to + // require such addresses. Since this is very likely to crash the whole + // machine (sanitizers themselves use fork() for llvm-symbolizer, for one), + // abort the process at initialization instead. + if (FixedCVE_2016_2143()) + return; + if (GetEnv("SANITIZER_IGNORE_CVE_2016_2143")) + return; + Report( + "ERROR: Your kernel seems to be vulnerable to CVE-2016-2143. Using ASan,\n" + "MSan, TSan, DFSan or LSan with such kernel can and will crash your\n" + "machine, or worse.\n" + "\n" + "If you are certain your kernel is not vulnerable (you have compiled it\n" + "yourself, or are using an unrecognized distribution kernel), you can\n" + "override this safety check by exporting SANITIZER_IGNORE_CVE_2016_2143\n" + "with any value.\n"); + Die(); +} +#endif + +} // namespace __sanitizer + +#endif // SANITIZER_LINUX && SANITIZER_S390 diff --git a/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_list.h b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_list.h new file mode 100644 index 0000000000..f0b925945e --- /dev/null +++ b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_list.h @@ -0,0 +1,166 @@ +//===-- sanitizer_list.h ----------------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// 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 { + friend class Iterator; + + void clear() { + first_ = last_ = nullptr; + size_ = 0; + } + + bool empty() const { return size_ == 0; } + uptr size() const { return size_; } + + void push_back(Item *x) { + if (empty()) { + x->next = nullptr; + first_ = last_ = x; + size_ = 1; + } else { + x->next = nullptr; + last_->next = x; + last_ = x; + size_++; + } + } + + void push_front(Item *x) { + if (empty()) { + x->next = nullptr; + first_ = last_ = x; + size_ = 1; + } else { + x->next = first_; + first_ = x; + size_++; + } + } + + void pop_front() { + CHECK(!empty()); + first_ = first_->next; + if (!first_) + last_ = nullptr; + size_--; + } + + void extract(Item *prev, Item *x) { + CHECK(!empty()); + CHECK_NE(prev, nullptr); + CHECK_NE(x, nullptr); + CHECK_EQ(prev->next, x); + prev->next = x->next; + if (last_ == x) + last_ = prev; + size_--; + } + + Item *front() { return first_; } + const Item *front() const { return first_; } + Item *back() { return last_; } + const Item *back() const { return last_; } + + void append_front(IntrusiveList<Item> *l) { + CHECK_NE(this, l); + if (l->empty()) + return; + 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 (l->empty()) + return; + 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); + } + } + + template<class ItemTy> + class IteratorBase { + public: + explicit IteratorBase(ItemTy *current) : current_(current) {} + IteratorBase &operator++() { + current_ = current_->next; + return *this; + } + bool operator!=(IteratorBase other) const { + return current_ != other.current_; + } + ItemTy &operator*() { + return *current_; + } + private: + ItemTy *current_; + }; + + typedef IteratorBase<Item> Iterator; + typedef IteratorBase<const Item> ConstIterator; + + Iterator begin() { return Iterator(first_); } + Iterator end() { return Iterator(0); } + + ConstIterator begin() const { return ConstIterator(first_); } + ConstIterator end() const { return ConstIterator(0); } + +// private, don't use directly. + uptr size_; + Item *first_; + Item *last_; +}; + +} // namespace __sanitizer + +#endif // SANITIZER_LIST_H diff --git a/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_local_address_space_view.h b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_local_address_space_view.h new file mode 100644 index 0000000000..a47cfc945c --- /dev/null +++ b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_local_address_space_view.h @@ -0,0 +1,76 @@ +//===-- sanitizer_local_address_space_view.h --------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// `LocalAddressSpaceView` provides the local (i.e. target and current address +// space are the same) implementation of the `AddressSpaceView` interface which +// provides a simple interface to load memory from another process (i.e. +// out-of-process) +// +// The `AddressSpaceView` interface requires that the type can be used as a +// template parameter to objects that wish to be able to operate in an +// out-of-process manner. In normal usage, objects are in-process and are thus +// instantiated with the `LocalAddressSpaceView` type. This type is used to +// load any pointers in instance methods. This implementation is effectively +// a no-op. When an object is to be used in an out-of-process manner it is +// instantiated with the `RemoteAddressSpaceView` type. +// +// By making `AddressSpaceView` a template parameter of an object, it can +// change its implementation at compile time which has no run time overhead. +// This also allows unifying in-process and out-of-process code which avoids +// code duplication. +// +//===----------------------------------------------------------------------===// +#ifndef SANITIZER_LOCAL_ADDRES_SPACE_VIEW_H +#define SANITIZER_LOCAL_ADDRES_SPACE_VIEW_H + +namespace __sanitizer { +struct LocalAddressSpaceView { + // Load memory `sizeof(T) * num_elements` bytes of memory from the target + // process (always local for this implementation) starting at address + // `target_address`. The local copy of this memory is returned as a pointer. + // The caller should not write to this memory. The behaviour when doing so is + // undefined. Callers should use `LoadWritable()` to get access to memory + // that is writable. + // + // The lifetime of loaded memory is implementation defined. + template <typename T> + static const T *Load(const T *target_address, uptr num_elements = 1) { + // The target address space is the local address space so + // nothing needs to be copied. Just return the pointer. + return target_address; + } + + // Load memory `sizeof(T) * num_elements` bytes of memory from the target + // process (always local for this implementation) starting at address + // `target_address`. The local copy of this memory is returned as a pointer. + // The memory returned may be written to. + // + // Writes made to the returned memory will be visible in the memory returned + // by subsequent `Load()` or `LoadWritable()` calls provided the + // `target_address` parameter is the same. It is not guaranteed that the + // memory returned by previous calls to `Load()` will contain any performed + // writes. If two or more overlapping regions of memory are loaded via + // separate calls to `LoadWritable()`, it is implementation defined whether + // writes made to the region returned by one call are visible in the regions + // returned by other calls. + // + // Given the above it is recommended to load the largest possible object + // that requires modification (e.g. a class) rather than individual fields + // from a class to avoid issues with overlapping writable regions. + // + // The lifetime of loaded memory is implementation defined. + template <typename T> + static T *LoadWritable(T *target_address, uptr num_elements = 1) { + // The target address space is the local address space so + // nothing needs to be copied. Just return the pointer. + return target_address; + } +}; +} // namespace __sanitizer + +#endif diff --git a/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_lzw.h b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_lzw.h new file mode 100644 index 0000000000..42acfbdcea --- /dev/null +++ b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_lzw.h @@ -0,0 +1,159 @@ +//===-- sanitizer_lzw.h -----------------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// Lempel–Ziv–Welch encoding/decoding +// +//===----------------------------------------------------------------------===// + +#ifndef SANITIZER_LZW_H +#define SANITIZER_LZW_H + +#include "sanitizer_dense_map.h" + +namespace __sanitizer { + +using LzwCodeType = u32; + +template <class T, class ItIn, class ItOut> +ItOut LzwEncode(ItIn begin, ItIn end, ItOut out) { + using Substring = + detail::DenseMapPair<LzwCodeType /* Prefix */, T /* Next input */>; + + // Sentinel value for substrings of len 1. + static constexpr LzwCodeType kNoPrefix = + Min(DenseMapInfo<Substring>::getEmptyKey().first, + DenseMapInfo<Substring>::getTombstoneKey().first) - + 1; + DenseMap<Substring, LzwCodeType> prefix_to_code; + { + // Add all substring of len 1 as initial dictionary. + InternalMmapVector<T> dict_len1; + for (auto it = begin; it != end; ++it) + if (prefix_to_code.try_emplace({kNoPrefix, *it}, 0).second) + dict_len1.push_back(*it); + + // Slightly helps with later delta encoding. + Sort(dict_len1.data(), dict_len1.size()); + + // For large sizeof(T) we have to store dict_len1. Smaller types like u8 can + // just generate them. + *out = dict_len1.size(); + ++out; + + for (uptr i = 0; i != dict_len1.size(); ++i) { + // Remap after the Sort. + prefix_to_code[{kNoPrefix, dict_len1[i]}] = i; + *out = dict_len1[i]; + ++out; + } + CHECK_EQ(prefix_to_code.size(), dict_len1.size()); + } + + if (begin == end) + return out; + + // Main LZW encoding loop. + LzwCodeType match = prefix_to_code.find({kNoPrefix, *begin})->second; + ++begin; + for (auto it = begin; it != end; ++it) { + // Extend match with the new item. + auto ins = prefix_to_code.try_emplace({match, *it}, prefix_to_code.size()); + if (ins.second) { + // This is a new substring, but emit the code for the current match + // (before extend). This allows LZW decoder to recover the dictionary. + *out = match; + ++out; + // Reset the match to a single item, which must be already in the map. + match = prefix_to_code.find({kNoPrefix, *it})->second; + } else { + // Already known, use as the current match. + match = ins.first->second; + } + } + + *out = match; + ++out; + + return out; +} + +template <class T, class ItIn, class ItOut> +ItOut LzwDecode(ItIn begin, ItIn end, ItOut out) { + if (begin == end) + return out; + + // Load dictionary of len 1 substrings. Theses correspont to lowest codes. + InternalMmapVector<T> dict_len1(*begin); + ++begin; + + if (begin == end) + return out; + + for (auto& v : dict_len1) { + v = *begin; + ++begin; + } + + // Substrings of len 2 and up. Indexes are shifted because [0, + // dict_len1.size()) stored in dict_len1. Substings get here after being + // emitted to the output, so we can use output position. + InternalMmapVector<detail::DenseMapPair<ItOut /* begin. */, ItOut /* end */>> + code_to_substr; + + // Copies already emitted substrings into the output again. + auto copy = [&code_to_substr, &dict_len1](LzwCodeType code, ItOut out) { + if (code < dict_len1.size()) { + *out = dict_len1[code]; + ++out; + return out; + } + const auto& s = code_to_substr[code - dict_len1.size()]; + + for (ItOut it = s.first; it != s.second; ++it, ++out) *out = *it; + return out; + }; + + // Returns lens of the substring with the given code. + auto code_to_len = [&code_to_substr, &dict_len1](LzwCodeType code) -> uptr { + if (code < dict_len1.size()) + return 1; + const auto& s = code_to_substr[code - dict_len1.size()]; + return s.second - s.first; + }; + + // Main LZW decoding loop. + LzwCodeType prev_code = *begin; + ++begin; + out = copy(prev_code, out); + for (auto it = begin; it != end; ++it) { + LzwCodeType code = *it; + auto start = out; + if (code == dict_len1.size() + code_to_substr.size()) { + // Special LZW case. The code is not in the dictionary yet. This is + // possible only when the new substring is the same as previous one plus + // the first item of the previous substring. We can emit that in two + // steps. + out = copy(prev_code, out); + *out = *start; + ++out; + } else { + out = copy(code, out); + } + + // Every time encoded emits the code, it also creates substing of len + 1 + // including the first item of the just emmited substring. Do the same here. + uptr len = code_to_len(prev_code); + code_to_substr.push_back({start - len, start + 1}); + + prev_code = code; + } + return out; +} + +} // namespace __sanitizer +#endif diff --git a/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_mac.cpp b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_mac.cpp new file mode 100644 index 0000000000..3b20e1c5e2 --- /dev/null +++ b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_mac.cpp @@ -0,0 +1,1425 @@ +//===-- sanitizer_mac.cpp -------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file is shared between various sanitizers' runtime libraries and +// implements OSX-specific functions. +//===----------------------------------------------------------------------===// + +#include "sanitizer_platform.h" +#if SANITIZER_MAC +#include "sanitizer_mac.h" +#include "interception/interception.h" + +// Use 64-bit inodes in file operations. ASan does not support OS X 10.5, so +// the clients will most certainly use 64-bit ones as well. +#ifndef _DARWIN_USE_64_BIT_INODE +#define _DARWIN_USE_64_BIT_INODE 1 +#endif +#include <stdio.h> + +#include "sanitizer_common.h" +#include "sanitizer_file.h" +#include "sanitizer_flags.h" +#include "sanitizer_internal_defs.h" +#include "sanitizer_libc.h" +#include "sanitizer_platform_limits_posix.h" +#include "sanitizer_procmaps.h" +#include "sanitizer_ptrauth.h" + +#if !SANITIZER_IOS +#include <crt_externs.h> // for _NSGetEnviron +#else +extern char **environ; +#endif + +#if defined(__has_include) && __has_include(<os/trace.h>) +#define SANITIZER_OS_TRACE 1 +#include <os/trace.h> +#else +#define SANITIZER_OS_TRACE 0 +#endif + +// import new crash reporting api +#if defined(__has_include) && __has_include(<CrashReporterClient.h>) +#define HAVE_CRASHREPORTERCLIENT_H 1 +#include <CrashReporterClient.h> +#else +#define HAVE_CRASHREPORTERCLIENT_H 0 +#endif + +#if !SANITIZER_IOS +#include <crt_externs.h> // for _NSGetArgv and _NSGetEnviron +#else +extern "C" { + extern char ***_NSGetArgv(void); +} +#endif + +#include <asl.h> +#include <dlfcn.h> // for dladdr() +#include <errno.h> +#include <fcntl.h> +#include <libkern/OSAtomic.h> +#include <mach-o/dyld.h> +#include <mach/mach.h> +#include <mach/mach_time.h> +#include <mach/vm_statistics.h> +#include <malloc/malloc.h> +#include <os/log.h> +#include <pthread.h> +#include <sched.h> +#include <signal.h> +#include <spawn.h> +#include <stdlib.h> +#include <sys/ioctl.h> +#include <sys/mman.h> +#include <sys/resource.h> +#include <sys/stat.h> +#include <sys/sysctl.h> +#include <sys/types.h> +#include <sys/wait.h> +#include <unistd.h> +#include <util.h> + +// From <crt_externs.h>, but we don't have that file on iOS. +extern "C" { + extern char ***_NSGetArgv(void); + extern char ***_NSGetEnviron(void); +} + +// From <mach/mach_vm.h>, but we don't have that file on iOS. +extern "C" { + extern kern_return_t mach_vm_region_recurse( + vm_map_t target_task, + mach_vm_address_t *address, + mach_vm_size_t *size, + natural_t *nesting_depth, + vm_region_recurse_info_t info, + mach_msg_type_number_t *infoCnt); +} + +namespace __sanitizer { + +#include "sanitizer_syscall_generic.inc" + +// Direct syscalls, don't call libmalloc hooks (but not available on 10.6). +extern "C" void *__mmap(void *addr, size_t len, int prot, int flags, int fildes, + off_t off) SANITIZER_WEAK_ATTRIBUTE; +extern "C" int __munmap(void *, size_t) SANITIZER_WEAK_ATTRIBUTE; + +// ---------------------- sanitizer_libc.h + +// From <mach/vm_statistics.h>, but not on older OSs. +#ifndef VM_MEMORY_SANITIZER +#define VM_MEMORY_SANITIZER 99 +#endif + +// XNU on Darwin provides a mmap flag that optimizes allocation/deallocation of +// giant memory regions (i.e. shadow memory regions). +#define kXnuFastMmapFd 0x4 +static size_t kXnuFastMmapThreshold = 2 << 30; // 2 GB +static bool use_xnu_fast_mmap = false; + +uptr internal_mmap(void *addr, size_t length, int prot, int flags, + int fd, u64 offset) { + if (fd == -1) { + fd = VM_MAKE_TAG(VM_MEMORY_SANITIZER); + if (length >= kXnuFastMmapThreshold) { + if (use_xnu_fast_mmap) fd |= kXnuFastMmapFd; + } + } + if (&__mmap) return (uptr)__mmap(addr, length, prot, flags, fd, offset); + return (uptr)mmap(addr, length, prot, flags, fd, offset); +} + +uptr internal_munmap(void *addr, uptr length) { + if (&__munmap) return __munmap(addr, length); + return munmap(addr, length); +} + +uptr internal_mremap(void *old_address, uptr old_size, uptr new_size, int flags, + void *new_address) { + CHECK(false && "internal_mremap is unimplemented on Mac"); + return 0; +} + +int internal_mprotect(void *addr, uptr length, int prot) { + return mprotect(addr, length, prot); +} + +int internal_madvise(uptr addr, uptr length, int advice) { + return madvise((void *)addr, length, advice); +} + +uptr internal_close(fd_t fd) { + return close(fd); +} + +uptr internal_open(const char *filename, int flags) { + return open(filename, flags); +} + +uptr internal_open(const char *filename, int flags, u32 mode) { + return open(filename, flags, mode); +} + +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_stat(const char *path, void *buf) { + return stat(path, (struct stat *)buf); +} + +uptr internal_lstat(const char *path, void *buf) { + return lstat(path, (struct stat *)buf); +} + +uptr internal_fstat(fd_t fd, void *buf) { + return fstat(fd, (struct stat *)buf); +} + +uptr internal_filesize(fd_t fd) { + struct stat st; + if (internal_fstat(fd, &st)) + return -1; + return (uptr)st.st_size; +} + +uptr internal_dup(int oldfd) { + return dup(oldfd); +} + +uptr internal_dup2(int oldfd, int newfd) { + return dup2(oldfd, newfd); +} + +uptr internal_readlink(const char *path, char *buf, uptr bufsize) { + return readlink(path, buf, bufsize); +} + +uptr internal_unlink(const char *path) { + return unlink(path); +} + +uptr internal_sched_yield() { + return sched_yield(); +} + +void internal__exit(int exitcode) { + _exit(exitcode); +} + +void internal_usleep(u64 useconds) { usleep(useconds); } + +uptr internal_getpid() { + return getpid(); +} + +int internal_dlinfo(void *handle, int request, void *p) { + UNIMPLEMENTED(); +} + +int internal_sigaction(int signum, const void *act, void *oldact) { + return sigaction(signum, + (const struct sigaction *)act, (struct sigaction *)oldact); +} + +void internal_sigfillset(__sanitizer_sigset_t *set) { sigfillset(set); } + +uptr internal_sigprocmask(int how, __sanitizer_sigset_t *set, + __sanitizer_sigset_t *oldset) { + // Don't use sigprocmask here, because it affects all threads. + return pthread_sigmask(how, set, oldset); +} + +// Doesn't call pthread_atfork() handlers (but not available on 10.6). +extern "C" pid_t __fork(void) SANITIZER_WEAK_ATTRIBUTE; + +int internal_fork() { + if (&__fork) + return __fork(); + return fork(); +} + +int internal_sysctl(const int *name, unsigned int namelen, void *oldp, + uptr *oldlenp, const void *newp, uptr newlen) { + return sysctl(const_cast<int *>(name), namelen, oldp, (size_t *)oldlenp, + const_cast<void *>(newp), (size_t)newlen); +} + +int internal_sysctlbyname(const char *sname, void *oldp, uptr *oldlenp, + const void *newp, uptr newlen) { + return sysctlbyname(sname, oldp, (size_t *)oldlenp, const_cast<void *>(newp), + (size_t)newlen); +} + +static fd_t internal_spawn_impl(const char *argv[], const char *envp[], + pid_t *pid) { + fd_t primary_fd = kInvalidFd; + fd_t secondary_fd = kInvalidFd; + + auto fd_closer = at_scope_exit([&] { + internal_close(primary_fd); + internal_close(secondary_fd); + }); + + // We need a new pseudoterminal to avoid buffering problems. The 'atos' tool + // in particular detects when it's talking to a pipe and forgets to flush the + // output stream after sending a response. + primary_fd = posix_openpt(O_RDWR); + if (primary_fd == kInvalidFd) + return kInvalidFd; + + int res = grantpt(primary_fd) || unlockpt(primary_fd); + if (res != 0) return kInvalidFd; + + // Use TIOCPTYGNAME instead of ptsname() to avoid threading problems. + char secondary_pty_name[128]; + res = ioctl(primary_fd, TIOCPTYGNAME, secondary_pty_name); + if (res == -1) return kInvalidFd; + + secondary_fd = internal_open(secondary_pty_name, O_RDWR); + if (secondary_fd == kInvalidFd) + return kInvalidFd; + + // File descriptor actions + posix_spawn_file_actions_t acts; + res = posix_spawn_file_actions_init(&acts); + if (res != 0) return kInvalidFd; + + auto acts_cleanup = at_scope_exit([&] { + posix_spawn_file_actions_destroy(&acts); + }); + + res = posix_spawn_file_actions_adddup2(&acts, secondary_fd, STDIN_FILENO) || + posix_spawn_file_actions_adddup2(&acts, secondary_fd, STDOUT_FILENO) || + posix_spawn_file_actions_addclose(&acts, secondary_fd); + if (res != 0) return kInvalidFd; + + // Spawn attributes + posix_spawnattr_t attrs; + res = posix_spawnattr_init(&attrs); + if (res != 0) return kInvalidFd; + + auto attrs_cleanup = at_scope_exit([&] { + posix_spawnattr_destroy(&attrs); + }); + + // In the spawned process, close all file descriptors that are not explicitly + // described by the file actions object. This is Darwin-specific extension. + res = posix_spawnattr_setflags(&attrs, POSIX_SPAWN_CLOEXEC_DEFAULT); + if (res != 0) return kInvalidFd; + + // posix_spawn + char **argv_casted = const_cast<char **>(argv); + char **envp_casted = const_cast<char **>(envp); + res = posix_spawn(pid, argv[0], &acts, &attrs, argv_casted, envp_casted); + if (res != 0) return kInvalidFd; + + // Disable echo in the new terminal, disable CR. + struct termios termflags; + tcgetattr(primary_fd, &termflags); + termflags.c_oflag &= ~ONLCR; + termflags.c_lflag &= ~ECHO; + tcsetattr(primary_fd, TCSANOW, &termflags); + + // On success, do not close primary_fd on scope exit. + fd_t fd = primary_fd; + primary_fd = kInvalidFd; + + return fd; +} + +fd_t internal_spawn(const char *argv[], const char *envp[], pid_t *pid) { + // The client program may close its stdin and/or stdout and/or stderr thus + // allowing open/posix_openpt to reuse file descriptors 0, 1 or 2. In this + // case the communication is broken if either the parent or the child tries to + // close or duplicate these descriptors. We temporarily reserve these + // descriptors here to prevent this. + fd_t low_fds[3]; + size_t count = 0; + + for (; count < 3; count++) { + low_fds[count] = posix_openpt(O_RDWR); + if (low_fds[count] >= STDERR_FILENO) + break; + } + + fd_t fd = internal_spawn_impl(argv, envp, pid); + + for (; count > 0; count--) { + internal_close(low_fds[count]); + } + + return fd; +} + +uptr internal_rename(const char *oldpath, const char *newpath) { + return rename(oldpath, newpath); +} + +uptr internal_ftruncate(fd_t fd, uptr size) { + return ftruncate(fd, size); +} + +uptr internal_execve(const char *filename, char *const argv[], + char *const envp[]) { + return execve(filename, argv, envp); +} + +uptr internal_waitpid(int pid, int *status, int options) { + return waitpid(pid, status, options); +} + +// ----------------- sanitizer_common.h +bool FileExists(const char *filename) { + if (ShouldMockFailureToOpen(filename)) + return false; + struct stat st; + if (stat(filename, &st)) + return false; + // Sanity check: filename is a regular file. + return S_ISREG(st.st_mode); +} + +tid_t GetTid() { + tid_t tid; + pthread_threadid_np(nullptr, &tid); + return tid; +} + +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()); + // pthread_get_stacksize_np() returns an incorrect stack size for the main + // thread on Mavericks. See + // https://github.com/google/sanitizers/issues/261 + if ((GetMacosAlignedVersion() >= MacosVersion(10, 9)) && at_initialization && + stacksize == (1 << 19)) { + struct rlimit rl; + CHECK_EQ(getrlimit(RLIMIT_STACK, &rl), 0); + // Most often rl.rlim_cur will be the desired 8M. + if (rl.rlim_cur < kMaxThreadStackSize) { + stacksize = rl.rlim_cur; + } else { + stacksize = kMaxThreadStackSize; + } + } + void *stackaddr = pthread_get_stackaddr_np(pthread_self()); + *stack_top = (uptr)stackaddr; + *stack_bottom = *stack_top - stacksize; +} + +char **GetEnviron() { +#if !SANITIZER_IOS + char ***env_ptr = _NSGetEnviron(); + if (!env_ptr) { + Report("_NSGetEnviron() returned NULL. Please make sure __asan_init() is " + "called after libSystem_initializer().\n"); + CHECK(env_ptr); + } + char **environ = *env_ptr; +#endif + CHECK(environ); + return environ; +} + +const char *GetEnv(const char *name) { + char **env = GetEnviron(); + uptr name_len = internal_strlen(name); + while (*env != 0) { + uptr len = internal_strlen(*env); + if (len > name_len) { + const char *p = *env; + if (!internal_memcmp(p, name, name_len) && + p[name_len] == '=') { // Match. + return *env + name_len + 1; // String starting after =. + } + } + env++; + } + return 0; +} + +uptr ReadBinaryName(/*out*/char *buf, uptr buf_len) { + CHECK_LE(kMaxPathLength, buf_len); + + // On OS X the executable path is saved to the stack by dyld. Reading it + // from there is much faster than calling dladdr, especially for large + // binaries with symbols. + InternalMmapVector<char> exe_path(kMaxPathLength); + uint32_t size = exe_path.size(); + if (_NSGetExecutablePath(exe_path.data(), &size) == 0 && + realpath(exe_path.data(), buf) != 0) { + return internal_strlen(buf); + } + return 0; +} + +uptr ReadLongProcessName(/*out*/char *buf, uptr buf_len) { + return ReadBinaryName(buf, buf_len); +} + +void ReExec() { + UNIMPLEMENTED(); +} + +void CheckASLR() { + // Do nothing +} + +void CheckMPROTECT() { + // Do nothing +} + +uptr GetPageSize() { + return sysconf(_SC_PAGESIZE); +} + +extern "C" unsigned malloc_num_zones; +extern "C" malloc_zone_t **malloc_zones; +malloc_zone_t sanitizer_zone; + +// We need to make sure that sanitizer_zone is registered as malloc_zones[0]. If +// libmalloc tries to set up a different zone as malloc_zones[0], it will call +// mprotect(malloc_zones, ..., PROT_READ). This interceptor will catch that and +// make sure we are still the first (default) zone. +void MprotectMallocZones(void *addr, int prot) { + if (addr == malloc_zones && prot == PROT_READ) { + if (malloc_num_zones > 1 && malloc_zones[0] != &sanitizer_zone) { + for (unsigned i = 1; i < malloc_num_zones; i++) { + if (malloc_zones[i] == &sanitizer_zone) { + // Swap malloc_zones[0] and malloc_zones[i]. + malloc_zones[i] = malloc_zones[0]; + malloc_zones[0] = &sanitizer_zone; + break; + } + } + } + } +} + +void FutexWait(atomic_uint32_t *p, u32 cmp) { + // FIXME: implement actual blocking. + sched_yield(); +} + +void FutexWake(atomic_uint32_t *p, u32 count) {} + +u64 NanoTime() { + timeval tv; + internal_memset(&tv, 0, sizeof(tv)); + gettimeofday(&tv, 0); + return (u64)tv.tv_sec * 1000*1000*1000 + tv.tv_usec * 1000; +} + +// This needs to be called during initialization to avoid being racy. +u64 MonotonicNanoTime() { + static mach_timebase_info_data_t timebase_info; + if (timebase_info.denom == 0) mach_timebase_info(&timebase_info); + return (mach_absolute_time() * timebase_info.numer) / timebase_info.denom; +} + +uptr GetTlsSize() { + return 0; +} + +void InitTlsSize() { +} + +uptr TlsBaseAddr() { + uptr segbase = 0; +#if defined(__x86_64__) + asm("movq %%gs:0,%0" : "=r"(segbase)); +#elif defined(__i386__) + asm("movl %%gs:0,%0" : "=r"(segbase)); +#elif defined(__aarch64__) + asm("mrs %x0, tpidrro_el0" : "=r"(segbase)); + segbase &= 0x07ul; // clearing lower bits, cpu id stored there +#endif + return segbase; +} + +// The size of the tls on darwin does not appear to be well documented, +// however the vm memory map suggests that it is 1024 uptrs in size, +// with a size of 0x2000 bytes on x86_64 and 0x1000 bytes on i386. +uptr TlsSize() { +#if defined(__x86_64__) || defined(__i386__) + return 1024 * sizeof(uptr); +#else + return 0; +#endif +} + +void GetThreadStackAndTls(bool main, uptr *stk_addr, uptr *stk_size, + uptr *tls_addr, uptr *tls_size) { +#if !SANITIZER_GO + uptr stack_top, stack_bottom; + GetThreadStackTopAndBottom(main, &stack_top, &stack_bottom); + *stk_addr = stack_bottom; + *stk_size = stack_top - stack_bottom; + *tls_addr = TlsBaseAddr(); + *tls_size = TlsSize(); +#else + *stk_addr = 0; + *stk_size = 0; + *tls_addr = 0; + *tls_size = 0; +#endif +} + +void ListOfModules::init() { + clearOrInit(); + MemoryMappingLayout memory_mapping(false); + memory_mapping.DumpListOfModules(&modules_); +} + +void ListOfModules::fallbackInit() { clear(); } + +static HandleSignalMode GetHandleSignalModeImpl(int signum) { + switch (signum) { + case SIGABRT: + return common_flags()->handle_abort; + case SIGILL: + return common_flags()->handle_sigill; + case SIGTRAP: + return common_flags()->handle_sigtrap; + case SIGFPE: + return common_flags()->handle_sigfpe; + case SIGSEGV: + return common_flags()->handle_segv; + case SIGBUS: + return common_flags()->handle_sigbus; + } + return kHandleSignalNo; +} + +HandleSignalMode GetHandleSignalMode(int signum) { + // Handling fatal signals on watchOS and tvOS devices is disallowed. + if ((SANITIZER_WATCHOS || SANITIZER_TVOS) && !(SANITIZER_IOSSIM)) + return kHandleSignalNo; + HandleSignalMode result = GetHandleSignalModeImpl(signum); + if (result == kHandleSignalYes && !common_flags()->allow_user_segv_handler) + return kHandleSignalExclusive; + return result; +} + +// Offset example: +// XNU 17 -- macOS 10.13 -- iOS 11 -- tvOS 11 -- watchOS 4 +constexpr u16 GetOSMajorKernelOffset() { + if (TARGET_OS_OSX) return 4; + if (TARGET_OS_IOS || TARGET_OS_TV) return 6; + if (TARGET_OS_WATCH) return 13; +} + +using VersStr = char[64]; + +static uptr ApproximateOSVersionViaKernelVersion(VersStr vers) { + u16 kernel_major = GetDarwinKernelVersion().major; + u16 offset = GetOSMajorKernelOffset(); + CHECK_GE(kernel_major, offset); + u16 os_major = kernel_major - offset; + + const char *format = "%d.0"; + if (TARGET_OS_OSX) { + if (os_major >= 16) { // macOS 11+ + os_major -= 5; + } else { // macOS 10.15 and below + format = "10.%d"; + } + } + return internal_snprintf(vers, sizeof(VersStr), format, os_major); +} + +static void GetOSVersion(VersStr vers) { + uptr len = sizeof(VersStr); + if (SANITIZER_IOSSIM) { + const char *vers_env = GetEnv("SIMULATOR_RUNTIME_VERSION"); + if (!vers_env) { + Report("ERROR: Running in simulator but SIMULATOR_RUNTIME_VERSION env " + "var is not set.\n"); + Die(); + } + len = internal_strlcpy(vers, vers_env, len); + } else { + int res = + internal_sysctlbyname("kern.osproductversion", vers, &len, nullptr, 0); + + // XNU 17 (macOS 10.13) and below do not provide the sysctl + // `kern.osproductversion` entry (res != 0). + bool no_os_version = res != 0; + + // For launchd, sanitizer initialization runs before sysctl is setup + // (res == 0 && len != strlen(vers), vers is not a valid version). However, + // the kernel version `kern.osrelease` is available. + bool launchd = (res == 0 && internal_strlen(vers) < 3); + if (launchd) CHECK_EQ(internal_getpid(), 1); + + if (no_os_version || launchd) { + len = ApproximateOSVersionViaKernelVersion(vers); + } + } + CHECK_LT(len, sizeof(VersStr)); +} + +void ParseVersion(const char *vers, u16 *major, u16 *minor) { + // Format: <major>.<minor>[.<patch>]\0 + CHECK_GE(internal_strlen(vers), 3); + const char *p = vers; + *major = internal_simple_strtoll(p, &p, /*base=*/10); + CHECK_EQ(*p, '.'); + p += 1; + *minor = internal_simple_strtoll(p, &p, /*base=*/10); +} + +// Aligned versions example: +// macOS 10.15 -- iOS 13 -- tvOS 13 -- watchOS 6 +static void MapToMacos(u16 *major, u16 *minor) { + if (TARGET_OS_OSX) + return; + + if (TARGET_OS_IOS || TARGET_OS_TV) + *major += 2; + else if (TARGET_OS_WATCH) + *major += 9; + else + UNREACHABLE("unsupported platform"); + + if (*major >= 16) { // macOS 11+ + *major -= 5; + } else { // macOS 10.15 and below + *minor = *major; + *major = 10; + } +} + +static MacosVersion GetMacosAlignedVersionInternal() { + VersStr vers = {}; + GetOSVersion(vers); + + u16 major, minor; + ParseVersion(vers, &major, &minor); + MapToMacos(&major, &minor); + + return MacosVersion(major, minor); +} + +static_assert(sizeof(MacosVersion) == sizeof(atomic_uint32_t::Type), + "MacosVersion cache size"); +static atomic_uint32_t cached_macos_version; + +MacosVersion GetMacosAlignedVersion() { + atomic_uint32_t::Type result = + atomic_load(&cached_macos_version, memory_order_acquire); + if (!result) { + MacosVersion version = GetMacosAlignedVersionInternal(); + result = *reinterpret_cast<atomic_uint32_t::Type *>(&version); + atomic_store(&cached_macos_version, result, memory_order_release); + } + return *reinterpret_cast<MacosVersion *>(&result); +} + +DarwinKernelVersion GetDarwinKernelVersion() { + VersStr vers = {}; + uptr len = sizeof(VersStr); + int res = internal_sysctlbyname("kern.osrelease", vers, &len, nullptr, 0); + CHECK_EQ(res, 0); + CHECK_LT(len, sizeof(VersStr)); + + u16 major, minor; + ParseVersion(vers, &major, &minor); + + return DarwinKernelVersion(major, minor); +} + +uptr GetRSS() { + struct task_basic_info info; + unsigned count = TASK_BASIC_INFO_COUNT; + kern_return_t result = + task_info(mach_task_self(), TASK_BASIC_INFO, (task_info_t)&info, &count); + if (UNLIKELY(result != KERN_SUCCESS)) { + Report("Cannot get task info. Error: %d\n", result); + Die(); + } + return info.resident_size; +} + +void *internal_start_thread(void *(*func)(void *arg), void *arg) { + // Start the thread with signals blocked, otherwise it can steal user signals. + __sanitizer_sigset_t set, old; + internal_sigfillset(&set); + internal_sigprocmask(SIG_SETMASK, &set, &old); + pthread_t th; + pthread_create(&th, 0, func, arg); + internal_sigprocmask(SIG_SETMASK, &old, 0); + return th; +} + +void internal_join_thread(void *th) { pthread_join((pthread_t)th, 0); } + +#if !SANITIZER_GO +static Mutex syslog_lock; +# endif + +void WriteOneLineToSyslog(const char *s) { +#if !SANITIZER_GO + syslog_lock.CheckLocked(); + if (GetMacosAlignedVersion() >= MacosVersion(10, 12)) { + os_log_error(OS_LOG_DEFAULT, "%{public}s", s); + } else { + asl_log(nullptr, nullptr, ASL_LEVEL_ERR, "%s", s); + } +#endif +} + +// buffer to store crash report application information +static char crashreporter_info_buff[__sanitizer::kErrorMessageBufferSize] = {}; +static Mutex crashreporter_info_mutex; + +extern "C" { +// Integrate with crash reporter libraries. +#if HAVE_CRASHREPORTERCLIENT_H +CRASH_REPORTER_CLIENT_HIDDEN +struct crashreporter_annotations_t gCRAnnotations + __attribute__((section("__DATA," CRASHREPORTER_ANNOTATIONS_SECTION))) = { + CRASHREPORTER_ANNOTATIONS_VERSION, + 0, + 0, + 0, + 0, + 0, + 0, +#if CRASHREPORTER_ANNOTATIONS_VERSION > 4 + 0, +#endif +}; + +#else +// fall back to old crashreporter api +static const char *__crashreporter_info__ __attribute__((__used__)) = + &crashreporter_info_buff[0]; +asm(".desc ___crashreporter_info__, 0x10"); +#endif + +} // extern "C" + +static void CRAppendCrashLogMessage(const char *msg) { + Lock l(&crashreporter_info_mutex); + internal_strlcat(crashreporter_info_buff, msg, + sizeof(crashreporter_info_buff)); +#if HAVE_CRASHREPORTERCLIENT_H + (void)CRSetCrashLogMessage(crashreporter_info_buff); +#endif +} + +void LogMessageOnPrintf(const char *str) { + // Log all printf output to CrashLog. + if (common_flags()->abort_on_error) + CRAppendCrashLogMessage(str); +} + +void LogFullErrorReport(const char *buffer) { +#if !SANITIZER_GO + // Log with os_trace. This will make it into the crash log. +#if SANITIZER_OS_TRACE + if (GetMacosAlignedVersion() >= MacosVersion(10, 10)) { + // os_trace requires the message (format parameter) to be a string literal. + if (internal_strncmp(SanitizerToolName, "AddressSanitizer", + sizeof("AddressSanitizer") - 1) == 0) + os_trace("Address Sanitizer reported a failure."); + else if (internal_strncmp(SanitizerToolName, "UndefinedBehaviorSanitizer", + sizeof("UndefinedBehaviorSanitizer") - 1) == 0) + os_trace("Undefined Behavior Sanitizer reported a failure."); + else if (internal_strncmp(SanitizerToolName, "ThreadSanitizer", + sizeof("ThreadSanitizer") - 1) == 0) + os_trace("Thread Sanitizer reported a failure."); + else + os_trace("Sanitizer tool reported a failure."); + + if (common_flags()->log_to_syslog) + os_trace("Consult syslog for more information."); + } +#endif + + // Log to syslog. + // The logging on OS X may call pthread_create so we need the threading + // environment to be fully initialized. Also, this should never be called when + // holding the thread registry lock since that may result in a deadlock. If + // the reporting thread holds the thread registry mutex, and asl_log waits + // for GCD to dispatch a new thread, the process will deadlock, because the + // pthread_create wrapper needs to acquire the lock as well. + Lock l(&syslog_lock); + if (common_flags()->log_to_syslog) + WriteToSyslog(buffer); + + // The report is added to CrashLog as part of logging all of Printf output. +#endif +} + +SignalContext::WriteFlag SignalContext::GetWriteFlag() const { +#if defined(__x86_64__) || defined(__i386__) + ucontext_t *ucontext = static_cast<ucontext_t*>(context); + return ucontext->uc_mcontext->__es.__err & 2 /*T_PF_WRITE*/ ? Write : Read; +#else + return Unknown; +#endif +} + +bool SignalContext::IsTrueFaultingAddress() const { + auto si = static_cast<const siginfo_t *>(siginfo); + // "Real" SIGSEGV codes (e.g., SEGV_MAPERR, SEGV_MAPERR) are non-zero. + return si->si_signo == SIGSEGV && si->si_code != 0; +} + +#if defined(__aarch64__) && defined(arm_thread_state64_get_sp) + #define AARCH64_GET_REG(r) \ + (uptr)ptrauth_strip( \ + (void *)arm_thread_state64_get_##r(ucontext->uc_mcontext->__ss), 0) +#else + #define AARCH64_GET_REG(r) (uptr)ucontext->uc_mcontext->__ss.__##r +#endif + +static void GetPcSpBp(void *context, uptr *pc, uptr *sp, uptr *bp) { + ucontext_t *ucontext = (ucontext_t*)context; +# if defined(__aarch64__) + *pc = AARCH64_GET_REG(pc); +# if defined(__IPHONE_8_0) && __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_8_0 + *bp = AARCH64_GET_REG(fp); +# else + *bp = AARCH64_GET_REG(lr); +# endif + *sp = AARCH64_GET_REG(sp); +# elif defined(__x86_64__) + *pc = ucontext->uc_mcontext->__ss.__rip; + *bp = ucontext->uc_mcontext->__ss.__rbp; + *sp = ucontext->uc_mcontext->__ss.__rsp; +# elif defined(__arm__) + *pc = ucontext->uc_mcontext->__ss.__pc; + *bp = ucontext->uc_mcontext->__ss.__r[7]; + *sp = ucontext->uc_mcontext->__ss.__sp; +# elif defined(__i386__) + *pc = ucontext->uc_mcontext->__ss.__eip; + *bp = ucontext->uc_mcontext->__ss.__ebp; + *sp = ucontext->uc_mcontext->__ss.__esp; +# else +# error "Unknown architecture" +# endif +} + +void SignalContext::InitPcSpBp() { + addr = (uptr)ptrauth_strip((void *)addr, 0); + GetPcSpBp(context, &pc, &sp, &bp); +} + +// ASan/TSan use mmap in a way that creates “deallocation gaps” which triggers +// EXC_GUARD exceptions on macOS 10.15+ (XNU 19.0+). +static void DisableMmapExcGuardExceptions() { + using task_exc_guard_behavior_t = uint32_t; + using task_set_exc_guard_behavior_t = + kern_return_t(task_t task, task_exc_guard_behavior_t behavior); + auto *set_behavior = (task_set_exc_guard_behavior_t *)dlsym( + RTLD_DEFAULT, "task_set_exc_guard_behavior"); + if (set_behavior == nullptr) return; + const task_exc_guard_behavior_t task_exc_guard_none = 0; + set_behavior(mach_task_self(), task_exc_guard_none); +} + +void InitializePlatformEarly() { + // Only use xnu_fast_mmap when on x86_64 and the kernel supports it. + use_xnu_fast_mmap = +#if defined(__x86_64__) + GetDarwinKernelVersion() >= DarwinKernelVersion(17, 5); +#else + false; +#endif + if (GetDarwinKernelVersion() >= DarwinKernelVersion(19, 0)) + DisableMmapExcGuardExceptions(); +} + +#if !SANITIZER_GO +static const char kDyldInsertLibraries[] = "DYLD_INSERT_LIBRARIES"; +LowLevelAllocator allocator_for_env; + +// Change the value of the env var |name|, leaking the original value. +// If |name_value| is NULL, the variable is deleted from the environment, +// otherwise the corresponding "NAME=value" string is replaced with +// |name_value|. +void LeakyResetEnv(const char *name, const char *name_value) { + char **env = GetEnviron(); + uptr name_len = internal_strlen(name); + while (*env != 0) { + uptr len = internal_strlen(*env); + if (len > name_len) { + const char *p = *env; + if (!internal_memcmp(p, name, name_len) && p[name_len] == '=') { + // Match. + if (name_value) { + // Replace the old value with the new one. + *env = const_cast<char*>(name_value); + } else { + // Shift the subsequent pointers back. + char **del = env; + do { + del[0] = del[1]; + } while (*del++); + } + } + } + env++; + } +} + +SANITIZER_WEAK_CXX_DEFAULT_IMPL +bool ReexecDisabled() { + return false; +} + +static bool DyldNeedsEnvVariable() { + // If running on OS X 10.11+ or iOS 9.0+, dyld will interpose even if + // DYLD_INSERT_LIBRARIES is not set. + return GetMacosAlignedVersion() < MacosVersion(10, 11); +} + +void MaybeReexec() { + // FIXME: This should really live in some "InitializePlatform" method. + MonotonicNanoTime(); + + if (ReexecDisabled()) return; + + // Make sure the dynamic runtime library is preloaded so that the + // wrappers work. If it is not, set DYLD_INSERT_LIBRARIES and re-exec + // ourselves. + Dl_info info; + RAW_CHECK(dladdr((void*)((uptr)&__sanitizer_report_error_summary), &info)); + char *dyld_insert_libraries = + const_cast<char*>(GetEnv(kDyldInsertLibraries)); + uptr old_env_len = dyld_insert_libraries ? + internal_strlen(dyld_insert_libraries) : 0; + uptr fname_len = internal_strlen(info.dli_fname); + const char *dylib_name = StripModuleName(info.dli_fname); + uptr dylib_name_len = internal_strlen(dylib_name); + + bool lib_is_in_env = dyld_insert_libraries && + internal_strstr(dyld_insert_libraries, dylib_name); + if (DyldNeedsEnvVariable() && !lib_is_in_env) { + // DYLD_INSERT_LIBRARIES is not set or does not contain the runtime + // library. + InternalMmapVector<char> program_name(1024); + uint32_t buf_size = program_name.size(); + _NSGetExecutablePath(program_name.data(), &buf_size); + char *new_env = const_cast<char*>(info.dli_fname); + if (dyld_insert_libraries) { + // Append the runtime dylib name to the existing value of + // DYLD_INSERT_LIBRARIES. + new_env = (char*)allocator_for_env.Allocate(old_env_len + fname_len + 2); + internal_strncpy(new_env, dyld_insert_libraries, old_env_len); + new_env[old_env_len] = ':'; + // Copy fname_len and add a trailing zero. + internal_strncpy(new_env + old_env_len + 1, info.dli_fname, + fname_len + 1); + // Ok to use setenv() since the wrappers don't depend on the value of + // asan_inited. + setenv(kDyldInsertLibraries, new_env, /*overwrite*/1); + } else { + // Set DYLD_INSERT_LIBRARIES equal to the runtime dylib name. + setenv(kDyldInsertLibraries, info.dli_fname, /*overwrite*/0); + } + VReport(1, "exec()-ing the program with\n"); + VReport(1, "%s=%s\n", kDyldInsertLibraries, new_env); + VReport(1, "to enable wrappers.\n"); + execv(program_name.data(), *_NSGetArgv()); + + // We get here only if execv() failed. + Report("ERROR: The process is launched without DYLD_INSERT_LIBRARIES, " + "which is required for the sanitizer to work. We tried to set the " + "environment variable and re-execute itself, but execv() failed, " + "possibly because of sandbox restrictions. Make sure to launch the " + "executable with:\n%s=%s\n", kDyldInsertLibraries, new_env); + RAW_CHECK("execv failed" && 0); + } + + // Verify that interceptors really work. We'll use dlsym to locate + // "pthread_create", if interceptors are working, it should really point to + // "wrap_pthread_create" within our own dylib. + Dl_info info_pthread_create; + void *dlopen_addr = dlsym(RTLD_DEFAULT, "pthread_create"); + RAW_CHECK(dladdr(dlopen_addr, &info_pthread_create)); + if (internal_strcmp(info.dli_fname, info_pthread_create.dli_fname) != 0) { + Report( + "ERROR: Interceptors are not working. This may be because %s is " + "loaded too late (e.g. via dlopen). Please launch the executable " + "with:\n%s=%s\n", + SanitizerToolName, kDyldInsertLibraries, info.dli_fname); + RAW_CHECK("interceptors not installed" && 0); + } + + if (!lib_is_in_env) + return; + + if (!common_flags()->strip_env) + return; + + // DYLD_INSERT_LIBRARIES is set and contains the runtime library. Let's remove + // the dylib from the environment variable, because interceptors are installed + // and we don't want our children to inherit the variable. + + uptr env_name_len = internal_strlen(kDyldInsertLibraries); + // Allocate memory to hold the previous env var name, its value, the '=' + // sign and the '\0' char. + char *new_env = (char*)allocator_for_env.Allocate( + old_env_len + 2 + env_name_len); + RAW_CHECK(new_env); + internal_memset(new_env, '\0', old_env_len + 2 + env_name_len); + internal_strncpy(new_env, kDyldInsertLibraries, env_name_len); + new_env[env_name_len] = '='; + char *new_env_pos = new_env + env_name_len + 1; + + // Iterate over colon-separated pieces of |dyld_insert_libraries|. + char *piece_start = dyld_insert_libraries; + char *piece_end = NULL; + char *old_env_end = dyld_insert_libraries + old_env_len; + do { + if (piece_start[0] == ':') piece_start++; + piece_end = internal_strchr(piece_start, ':'); + if (!piece_end) piece_end = dyld_insert_libraries + old_env_len; + if ((uptr)(piece_start - dyld_insert_libraries) > old_env_len) break; + uptr piece_len = piece_end - piece_start; + + char *filename_start = + (char *)internal_memrchr(piece_start, '/', piece_len); + uptr filename_len = piece_len; + if (filename_start) { + filename_start += 1; + filename_len = piece_len - (filename_start - piece_start); + } else { + filename_start = piece_start; + } + + // If the current piece isn't the runtime library name, + // append it to new_env. + if ((dylib_name_len != filename_len) || + (internal_memcmp(filename_start, dylib_name, dylib_name_len) != 0)) { + if (new_env_pos != new_env + env_name_len + 1) { + new_env_pos[0] = ':'; + new_env_pos++; + } + internal_strncpy(new_env_pos, piece_start, piece_len); + new_env_pos += piece_len; + } + // Move on to the next piece. + piece_start = piece_end; + } while (piece_start < old_env_end); + + // Can't use setenv() here, because it requires the allocator to be + // initialized. + // FIXME: instead of filtering DYLD_INSERT_LIBRARIES here, do it in + // a separate function called after InitializeAllocator(). + if (new_env_pos == new_env + env_name_len + 1) new_env = NULL; + LeakyResetEnv(kDyldInsertLibraries, new_env); +} +#endif // SANITIZER_GO + +char **GetArgv() { + return *_NSGetArgv(); +} + +#if SANITIZER_IOS && !SANITIZER_IOSSIM +// The task_vm_info struct is normally provided by the macOS SDK, but we need +// fields only available in 10.12+. Declare the struct manually to be able to +// build against older SDKs. +struct __sanitizer_task_vm_info { + mach_vm_size_t virtual_size; + integer_t region_count; + integer_t page_size; + mach_vm_size_t resident_size; + mach_vm_size_t resident_size_peak; + mach_vm_size_t device; + mach_vm_size_t device_peak; + mach_vm_size_t internal; + mach_vm_size_t internal_peak; + mach_vm_size_t external; + mach_vm_size_t external_peak; + mach_vm_size_t reusable; + mach_vm_size_t reusable_peak; + mach_vm_size_t purgeable_volatile_pmap; + mach_vm_size_t purgeable_volatile_resident; + mach_vm_size_t purgeable_volatile_virtual; + mach_vm_size_t compressed; + mach_vm_size_t compressed_peak; + mach_vm_size_t compressed_lifetime; + mach_vm_size_t phys_footprint; + mach_vm_address_t min_address; + mach_vm_address_t max_address; +}; +#define __SANITIZER_TASK_VM_INFO_COUNT ((mach_msg_type_number_t) \ + (sizeof(__sanitizer_task_vm_info) / sizeof(natural_t))) + +static uptr GetTaskInfoMaxAddress() { + __sanitizer_task_vm_info vm_info = {} /* zero initialize */; + mach_msg_type_number_t count = __SANITIZER_TASK_VM_INFO_COUNT; + int err = task_info(mach_task_self(), TASK_VM_INFO, (int *)&vm_info, &count); + return err ? 0 : vm_info.max_address; +} + +uptr GetMaxUserVirtualAddress() { + static uptr max_vm = GetTaskInfoMaxAddress(); + if (max_vm != 0) { + const uptr ret_value = max_vm - 1; + CHECK_LE(ret_value, SANITIZER_MMAP_RANGE_SIZE); + return ret_value; + } + + // xnu cannot provide vm address limit +# if SANITIZER_WORDSIZE == 32 + constexpr uptr fallback_max_vm = 0xffe00000 - 1; +# else + constexpr uptr fallback_max_vm = 0x200000000 - 1; +# endif + static_assert(fallback_max_vm <= SANITIZER_MMAP_RANGE_SIZE, + "Max virtual address must be less than mmap range size."); + return fallback_max_vm; +} + +#else // !SANITIZER_IOS + +uptr GetMaxUserVirtualAddress() { +# if SANITIZER_WORDSIZE == 64 + constexpr uptr max_vm = (1ULL << 47) - 1; // 0x00007fffffffffffUL; +# else // SANITIZER_WORDSIZE == 32 + static_assert(SANITIZER_WORDSIZE == 32, "Wrong wordsize"); + constexpr uptr max_vm = (1ULL << 32) - 1; // 0xffffffff; +# endif + static_assert(max_vm <= SANITIZER_MMAP_RANGE_SIZE, + "Max virtual address must be less than mmap range size."); + return max_vm; +} +#endif + +uptr GetMaxVirtualAddress() { + return GetMaxUserVirtualAddress(); +} + +uptr MapDynamicShadow(uptr shadow_size_bytes, uptr shadow_scale, + uptr min_shadow_base_alignment, uptr &high_mem_end) { + const uptr granularity = GetMmapGranularity(); + const uptr alignment = + Max<uptr>(granularity << shadow_scale, 1ULL << min_shadow_base_alignment); + const uptr left_padding = + Max<uptr>(granularity, 1ULL << min_shadow_base_alignment); + + uptr space_size = shadow_size_bytes + left_padding; + + uptr largest_gap_found = 0; + uptr max_occupied_addr = 0; + VReport(2, "FindDynamicShadowStart, space_size = %p\n", (void *)space_size); + uptr shadow_start = + FindAvailableMemoryRange(space_size, alignment, granularity, + &largest_gap_found, &max_occupied_addr); + // If the shadow doesn't fit, restrict the address space to make it fit. + if (shadow_start == 0) { + VReport( + 2, + "Shadow doesn't fit, largest_gap_found = %p, max_occupied_addr = %p\n", + (void *)largest_gap_found, (void *)max_occupied_addr); + uptr new_max_vm = RoundDownTo(largest_gap_found << shadow_scale, alignment); + if (new_max_vm < max_occupied_addr) { + Report("Unable to find a memory range for dynamic shadow.\n"); + Report( + "space_size = %p, largest_gap_found = %p, max_occupied_addr = %p, " + "new_max_vm = %p\n", + (void *)space_size, (void *)largest_gap_found, + (void *)max_occupied_addr, (void *)new_max_vm); + CHECK(0 && "cannot place shadow"); + } + RestrictMemoryToMaxAddress(new_max_vm); + high_mem_end = new_max_vm - 1; + space_size = (high_mem_end >> shadow_scale) + left_padding; + VReport(2, "FindDynamicShadowStart, space_size = %p\n", (void *)space_size); + shadow_start = FindAvailableMemoryRange(space_size, alignment, granularity, + nullptr, nullptr); + if (shadow_start == 0) { + Report("Unable to find a memory range after restricting VM.\n"); + CHECK(0 && "cannot place shadow after restricting vm"); + } + } + CHECK_NE((uptr)0, shadow_start); + CHECK(IsAligned(shadow_start, alignment)); + return shadow_start; +} + +uptr MapDynamicShadowAndAliases(uptr shadow_size, uptr alias_size, + uptr num_aliases, uptr ring_buffer_size) { + CHECK(false && "HWASan aliasing is unimplemented on Mac"); + return 0; +} + +uptr FindAvailableMemoryRange(uptr size, uptr alignment, uptr left_padding, + uptr *largest_gap_found, + uptr *max_occupied_addr) { + typedef vm_region_submap_short_info_data_64_t RegionInfo; + enum { kRegionInfoSize = VM_REGION_SUBMAP_SHORT_INFO_COUNT_64 }; + // Start searching for available memory region past PAGEZERO, which is + // 4KB on 32-bit and 4GB on 64-bit. + mach_vm_address_t start_address = + (SANITIZER_WORDSIZE == 32) ? 0x000000001000 : 0x000100000000; + + mach_vm_address_t address = start_address; + mach_vm_address_t free_begin = start_address; + kern_return_t kr = KERN_SUCCESS; + if (largest_gap_found) *largest_gap_found = 0; + if (max_occupied_addr) *max_occupied_addr = 0; + while (kr == KERN_SUCCESS) { + mach_vm_size_t vmsize = 0; + natural_t depth = 0; + RegionInfo vminfo; + mach_msg_type_number_t count = kRegionInfoSize; + kr = mach_vm_region_recurse(mach_task_self(), &address, &vmsize, &depth, + (vm_region_info_t)&vminfo, &count); + if (kr == KERN_INVALID_ADDRESS) { + // No more regions beyond "address", consider the gap at the end of VM. + address = GetMaxVirtualAddress() + 1; + vmsize = 0; + } else { + if (max_occupied_addr) *max_occupied_addr = address + vmsize; + } + if (free_begin != address) { + // We found a free region [free_begin..address-1]. + uptr gap_start = RoundUpTo((uptr)free_begin + left_padding, alignment); + uptr gap_end = RoundDownTo((uptr)address, alignment); + uptr gap_size = gap_end > gap_start ? gap_end - gap_start : 0; + if (size < gap_size) { + return gap_start; + } + + if (largest_gap_found && *largest_gap_found < gap_size) { + *largest_gap_found = gap_size; + } + } + // Move to the next region. + address += vmsize; + free_begin = address; + } + + // We looked at all free regions and could not find one large enough. + return 0; +} + +// FIXME implement on this platform. +void GetMemoryProfile(fill_profile_f cb, uptr *stats) {} + +void SignalContext::DumpAllRegisters(void *context) { + Report("Register values:\n"); + + ucontext_t *ucontext = (ucontext_t*)context; +# define DUMPREG64(r) \ + Printf("%s = 0x%016llx ", #r, ucontext->uc_mcontext->__ss.__ ## r); +# define DUMPREGA64(r) \ + Printf(" %s = 0x%016lx ", #r, AARCH64_GET_REG(r)); +# define DUMPREG32(r) \ + Printf("%s = 0x%08x ", #r, ucontext->uc_mcontext->__ss.__ ## r); +# define DUMPREG_(r) Printf(" "); DUMPREG(r); +# define DUMPREG__(r) Printf(" "); DUMPREG(r); +# define DUMPREG___(r) Printf(" "); DUMPREG(r); + +# if defined(__x86_64__) +# define DUMPREG(r) DUMPREG64(r) + DUMPREG(rax); DUMPREG(rbx); DUMPREG(rcx); DUMPREG(rdx); Printf("\n"); + DUMPREG(rdi); DUMPREG(rsi); DUMPREG(rbp); DUMPREG(rsp); Printf("\n"); + DUMPREG_(r8); DUMPREG_(r9); DUMPREG(r10); DUMPREG(r11); Printf("\n"); + DUMPREG(r12); DUMPREG(r13); DUMPREG(r14); DUMPREG(r15); Printf("\n"); +# elif defined(__i386__) +# define DUMPREG(r) DUMPREG32(r) + DUMPREG(eax); DUMPREG(ebx); DUMPREG(ecx); DUMPREG(edx); Printf("\n"); + DUMPREG(edi); DUMPREG(esi); DUMPREG(ebp); DUMPREG(esp); Printf("\n"); +# elif defined(__aarch64__) +# define DUMPREG(r) DUMPREG64(r) + DUMPREG_(x[0]); DUMPREG_(x[1]); DUMPREG_(x[2]); DUMPREG_(x[3]); Printf("\n"); + DUMPREG_(x[4]); DUMPREG_(x[5]); DUMPREG_(x[6]); DUMPREG_(x[7]); Printf("\n"); + DUMPREG_(x[8]); DUMPREG_(x[9]); DUMPREG(x[10]); DUMPREG(x[11]); Printf("\n"); + DUMPREG(x[12]); DUMPREG(x[13]); DUMPREG(x[14]); DUMPREG(x[15]); Printf("\n"); + DUMPREG(x[16]); DUMPREG(x[17]); DUMPREG(x[18]); DUMPREG(x[19]); Printf("\n"); + DUMPREG(x[20]); DUMPREG(x[21]); DUMPREG(x[22]); DUMPREG(x[23]); Printf("\n"); + DUMPREG(x[24]); DUMPREG(x[25]); DUMPREG(x[26]); DUMPREG(x[27]); Printf("\n"); + DUMPREG(x[28]); DUMPREGA64(fp); DUMPREGA64(lr); DUMPREGA64(sp); Printf("\n"); +# elif defined(__arm__) +# define DUMPREG(r) DUMPREG32(r) + DUMPREG_(r[0]); DUMPREG_(r[1]); DUMPREG_(r[2]); DUMPREG_(r[3]); Printf("\n"); + DUMPREG_(r[4]); DUMPREG_(r[5]); DUMPREG_(r[6]); DUMPREG_(r[7]); Printf("\n"); + DUMPREG_(r[8]); DUMPREG_(r[9]); DUMPREG(r[10]); DUMPREG(r[11]); Printf("\n"); + DUMPREG(r[12]); DUMPREG___(sp); DUMPREG___(lr); DUMPREG___(pc); Printf("\n"); +# else +# error "Unknown architecture" +# endif + +# undef DUMPREG64 +# undef DUMPREG32 +# undef DUMPREG_ +# undef DUMPREG__ +# undef DUMPREG___ +# undef DUMPREG +} + +static inline bool CompareBaseAddress(const LoadedModule &a, + const LoadedModule &b) { + return a.base_address() < b.base_address(); +} + +void FormatUUID(char *out, uptr size, const u8 *uuid) { + internal_snprintf(out, size, + "<%02X%02X%02X%02X-%02X%02X-%02X%02X-%02X%02X-" + "%02X%02X%02X%02X%02X%02X>", + uuid[0], uuid[1], uuid[2], uuid[3], uuid[4], uuid[5], + uuid[6], uuid[7], uuid[8], uuid[9], uuid[10], uuid[11], + uuid[12], uuid[13], uuid[14], uuid[15]); +} + +void DumpProcessMap() { + Printf("Process module map:\n"); + MemoryMappingLayout memory_mapping(false); + InternalMmapVector<LoadedModule> modules; + modules.reserve(128); + memory_mapping.DumpListOfModules(&modules); + Sort(modules.data(), modules.size(), CompareBaseAddress); + for (uptr i = 0; i < modules.size(); ++i) { + char uuid_str[128]; + FormatUUID(uuid_str, sizeof(uuid_str), modules[i].uuid()); + Printf("0x%zx-0x%zx %s (%s) %s\n", modules[i].base_address(), + modules[i].max_executable_address(), modules[i].full_name(), + ModuleArchToString(modules[i].arch()), uuid_str); + } + Printf("End of module map.\n"); +} + +void CheckNoDeepBind(const char *filename, int flag) { + // Do nothing. +} + +bool GetRandom(void *buffer, uptr length, bool blocking) { + if (!buffer || !length || length > 256) + return false; + // arc4random never fails. + REAL(arc4random_buf)(buffer, length); + return true; +} + +u32 GetNumberOfCPUs() { + return (u32)sysconf(_SC_NPROCESSORS_ONLN); +} + +void InitializePlatformCommonFlags(CommonFlags *cf) {} + +} // namespace __sanitizer + +#endif // SANITIZER_MAC diff --git a/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_mac.h b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_mac.h new file mode 100644 index 0000000000..0b6af5a3c0 --- /dev/null +++ b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_mac.h @@ -0,0 +1,68 @@ +//===-- sanitizer_mac.h -----------------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file is shared between various sanitizers' runtime libraries and +// provides definitions for OSX-specific functions. +//===----------------------------------------------------------------------===// +#ifndef SANITIZER_MAC_H +#define SANITIZER_MAC_H + +#include "sanitizer_common.h" +#include "sanitizer_platform.h" +#if SANITIZER_MAC +#include "sanitizer_posix.h" + +namespace __sanitizer { + +struct MemoryMappingLayoutData { + int current_image; + u32 current_magic; + u32 current_filetype; + ModuleArch current_arch; + u8 current_uuid[kModuleUUIDSize]; + int current_load_cmd_count; + const char *current_load_cmd_addr; + bool current_instrumented; +}; + +template <typename VersionType> +struct VersionBase { + u16 major; + u16 minor; + + VersionBase(u16 major, u16 minor) : major(major), minor(minor) {} + + bool operator==(const VersionType &other) const { + return major == other.major && minor == other.minor; + } + bool operator>=(const VersionType &other) const { + return major > other.major || + (major == other.major && minor >= other.minor); + } + bool operator<(const VersionType &other) const { return !(*this >= other); } +}; + +struct MacosVersion : VersionBase<MacosVersion> { + MacosVersion(u16 major, u16 minor) : VersionBase(major, minor) {} +}; + +struct DarwinKernelVersion : VersionBase<DarwinKernelVersion> { + DarwinKernelVersion(u16 major, u16 minor) : VersionBase(major, minor) {} +}; + +MacosVersion GetMacosAlignedVersion(); +DarwinKernelVersion GetDarwinKernelVersion(); + +char **GetEnviron(); + +void RestrictMemoryToMaxAddress(uptr max_address); + +} // namespace __sanitizer + +#endif // SANITIZER_MAC +#endif // SANITIZER_MAC_H diff --git a/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_mac_libcdep.cpp b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_mac_libcdep.cpp new file mode 100644 index 0000000000..ac7e328946 --- /dev/null +++ b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_mac_libcdep.cpp @@ -0,0 +1,29 @@ +//===-- sanitizer_mac_libcdep.cpp -----------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file is shared between various sanitizers' runtime libraries and +// implements OSX-specific functions. +//===----------------------------------------------------------------------===// + +#include "sanitizer_platform.h" +#if SANITIZER_MAC +#include "sanitizer_mac.h" + +#include <sys/mman.h> + +namespace __sanitizer { + +void RestrictMemoryToMaxAddress(uptr max_address) { + uptr size_to_mmap = GetMaxUserVirtualAddress() + 1 - max_address; + void *res = MmapFixedNoAccess(max_address, size_to_mmap, "high gap"); + CHECK(res != MAP_FAILED); +} + +} // namespace __sanitizer + +#endif // SANITIZER_MAC diff --git a/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_malloc_mac.inc b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_malloc_mac.inc new file mode 100644 index 0000000000..764e2cef5e --- /dev/null +++ b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_malloc_mac.inc @@ -0,0 +1,414 @@ +//===-- sanitizer_malloc_mac.inc --------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file contains Mac-specific malloc interceptors and a custom zone +// implementation, which together replace the system allocator. +// +//===----------------------------------------------------------------------===// + +#include "sanitizer_common/sanitizer_platform.h" +#if !SANITIZER_MAC +#error "This file should only be compiled on Darwin." +#endif + +#include <AvailabilityMacros.h> +#include <CoreFoundation/CFBase.h> +#include <dlfcn.h> +#include <malloc/malloc.h> +#include <sys/mman.h> + +#include "interception/interception.h" +#include "sanitizer_common/sanitizer_allocator_dlsym.h" +#include "sanitizer_common/sanitizer_mac.h" + +// Similar code is used in Google Perftools, +// https://github.com/gperftools/gperftools. + +namespace __sanitizer { + +extern malloc_zone_t sanitizer_zone; + +struct sanitizer_malloc_introspection_t : public malloc_introspection_t { + // IMPORTANT: Do not change the order, alignment, or types of these fields to + // maintain binary compatibility. You should only add fields to this struct. + + // Used to track changes to the allocator that will affect + // zone enumeration. + u64 allocator_enumeration_version; + uptr allocator_ptr; + uptr allocator_size; +}; + +u64 GetMallocZoneAllocatorEnumerationVersion() { + // This represents the current allocator ABI version. + // This field should be incremented every time the Allocator + // ABI changes in a way that breaks allocator enumeration. + return 0; +} + +} // namespace __sanitizer + +INTERCEPTOR(malloc_zone_t *, malloc_create_zone, + vm_size_t start_size, unsigned zone_flags) { + COMMON_MALLOC_ENTER(); + uptr page_size = GetPageSizeCached(); + uptr allocated_size = RoundUpTo(sizeof(sanitizer_zone), page_size); + COMMON_MALLOC_MEMALIGN(page_size, allocated_size); + malloc_zone_t *new_zone = (malloc_zone_t *)p; + internal_memcpy(new_zone, &sanitizer_zone, sizeof(sanitizer_zone)); + new_zone->zone_name = NULL; // The name will be changed anyway. + // Prevent the client app from overwriting the zone contents. + // Library functions that need to modify the zone will set PROT_WRITE on it. + // This matches the behavior of malloc_create_zone() on OSX 10.7 and higher. + mprotect(new_zone, allocated_size, PROT_READ); + // We're explicitly *NOT* registering the zone. + return new_zone; +} + +INTERCEPTOR(void, malloc_destroy_zone, malloc_zone_t *zone) { + COMMON_MALLOC_ENTER(); + // We don't need to do anything here. We're not registering new zones, so we + // don't to unregister. Just un-mprotect and free() the zone. + uptr page_size = GetPageSizeCached(); + uptr allocated_size = RoundUpTo(sizeof(sanitizer_zone), page_size); + mprotect(zone, allocated_size, PROT_READ | PROT_WRITE); + if (zone->zone_name) { + COMMON_MALLOC_FREE((void *)zone->zone_name); + } + COMMON_MALLOC_FREE(zone); +} + +INTERCEPTOR(malloc_zone_t *, malloc_default_zone, void) { + COMMON_MALLOC_ENTER(); + return &sanitizer_zone; +} + +INTERCEPTOR(malloc_zone_t *, malloc_zone_from_ptr, const void *ptr) { + COMMON_MALLOC_ENTER(); + size_t size = sanitizer_zone.size(&sanitizer_zone, ptr); + if (size) { // Claimed by sanitizer zone? + return &sanitizer_zone; + } + return REAL(malloc_zone_from_ptr)(ptr); +} + +INTERCEPTOR(malloc_zone_t *, malloc_default_purgeable_zone, void) { + // FIXME: ASan should support purgeable allocations. + // https://github.com/google/sanitizers/issues/139 + COMMON_MALLOC_ENTER(); + return &sanitizer_zone; +} + +INTERCEPTOR(void, malloc_make_purgeable, void *ptr) { + // FIXME: ASan should support purgeable allocations. Ignoring them is fine + // for now. + COMMON_MALLOC_ENTER(); +} + +INTERCEPTOR(int, malloc_make_nonpurgeable, void *ptr) { + // FIXME: ASan should support purgeable allocations. Ignoring them is fine + // for now. + COMMON_MALLOC_ENTER(); + // Must return 0 if the contents were not purged since the last call to + // malloc_make_purgeable(). + return 0; +} + +INTERCEPTOR(void, malloc_set_zone_name, malloc_zone_t *zone, const char *name) { + COMMON_MALLOC_ENTER(); + InternalScopedString new_name; + if (name && zone->introspect == sanitizer_zone.introspect) { + new_name.append(COMMON_MALLOC_ZONE_NAME "-%s", name); + name = new_name.data(); + } + + // Call the system malloc's implementation for both external and our zones, + // since that appropriately changes VM region protections on the zone. + REAL(malloc_set_zone_name)(zone, name); +} + +INTERCEPTOR(void *, malloc, size_t size) { + COMMON_MALLOC_ENTER(); + COMMON_MALLOC_MALLOC(size); + return p; +} + +INTERCEPTOR(void, free, void *ptr) { + COMMON_MALLOC_ENTER(); + if (!ptr) return; + COMMON_MALLOC_FREE(ptr); +} + +INTERCEPTOR(void *, realloc, void *ptr, size_t size) { + COMMON_MALLOC_ENTER(); + COMMON_MALLOC_REALLOC(ptr, size); + return p; +} + +INTERCEPTOR(void *, calloc, size_t nmemb, size_t size) { + COMMON_MALLOC_ENTER(); + COMMON_MALLOC_CALLOC(nmemb, size); + return p; +} + +INTERCEPTOR(void *, valloc, size_t size) { + COMMON_MALLOC_ENTER(); + COMMON_MALLOC_VALLOC(size); + return p; +} + +INTERCEPTOR(size_t, malloc_good_size, size_t size) { + COMMON_MALLOC_ENTER(); + return sanitizer_zone.introspect->good_size(&sanitizer_zone, size); +} + +INTERCEPTOR(int, posix_memalign, void **memptr, size_t alignment, size_t size) { + COMMON_MALLOC_ENTER(); + CHECK(memptr); + COMMON_MALLOC_POSIX_MEMALIGN(memptr, alignment, size); + return res; +} + +namespace { + +// TODO(glider): the __sanitizer_mz_* functions should be united with the Linux +// wrappers, as they are basically copied from there. +extern "C" +SANITIZER_INTERFACE_ATTRIBUTE +size_t __sanitizer_mz_size(malloc_zone_t* zone, const void* ptr) { + COMMON_MALLOC_SIZE(ptr); + return size; +} + +extern "C" +SANITIZER_INTERFACE_ATTRIBUTE +void *__sanitizer_mz_malloc(malloc_zone_t *zone, uptr size) { + COMMON_MALLOC_ENTER(); + COMMON_MALLOC_MALLOC(size); + return p; +} + +struct DlsymAlloc : public DlSymAllocator<DlsymAlloc> { + static bool UseImpl() { return !COMMON_MALLOC_SANITIZER_INITIALIZED; } +}; + +extern "C" +SANITIZER_INTERFACE_ATTRIBUTE +void *__sanitizer_mz_calloc(malloc_zone_t *zone, size_t nmemb, size_t size) { + if (DlsymAlloc::Use()) + return DlsymAlloc::Callocate(nmemb, size); + COMMON_MALLOC_CALLOC(nmemb, size); + return p; +} + +extern "C" +SANITIZER_INTERFACE_ATTRIBUTE +void *__sanitizer_mz_valloc(malloc_zone_t *zone, size_t size) { + COMMON_MALLOC_ENTER(); + COMMON_MALLOC_VALLOC(size); + return p; +} + +// TODO(glider): the allocation callbacks need to be refactored. +extern "C" +SANITIZER_INTERFACE_ATTRIBUTE +void __sanitizer_mz_free(malloc_zone_t *zone, void *ptr) { + if (!ptr) return; + if (DlsymAlloc::PointerIsMine(ptr)) + return DlsymAlloc::Free(ptr); + COMMON_MALLOC_FREE(ptr); +} + +#define GET_ZONE_FOR_PTR(ptr) \ + malloc_zone_t *zone_ptr = WRAP(malloc_zone_from_ptr)(ptr); \ + const char *zone_name = (zone_ptr == 0) ? 0 : zone_ptr->zone_name + +extern "C" +SANITIZER_INTERFACE_ATTRIBUTE +void *__sanitizer_mz_realloc(malloc_zone_t *zone, void *ptr, size_t new_size) { + if (!ptr) { + COMMON_MALLOC_MALLOC(new_size); + return p; + } else { + COMMON_MALLOC_SIZE(ptr); + if (size) { + COMMON_MALLOC_REALLOC(ptr, new_size); + return p; + } else { + // We can't recover from reallocating an unknown address, because + // this would require reading at most |new_size| bytes from + // potentially unaccessible memory. + GET_ZONE_FOR_PTR(ptr); + COMMON_MALLOC_REPORT_UNKNOWN_REALLOC(ptr, zone_ptr, zone_name); + return nullptr; + } + } +} + +extern "C" +SANITIZER_INTERFACE_ATTRIBUTE +void __sanitizer_mz_destroy(malloc_zone_t* zone) { + // A no-op -- we will not be destroyed! + Report("__sanitizer_mz_destroy() called -- ignoring\n"); +} + +extern "C" +SANITIZER_INTERFACE_ATTRIBUTE +void *__sanitizer_mz_memalign(malloc_zone_t *zone, size_t align, size_t size) { + COMMON_MALLOC_ENTER(); + COMMON_MALLOC_MEMALIGN(align, size); + return p; +} + +// This public API exists purely for testing purposes. +extern "C" +SANITIZER_INTERFACE_ATTRIBUTE +malloc_zone_t* __sanitizer_mz_default_zone() { + return &sanitizer_zone; +} + +// This function is currently unused, and we build with -Werror. +#if 0 +void __sanitizer_mz_free_definite_size( + malloc_zone_t* zone, void *ptr, size_t size) { + // TODO(glider): check that |size| is valid. + UNIMPLEMENTED(); +} +#endif + +#ifndef COMMON_MALLOC_HAS_ZONE_ENUMERATOR +#error "COMMON_MALLOC_HAS_ZONE_ENUMERATOR must be defined" +#endif +static_assert((COMMON_MALLOC_HAS_ZONE_ENUMERATOR) == 0 || + (COMMON_MALLOC_HAS_ZONE_ENUMERATOR) == 1, + "COMMON_MALLOC_HAS_ZONE_ENUMERATOR must be 0 or 1"); + +#if COMMON_MALLOC_HAS_ZONE_ENUMERATOR +// Forward declare and expect the implementation to provided by +// includer. +kern_return_t mi_enumerator(task_t task, void *, unsigned type_mask, + vm_address_t zone_address, memory_reader_t reader, + vm_range_recorder_t recorder); +#else +// Provide stub implementation that fails. +kern_return_t mi_enumerator(task_t task, void *, unsigned type_mask, + vm_address_t zone_address, memory_reader_t reader, + vm_range_recorder_t recorder) { + // Not supported. + return KERN_FAILURE; +} +#endif + +#ifndef COMMON_MALLOC_HAS_EXTRA_INTROSPECTION_INIT +#error "COMMON_MALLOC_HAS_EXTRA_INTROSPECTION_INIT must be defined" +#endif +static_assert((COMMON_MALLOC_HAS_EXTRA_INTROSPECTION_INIT) == 0 || + (COMMON_MALLOC_HAS_EXTRA_INTROSPECTION_INIT) == 1, + "COMMON_MALLOC_HAS_EXTRA_INTROSPECTION_INIT must be 0 or 1"); +#if COMMON_MALLOC_HAS_EXTRA_INTROSPECTION_INIT +// Forward declare and expect the implementation to provided by +// includer. +void mi_extra_init( + sanitizer_malloc_introspection_t *mi); +#else +void mi_extra_init( + sanitizer_malloc_introspection_t *mi) { + // Just zero initialize the fields. + mi->allocator_ptr = 0; + mi->allocator_size = 0; +} +#endif + +size_t mi_good_size(malloc_zone_t *zone, size_t size) { + // I think it's always safe to return size, but we maybe could do better. + return size; +} + +boolean_t mi_check(malloc_zone_t *zone) { + UNIMPLEMENTED(); +} + +void mi_print(malloc_zone_t *zone, boolean_t verbose) { + UNIMPLEMENTED(); +} + +void mi_log(malloc_zone_t *zone, void *address) { + // I don't think we support anything like this +} + +void mi_force_lock(malloc_zone_t *zone) { + COMMON_MALLOC_FORCE_LOCK(); +} + +void mi_force_unlock(malloc_zone_t *zone) { + COMMON_MALLOC_FORCE_UNLOCK(); +} + +void mi_statistics(malloc_zone_t *zone, malloc_statistics_t *stats) { + COMMON_MALLOC_FILL_STATS(zone, stats); +} + +boolean_t mi_zone_locked(malloc_zone_t *zone) { + // UNIMPLEMENTED(); + return false; +} + +} // unnamed namespace + +namespace COMMON_MALLOC_NAMESPACE { + +void InitMallocZoneFields() { + static sanitizer_malloc_introspection_t sanitizer_zone_introspection; + // Ok to use internal_memset, these places are not performance-critical. + internal_memset(&sanitizer_zone_introspection, 0, + sizeof(sanitizer_zone_introspection)); + + sanitizer_zone_introspection.enumerator = &mi_enumerator; + sanitizer_zone_introspection.good_size = &mi_good_size; + sanitizer_zone_introspection.check = &mi_check; + sanitizer_zone_introspection.print = &mi_print; + sanitizer_zone_introspection.log = &mi_log; + sanitizer_zone_introspection.force_lock = &mi_force_lock; + sanitizer_zone_introspection.force_unlock = &mi_force_unlock; + sanitizer_zone_introspection.statistics = &mi_statistics; + sanitizer_zone_introspection.zone_locked = &mi_zone_locked; + + // Set current allocator enumeration version. + sanitizer_zone_introspection.allocator_enumeration_version = + GetMallocZoneAllocatorEnumerationVersion(); + + // Perform any sanitizer specific initialization. + mi_extra_init(&sanitizer_zone_introspection); + + internal_memset(&sanitizer_zone, 0, sizeof(malloc_zone_t)); + + // Use version 6 for OSX >= 10.6. + sanitizer_zone.version = 6; + sanitizer_zone.zone_name = COMMON_MALLOC_ZONE_NAME; + sanitizer_zone.size = &__sanitizer_mz_size; + sanitizer_zone.malloc = &__sanitizer_mz_malloc; + sanitizer_zone.calloc = &__sanitizer_mz_calloc; + sanitizer_zone.valloc = &__sanitizer_mz_valloc; + sanitizer_zone.free = &__sanitizer_mz_free; + sanitizer_zone.realloc = &__sanitizer_mz_realloc; + sanitizer_zone.destroy = &__sanitizer_mz_destroy; + sanitizer_zone.batch_malloc = 0; + sanitizer_zone.batch_free = 0; + sanitizer_zone.free_definite_size = 0; + sanitizer_zone.memalign = &__sanitizer_mz_memalign; + sanitizer_zone.introspect = &sanitizer_zone_introspection; +} + +void ReplaceSystemMalloc() { + InitMallocZoneFields(); + + // Register the zone. + malloc_zone_register(&sanitizer_zone); +} + +} // namespace COMMON_MALLOC_NAMESPACE diff --git a/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_mutex.cpp b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_mutex.cpp new file mode 100644 index 0000000000..40fe566612 --- /dev/null +++ b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_mutex.cpp @@ -0,0 +1,225 @@ +//===-- sanitizer_mutex.cpp -----------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file is shared between AddressSanitizer and ThreadSanitizer +// run-time libraries. +//===----------------------------------------------------------------------===// + +#include "sanitizer_mutex.h" + +#include "sanitizer_common.h" + +namespace __sanitizer { + +void StaticSpinMutex::LockSlow() { + for (int i = 0;; i++) { + if (i < 100) + proc_yield(1); + else + internal_sched_yield(); + if (atomic_load(&state_, memory_order_relaxed) == 0 && + atomic_exchange(&state_, 1, memory_order_acquire) == 0) + return; + } +} + +void Semaphore::Wait() { + u32 count = atomic_load(&state_, memory_order_relaxed); + for (;;) { + if (count == 0) { + FutexWait(&state_, 0); + count = atomic_load(&state_, memory_order_relaxed); + continue; + } + if (atomic_compare_exchange_weak(&state_, &count, count - 1, + memory_order_acquire)) + break; + } +} + +void Semaphore::Post(u32 count) { + CHECK_NE(count, 0); + atomic_fetch_add(&state_, count, memory_order_release); + FutexWake(&state_, count); +} + +#if SANITIZER_CHECK_DEADLOCKS +// An empty mutex meta table, it effectively disables deadlock detection. +// Each tool can override the table to define own mutex hierarchy and +// enable deadlock detection. +// The table defines a static mutex type hierarchy (what mutex types can be locked +// under what mutex types). This table is checked to be acyclic and then +// actual mutex lock/unlock operations are checked to adhere to this hierarchy. +// The checking happens on mutex types rather than on individual mutex instances +// because doing it on mutex instances will both significantly complicate +// the implementation, worsen performance and memory overhead and is mostly +// unnecessary (we almost never lock multiple mutexes of the same type recursively). +static constexpr int kMutexTypeMax = 20; +SANITIZER_WEAK_ATTRIBUTE MutexMeta mutex_meta[kMutexTypeMax] = {}; +SANITIZER_WEAK_ATTRIBUTE void PrintMutexPC(uptr pc) {} +static StaticSpinMutex mutex_meta_mtx; +static int mutex_type_count = -1; +// Adjacency matrix of what mutexes can be locked under what mutexes. +static bool mutex_can_lock[kMutexTypeMax][kMutexTypeMax]; +// Mutex types with MutexMulti mark. +static bool mutex_multi[kMutexTypeMax]; + +void DebugMutexInit() { + // Build adjacency matrix. + bool leaf[kMutexTypeMax]; + internal_memset(&leaf, 0, sizeof(leaf)); + int cnt[kMutexTypeMax]; + internal_memset(&cnt, 0, sizeof(cnt)); + for (int t = 0; t < kMutexTypeMax; t++) { + mutex_type_count = t; + if (!mutex_meta[t].name) + break; + CHECK_EQ(t, mutex_meta[t].type); + for (uptr j = 0; j < ARRAY_SIZE(mutex_meta[t].can_lock); j++) { + MutexType z = mutex_meta[t].can_lock[j]; + if (z == MutexInvalid) + break; + if (z == MutexLeaf) { + CHECK(!leaf[t]); + leaf[t] = true; + continue; + } + if (z == MutexMulti) { + mutex_multi[t] = true; + continue; + } + CHECK_LT(z, kMutexTypeMax); + CHECK(!mutex_can_lock[t][z]); + mutex_can_lock[t][z] = true; + cnt[t]++; + } + } + // Indicates the array is not properly terminated. + CHECK_LT(mutex_type_count, kMutexTypeMax); + // Add leaf mutexes. + for (int t = 0; t < mutex_type_count; t++) { + if (!leaf[t]) + continue; + CHECK_EQ(cnt[t], 0); + for (int z = 0; z < mutex_type_count; z++) { + if (z == MutexInvalid || t == z || leaf[z]) + continue; + CHECK(!mutex_can_lock[z][t]); + mutex_can_lock[z][t] = true; + } + } + // Build the transitive closure and check that the graphs is acyclic. + u32 trans[kMutexTypeMax]; + static_assert(sizeof(trans[0]) * 8 >= kMutexTypeMax, + "kMutexTypeMax does not fit into u32, switch to u64"); + internal_memset(&trans, 0, sizeof(trans)); + for (int i = 0; i < mutex_type_count; i++) { + for (int j = 0; j < mutex_type_count; j++) + if (mutex_can_lock[i][j]) + trans[i] |= 1 << j; + } + for (int k = 0; k < mutex_type_count; k++) { + for (int i = 0; i < mutex_type_count; i++) { + if (trans[i] & (1 << k)) + trans[i] |= trans[k]; + } + } + for (int i = 0; i < mutex_type_count; i++) { + if (trans[i] & (1 << i)) { + Printf("Mutex %s participates in a cycle\n", mutex_meta[i].name); + Die(); + } + } +} + +struct InternalDeadlockDetector { + struct LockDesc { + u64 seq; + uptr pc; + int recursion; + }; + int initialized; + u64 sequence; + LockDesc locked[kMutexTypeMax]; + + void Lock(MutexType type, uptr pc) { + if (!Initialize(type)) + return; + CHECK_LT(type, mutex_type_count); + // Find the last locked mutex type. + // This is the type we will use for hierarchy checks. + u64 max_seq = 0; + MutexType max_idx = MutexInvalid; + for (int i = 0; i != mutex_type_count; i++) { + if (locked[i].seq == 0) + continue; + CHECK_NE(locked[i].seq, max_seq); + if (max_seq < locked[i].seq) { + max_seq = locked[i].seq; + max_idx = (MutexType)i; + } + } + if (max_idx == type && mutex_multi[type]) { + // Recursive lock of the same type. + CHECK_EQ(locked[type].seq, max_seq); + CHECK(locked[type].pc); + locked[type].recursion++; + return; + } + if (max_idx != MutexInvalid && !mutex_can_lock[max_idx][type]) { + Printf("%s: internal deadlock: can't lock %s under %s mutex\n", SanitizerToolName, + mutex_meta[type].name, mutex_meta[max_idx].name); + PrintMutexPC(locked[max_idx].pc); + CHECK(0); + } + locked[type].seq = ++sequence; + locked[type].pc = pc; + locked[type].recursion = 1; + } + + void Unlock(MutexType type) { + if (!Initialize(type)) + return; + CHECK_LT(type, mutex_type_count); + CHECK(locked[type].seq); + CHECK_GT(locked[type].recursion, 0); + if (--locked[type].recursion) + return; + locked[type].seq = 0; + locked[type].pc = 0; + } + + void CheckNoLocks() { + for (int i = 0; i < mutex_type_count; i++) CHECK_EQ(locked[i].recursion, 0); + } + + bool Initialize(MutexType type) { + if (type == MutexUnchecked || type == MutexInvalid) + return false; + CHECK_GT(type, MutexInvalid); + if (initialized != 0) + return initialized > 0; + initialized = -1; + SpinMutexLock lock(&mutex_meta_mtx); + if (mutex_type_count < 0) + DebugMutexInit(); + initialized = mutex_type_count ? 1 : -1; + return initialized > 0; + } +}; + +static THREADLOCAL InternalDeadlockDetector deadlock_detector; + +void CheckedMutex::LockImpl(uptr pc) { deadlock_detector.Lock(type_, pc); } + +void CheckedMutex::UnlockImpl() { deadlock_detector.Unlock(type_); } + +void CheckedMutex::CheckNoLocksImpl() { deadlock_detector.CheckNoLocks(); } +#endif + +} // namespace __sanitizer diff --git a/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_mutex.h b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_mutex.h new file mode 100644 index 0000000000..c16f5cdc1d --- /dev/null +++ b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_mutex.h @@ -0,0 +1,432 @@ +//===-- sanitizer_mutex.h ---------------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// 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" +#include "sanitizer_thread_safety.h" + +namespace __sanitizer { + +class SANITIZER_MUTEX StaticSpinMutex { + public: + void Init() { + atomic_store(&state_, 0, memory_order_relaxed); + } + + void Lock() SANITIZER_ACQUIRE() { + if (LIKELY(TryLock())) + return; + LockSlow(); + } + + bool TryLock() SANITIZER_TRY_ACQUIRE(true) { + return atomic_exchange(&state_, 1, memory_order_acquire) == 0; + } + + void Unlock() SANITIZER_RELEASE() { + atomic_store(&state_, 0, memory_order_release); + } + + void CheckLocked() const SANITIZER_CHECK_LOCKED() { + CHECK_EQ(atomic_load(&state_, memory_order_relaxed), 1); + } + + private: + atomic_uint8_t state_; + + void LockSlow(); +}; + +class SANITIZER_MUTEX SpinMutex : public StaticSpinMutex { + public: + SpinMutex() { + Init(); + } + + SpinMutex(const SpinMutex &) = delete; + void operator=(const SpinMutex &) = delete; +}; + +// Semaphore provides an OS-dependent way to park/unpark threads. +// The last thread returned from Wait can destroy the object +// (destruction-safety). +class Semaphore { + public: + constexpr Semaphore() {} + Semaphore(const Semaphore &) = delete; + void operator=(const Semaphore &) = delete; + + void Wait(); + void Post(u32 count = 1); + + private: + atomic_uint32_t state_ = {0}; +}; + +typedef int MutexType; + +enum { + // Used as sentinel and to catch unassigned types + // (should not be used as real Mutex type). + MutexInvalid = 0, + MutexThreadRegistry, + // Each tool own mutexes must start at this number. + MutexLastCommon, + // Type for legacy mutexes that are not checked for deadlocks. + MutexUnchecked = -1, + // Special marks that can be used in MutexMeta::can_lock table. + // The leaf mutexes can be locked under any other non-leaf mutex, + // but no other mutex can be locked while under a leaf mutex. + MutexLeaf = -1, + // Multiple mutexes of this type can be locked at the same time. + MutexMulti = -3, +}; + +// Go linker does not support THREADLOCAL variables, +// so we can't use per-thread state. +// Disable checked locks on Darwin. Although Darwin platforms support +// THREADLOCAL variables they are not usable early on during process init when +// `__sanitizer::Mutex` is used. +#define SANITIZER_CHECK_DEADLOCKS \ + (SANITIZER_DEBUG && !SANITIZER_GO && SANITIZER_SUPPORTS_THREADLOCAL && !SANITIZER_MAC) + +#if SANITIZER_CHECK_DEADLOCKS +struct MutexMeta { + MutexType type; + const char *name; + // The table fixes what mutexes can be locked under what mutexes. + // If the entry for MutexTypeFoo contains MutexTypeBar, + // then Bar mutex can be locked while under Foo mutex. + // Can also contain the special MutexLeaf/MutexMulti marks. + MutexType can_lock[10]; +}; +#endif + +class CheckedMutex { + public: + explicit constexpr CheckedMutex(MutexType type) +#if SANITIZER_CHECK_DEADLOCKS + : type_(type) +#endif + { + } + + ALWAYS_INLINE void Lock() { +#if SANITIZER_CHECK_DEADLOCKS + LockImpl(GET_CALLER_PC()); +#endif + } + + ALWAYS_INLINE void Unlock() { +#if SANITIZER_CHECK_DEADLOCKS + UnlockImpl(); +#endif + } + + // Checks that the current thread does not hold any mutexes + // (e.g. when returning from a runtime function to user code). + static void CheckNoLocks() { +#if SANITIZER_CHECK_DEADLOCKS + CheckNoLocksImpl(); +#endif + } + + private: +#if SANITIZER_CHECK_DEADLOCKS + const MutexType type_; + + void LockImpl(uptr pc); + void UnlockImpl(); + static void CheckNoLocksImpl(); +#endif +}; + +// Reader-writer mutex. +// Derive from CheckedMutex for the purposes of EBO. +// We could make it a field marked with [[no_unique_address]], +// but this attribute is not supported by some older compilers. +class SANITIZER_MUTEX Mutex : CheckedMutex { + public: + explicit constexpr Mutex(MutexType type = MutexUnchecked) + : CheckedMutex(type) {} + + void Lock() SANITIZER_ACQUIRE() { + CheckedMutex::Lock(); + u64 reset_mask = ~0ull; + u64 state = atomic_load_relaxed(&state_); + for (uptr spin_iters = 0;; spin_iters++) { + u64 new_state; + bool locked = (state & (kWriterLock | kReaderLockMask)) != 0; + if (LIKELY(!locked)) { + // The mutex is not read-/write-locked, try to lock. + new_state = (state | kWriterLock) & reset_mask; + } else if (spin_iters > kMaxSpinIters) { + // We've spun enough, increment waiting writers count and block. + // The counter will be decremented by whoever wakes us. + new_state = (state + kWaitingWriterInc) & reset_mask; + } else if ((state & kWriterSpinWait) == 0) { + // Active spinning, but denote our presence so that unlocking + // thread does not wake up other threads. + new_state = state | kWriterSpinWait; + } else { + // Active spinning. + state = atomic_load(&state_, memory_order_relaxed); + continue; + } + if (UNLIKELY(!atomic_compare_exchange_weak(&state_, &state, new_state, + memory_order_acquire))) + continue; + if (LIKELY(!locked)) + return; // We've locked the mutex. + if (spin_iters > kMaxSpinIters) { + // We've incremented waiting writers, so now block. + writers_.Wait(); + spin_iters = 0; + } else { + // We've set kWriterSpinWait, but we are still in active spinning. + } + // We either blocked and were unblocked, + // or we just spun but set kWriterSpinWait. + // Either way we need to reset kWriterSpinWait + // next time we take the lock or block again. + reset_mask = ~kWriterSpinWait; + state = atomic_load(&state_, memory_order_relaxed); + DCHECK_NE(state & kWriterSpinWait, 0); + } + } + + void Unlock() SANITIZER_RELEASE() { + CheckedMutex::Unlock(); + bool wake_writer; + u64 wake_readers; + u64 new_state; + u64 state = atomic_load_relaxed(&state_); + do { + DCHECK_NE(state & kWriterLock, 0); + DCHECK_EQ(state & kReaderLockMask, 0); + new_state = state & ~kWriterLock; + wake_writer = (state & (kWriterSpinWait | kReaderSpinWait)) == 0 && + (state & kWaitingWriterMask) != 0; + if (wake_writer) + new_state = (new_state - kWaitingWriterInc) | kWriterSpinWait; + wake_readers = + wake_writer || (state & kWriterSpinWait) != 0 + ? 0 + : ((state & kWaitingReaderMask) >> kWaitingReaderShift); + if (wake_readers) + new_state = (new_state & ~kWaitingReaderMask) | kReaderSpinWait; + } while (UNLIKELY(!atomic_compare_exchange_weak(&state_, &state, new_state, + memory_order_release))); + if (UNLIKELY(wake_writer)) + writers_.Post(); + else if (UNLIKELY(wake_readers)) + readers_.Post(wake_readers); + } + + void ReadLock() SANITIZER_ACQUIRE_SHARED() { + CheckedMutex::Lock(); + u64 reset_mask = ~0ull; + u64 state = atomic_load_relaxed(&state_); + for (uptr spin_iters = 0;; spin_iters++) { + bool locked = (state & kWriterLock) != 0; + u64 new_state; + if (LIKELY(!locked)) { + new_state = (state + kReaderLockInc) & reset_mask; + } else if (spin_iters > kMaxSpinIters) { + new_state = (state + kWaitingReaderInc) & reset_mask; + } else if ((state & kReaderSpinWait) == 0) { + // Active spinning, but denote our presence so that unlocking + // thread does not wake up other threads. + new_state = state | kReaderSpinWait; + } else { + // Active spinning. + state = atomic_load(&state_, memory_order_relaxed); + continue; + } + if (UNLIKELY(!atomic_compare_exchange_weak(&state_, &state, new_state, + memory_order_acquire))) + continue; + if (LIKELY(!locked)) + return; // We've locked the mutex. + if (spin_iters > kMaxSpinIters) { + // We've incremented waiting readers, so now block. + readers_.Wait(); + spin_iters = 0; + } else { + // We've set kReaderSpinWait, but we are still in active spinning. + } + reset_mask = ~kReaderSpinWait; + state = atomic_load(&state_, memory_order_relaxed); + } + } + + void ReadUnlock() SANITIZER_RELEASE_SHARED() { + CheckedMutex::Unlock(); + bool wake; + u64 new_state; + u64 state = atomic_load_relaxed(&state_); + do { + DCHECK_NE(state & kReaderLockMask, 0); + DCHECK_EQ(state & kWriterLock, 0); + new_state = state - kReaderLockInc; + wake = (new_state & + (kReaderLockMask | kWriterSpinWait | kReaderSpinWait)) == 0 && + (new_state & kWaitingWriterMask) != 0; + if (wake) + new_state = (new_state - kWaitingWriterInc) | kWriterSpinWait; + } while (UNLIKELY(!atomic_compare_exchange_weak(&state_, &state, new_state, + memory_order_release))); + if (UNLIKELY(wake)) + writers_.Post(); + } + + // This function does not guarantee an explicit check that the calling thread + // is the thread which owns the mutex. This behavior, while more strictly + // correct, causes problems in cases like StopTheWorld, where a parent thread + // owns the mutex but a child checks that it is locked. Rather than + // maintaining complex state to work around those situations, the check only + // checks that the mutex is owned. + void CheckWriteLocked() const SANITIZER_CHECK_LOCKED() { + CHECK(atomic_load(&state_, memory_order_relaxed) & kWriterLock); + } + + void CheckLocked() const SANITIZER_CHECK_LOCKED() { CheckWriteLocked(); } + + void CheckReadLocked() const SANITIZER_CHECK_LOCKED() { + CHECK(atomic_load(&state_, memory_order_relaxed) & kReaderLockMask); + } + + private: + atomic_uint64_t state_ = {0}; + Semaphore writers_; + Semaphore readers_; + + // The state has 3 counters: + // - number of readers holding the lock, + // if non zero, the mutex is read-locked + // - number of waiting readers, + // if not zero, the mutex is write-locked + // - number of waiting writers, + // if non zero, the mutex is read- or write-locked + // And 2 flags: + // - writer lock + // if set, the mutex is write-locked + // - a writer is awake and spin-waiting + // the flag is used to prevent thundering herd problem + // (new writers are not woken if this flag is set) + // - a reader is awake and spin-waiting + // + // Both writers and readers use active spinning before blocking. + // But readers are more aggressive and always take the mutex + // if there are any other readers. + // After wake up both writers and readers compete to lock the + // mutex again. This is needed to allow repeated locks even in presence + // of other blocked threads. + static constexpr u64 kCounterWidth = 20; + static constexpr u64 kReaderLockShift = 0; + static constexpr u64 kReaderLockInc = 1ull << kReaderLockShift; + static constexpr u64 kReaderLockMask = ((1ull << kCounterWidth) - 1) + << kReaderLockShift; + static constexpr u64 kWaitingReaderShift = kCounterWidth; + static constexpr u64 kWaitingReaderInc = 1ull << kWaitingReaderShift; + static constexpr u64 kWaitingReaderMask = ((1ull << kCounterWidth) - 1) + << kWaitingReaderShift; + static constexpr u64 kWaitingWriterShift = 2 * kCounterWidth; + static constexpr u64 kWaitingWriterInc = 1ull << kWaitingWriterShift; + static constexpr u64 kWaitingWriterMask = ((1ull << kCounterWidth) - 1) + << kWaitingWriterShift; + static constexpr u64 kWriterLock = 1ull << (3 * kCounterWidth); + static constexpr u64 kWriterSpinWait = 1ull << (3 * kCounterWidth + 1); + static constexpr u64 kReaderSpinWait = 1ull << (3 * kCounterWidth + 2); + + static constexpr uptr kMaxSpinIters = 1500; + + Mutex(LinkerInitialized) = delete; + Mutex(const Mutex &) = delete; + void operator=(const Mutex &) = delete; +}; + +void FutexWait(atomic_uint32_t *p, u32 cmp); +void FutexWake(atomic_uint32_t *p, u32 count); + +template <typename MutexType> +class SANITIZER_SCOPED_LOCK GenericScopedLock { + public: + explicit GenericScopedLock(MutexType *mu) SANITIZER_ACQUIRE(mu) : mu_(mu) { + mu_->Lock(); + } + + ~GenericScopedLock() SANITIZER_RELEASE() { mu_->Unlock(); } + + private: + MutexType *mu_; + + GenericScopedLock(const GenericScopedLock &) = delete; + void operator=(const GenericScopedLock &) = delete; +}; + +template <typename MutexType> +class SANITIZER_SCOPED_LOCK GenericScopedReadLock { + public: + explicit GenericScopedReadLock(MutexType *mu) SANITIZER_ACQUIRE(mu) + : mu_(mu) { + mu_->ReadLock(); + } + + ~GenericScopedReadLock() SANITIZER_RELEASE() { mu_->ReadUnlock(); } + + private: + MutexType *mu_; + + GenericScopedReadLock(const GenericScopedReadLock &) = delete; + void operator=(const GenericScopedReadLock &) = delete; +}; + +template <typename MutexType> +class SANITIZER_SCOPED_LOCK GenericScopedRWLock { + public: + ALWAYS_INLINE explicit GenericScopedRWLock(MutexType *mu, bool write) + SANITIZER_ACQUIRE(mu) + : mu_(mu), write_(write) { + if (write_) + mu_->Lock(); + else + mu_->ReadLock(); + } + + ALWAYS_INLINE ~GenericScopedRWLock() SANITIZER_RELEASE() { + if (write_) + mu_->Unlock(); + else + mu_->ReadUnlock(); + } + + private: + MutexType *mu_; + bool write_; + + GenericScopedRWLock(const GenericScopedRWLock &) = delete; + void operator=(const GenericScopedRWLock &) = delete; +}; + +typedef GenericScopedLock<StaticSpinMutex> SpinMutexLock; +typedef GenericScopedLock<Mutex> Lock; +typedef GenericScopedReadLock<Mutex> ReadLock; +typedef GenericScopedRWLock<Mutex> RWLock; + +} // namespace __sanitizer + +#endif // SANITIZER_MUTEX_H diff --git a/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_netbsd.cpp b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_netbsd.cpp new file mode 100644 index 0000000000..5e601bdcde --- /dev/null +++ b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_netbsd.cpp @@ -0,0 +1,351 @@ +//===-- sanitizer_netbsd.cpp ----------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file is shared between Sanitizer run-time libraries and implements +// NetBSD-specific functions from sanitizer_libc.h. +//===----------------------------------------------------------------------===// + +#include "sanitizer_platform.h" + +#if SANITIZER_NETBSD + +#include "sanitizer_common.h" +#include "sanitizer_flags.h" +#include "sanitizer_getauxval.h" +#include "sanitizer_internal_defs.h" +#include "sanitizer_libc.h" +#include "sanitizer_linux.h" +#include "sanitizer_mutex.h" +#include "sanitizer_placement_new.h" +#include "sanitizer_procmaps.h" + +#include <sys/param.h> +#include <sys/types.h> + +#include <sys/exec.h> +#include <sys/mman.h> +#include <sys/ptrace.h> +#include <sys/resource.h> +#include <sys/stat.h> +#include <sys/syscall.h> +#include <sys/sysctl.h> +#include <sys/time.h> + +#include <dlfcn.h> +#include <errno.h> +#include <fcntl.h> +#include <limits.h> +#include <link.h> +#include <lwp.h> +#include <pthread.h> +#include <sched.h> +#include <signal.h> +#include <ucontext.h> +#include <unistd.h> + +extern "C" void *__mmap(void *, size_t, int, int, int, int, + off_t) SANITIZER_WEAK_ATTRIBUTE; +extern "C" int __sysctl(const int *, unsigned int, void *, size_t *, + const void *, size_t) SANITIZER_WEAK_ATTRIBUTE; +extern "C" int _sys_close(int) SANITIZER_WEAK_ATTRIBUTE; +extern "C" int _sys_open(const char *, int, ...) SANITIZER_WEAK_ATTRIBUTE; +extern "C" ssize_t _sys_read(int, void *, size_t) SANITIZER_WEAK_ATTRIBUTE; +extern "C" ssize_t _sys_write(int, const void *, + size_t) SANITIZER_WEAK_ATTRIBUTE; +extern "C" int __ftruncate(int, int, off_t) SANITIZER_WEAK_ATTRIBUTE; +extern "C" ssize_t _sys_readlink(const char *, char *, + size_t) SANITIZER_WEAK_ATTRIBUTE; +extern "C" int _sys_sched_yield() SANITIZER_WEAK_ATTRIBUTE; +extern "C" int _sys___nanosleep50(const void *, + void *) SANITIZER_WEAK_ATTRIBUTE; +extern "C" int _sys_execve(const char *, char *const[], + char *const[]) SANITIZER_WEAK_ATTRIBUTE; +extern "C" off_t __lseek(int, int, off_t, int) SANITIZER_WEAK_ATTRIBUTE; +extern "C" int __fork() SANITIZER_WEAK_ATTRIBUTE; +extern "C" int _sys___sigprocmask14(int, const void *, + void *) SANITIZER_WEAK_ATTRIBUTE; +extern "C" int _sys___wait450(int wpid, int *, int, + void *) SANITIZER_WEAK_ATTRIBUTE; + +namespace __sanitizer { + +static void *GetRealLibcAddress(const char *symbol) { + void *real = dlsym(RTLD_NEXT, symbol); + if (!real) + real = dlsym(RTLD_DEFAULT, symbol); + if (!real) { + Printf("GetRealLibcAddress failed for symbol=%s", symbol); + Die(); + } + return real; +} + +#define _REAL(func, ...) real##_##func(__VA_ARGS__) +#define DEFINE__REAL(ret_type, func, ...) \ + static ret_type (*real_##func)(__VA_ARGS__) = NULL; \ + if (!real_##func) { \ + real_##func = (ret_type(*)(__VA_ARGS__))GetRealLibcAddress(#func); \ + } \ + CHECK(real_##func); + +// --------------- sanitizer_libc.h +uptr internal_mmap(void *addr, uptr length, int prot, int flags, int fd, + u64 offset) { + CHECK(&__mmap); + return (uptr)__mmap(addr, length, prot, flags, fd, 0, offset); +} + +uptr internal_munmap(void *addr, uptr length) { + DEFINE__REAL(int, munmap, void *a, uptr b); + return _REAL(munmap, addr, length); +} + +uptr internal_mremap(void *old_address, uptr old_size, uptr new_size, int flags, + void *new_address) { + CHECK(false && "internal_mremap is unimplemented on NetBSD"); + return 0; +} + +int internal_mprotect(void *addr, uptr length, int prot) { + DEFINE__REAL(int, mprotect, void *a, uptr b, int c); + return _REAL(mprotect, addr, length, prot); +} + +int internal_madvise(uptr addr, uptr length, int advice) { + DEFINE__REAL(int, madvise, void *a, uptr b, int c); + return _REAL(madvise, (void *)addr, length, advice); +} + +uptr internal_close(fd_t fd) { + CHECK(&_sys_close); + return _sys_close(fd); +} + +uptr internal_open(const char *filename, int flags) { + CHECK(&_sys_open); + return _sys_open(filename, flags); +} + +uptr internal_open(const char *filename, int flags, u32 mode) { + CHECK(&_sys_open); + return _sys_open(filename, flags, mode); +} + +uptr internal_read(fd_t fd, void *buf, uptr count) { + sptr res; + CHECK(&_sys_read); + HANDLE_EINTR(res, (sptr)_sys_read(fd, buf, (size_t)count)); + return res; +} + +uptr internal_write(fd_t fd, const void *buf, uptr count) { + sptr res; + CHECK(&_sys_write); + HANDLE_EINTR(res, (sptr)_sys_write(fd, buf, count)); + return res; +} + +uptr internal_ftruncate(fd_t fd, uptr size) { + sptr res; + CHECK(&__ftruncate); + HANDLE_EINTR(res, __ftruncate(fd, 0, (s64)size)); + return res; +} + +uptr internal_stat(const char *path, void *buf) { + DEFINE__REAL(int, __stat50, const char *a, void *b); + return _REAL(__stat50, path, buf); +} + +uptr internal_lstat(const char *path, void *buf) { + DEFINE__REAL(int, __lstat50, const char *a, void *b); + return _REAL(__lstat50, path, buf); +} + +uptr internal_fstat(fd_t fd, void *buf) { + DEFINE__REAL(int, __fstat50, int a, void *b); + return _REAL(__fstat50, fd, buf); +} + +uptr internal_filesize(fd_t fd) { + struct stat st; + if (internal_fstat(fd, &st)) + return -1; + return (uptr)st.st_size; +} + +uptr internal_dup(int oldfd) { + DEFINE__REAL(int, dup, int a); + return _REAL(dup, oldfd); +} + +uptr internal_dup2(int oldfd, int newfd) { + DEFINE__REAL(int, dup2, int a, int b); + return _REAL(dup2, oldfd, newfd); +} + +uptr internal_readlink(const char *path, char *buf, uptr bufsize) { + CHECK(&_sys_readlink); + return (uptr)_sys_readlink(path, buf, bufsize); +} + +uptr internal_unlink(const char *path) { + DEFINE__REAL(int, unlink, const char *a); + return _REAL(unlink, path); +} + +uptr internal_rename(const char *oldpath, const char *newpath) { + DEFINE__REAL(int, rename, const char *a, const char *b); + return _REAL(rename, oldpath, newpath); +} + +uptr internal_sched_yield() { + CHECK(&_sys_sched_yield); + return _sys_sched_yield(); +} + +void internal__exit(int exitcode) { + DEFINE__REAL(void, _exit, int a); + _REAL(_exit, exitcode); + Die(); // Unreachable. +} + +void internal_usleep(u64 useconds) { + struct timespec ts; + ts.tv_sec = useconds / 1000000; + ts.tv_nsec = (useconds % 1000000) * 1000; + CHECK(&_sys___nanosleep50); + _sys___nanosleep50(&ts, &ts); +} + +uptr internal_execve(const char *filename, char *const argv[], + char *const envp[]) { + CHECK(&_sys_execve); + return _sys_execve(filename, argv, envp); +} + +tid_t GetTid() { + DEFINE__REAL(int, _lwp_self); + return _REAL(_lwp_self); +} + +int TgKill(pid_t pid, tid_t tid, int sig) { + DEFINE__REAL(int, _lwp_kill, int a, int b); + (void)pid; + return _REAL(_lwp_kill, tid, sig); +} + +u64 NanoTime() { + timeval tv; + DEFINE__REAL(int, __gettimeofday50, void *a, void *b); + internal_memset(&tv, 0, sizeof(tv)); + _REAL(__gettimeofday50, &tv, 0); + return (u64)tv.tv_sec * 1000 * 1000 * 1000 + tv.tv_usec * 1000; +} + +uptr internal_clock_gettime(__sanitizer_clockid_t clk_id, void *tp) { + DEFINE__REAL(int, __clock_gettime50, __sanitizer_clockid_t a, void *b); + return _REAL(__clock_gettime50, clk_id, tp); +} + +uptr internal_ptrace(int request, int pid, void *addr, int data) { + DEFINE__REAL(int, ptrace, int a, int b, void *c, int d); + return _REAL(ptrace, request, pid, addr, data); +} + +uptr internal_waitpid(int pid, int *status, int options) { + CHECK(&_sys___wait450); + return _sys___wait450(pid, status, options, 0 /* rusage */); +} + +uptr internal_getpid() { + DEFINE__REAL(int, getpid); + return _REAL(getpid); +} + +uptr internal_getppid() { + DEFINE__REAL(int, getppid); + return _REAL(getppid); +} + +int internal_dlinfo(void *handle, int request, void *p) { + DEFINE__REAL(int, dlinfo, void *a, int b, void *c); + return _REAL(dlinfo, handle, request, p); +} + +uptr internal_getdents(fd_t fd, void *dirp, unsigned int count) { + DEFINE__REAL(int, __getdents30, int a, void *b, size_t c); + return _REAL(__getdents30, fd, dirp, count); +} + +uptr internal_lseek(fd_t fd, OFF_T offset, int whence) { + CHECK(&__lseek); + return __lseek(fd, 0, offset, whence); +} + +uptr internal_prctl(int option, uptr arg2, uptr arg3, uptr arg4, uptr arg5) { + Printf("internal_prctl not implemented for NetBSD"); + Die(); + return 0; +} + +uptr internal_sigaltstack(const void *ss, void *oss) { + DEFINE__REAL(int, __sigaltstack14, const void *a, void *b); + return _REAL(__sigaltstack14, ss, oss); +} + +int internal_fork() { + CHECK(&__fork); + return __fork(); +} + +int internal_sysctl(const int *name, unsigned int namelen, void *oldp, + uptr *oldlenp, const void *newp, uptr newlen) { + CHECK(&__sysctl); + return __sysctl(name, namelen, oldp, (size_t *)oldlenp, newp, (size_t)newlen); +} + +int internal_sysctlbyname(const char *sname, void *oldp, uptr *oldlenp, + const void *newp, uptr newlen) { + DEFINE__REAL(int, sysctlbyname, const char *a, void *b, size_t *c, + const void *d, size_t e); + return _REAL(sysctlbyname, sname, oldp, (size_t *)oldlenp, newp, + (size_t)newlen); +} + +uptr internal_sigprocmask(int how, __sanitizer_sigset_t *set, + __sanitizer_sigset_t *oldset) { + CHECK(&_sys___sigprocmask14); + return _sys___sigprocmask14(how, set, oldset); +} + +void internal_sigfillset(__sanitizer_sigset_t *set) { + DEFINE__REAL(int, __sigfillset14, const void *a); + (void)_REAL(__sigfillset14, set); +} + +void internal_sigemptyset(__sanitizer_sigset_t *set) { + DEFINE__REAL(int, __sigemptyset14, const void *a); + (void)_REAL(__sigemptyset14, set); +} + +void internal_sigdelset(__sanitizer_sigset_t *set, int signo) { + DEFINE__REAL(int, __sigdelset14, const void *a, int b); + (void)_REAL(__sigdelset14, set, signo); +} + +uptr internal_clone(int (*fn)(void *), void *child_stack, int flags, + void *arg) { + DEFINE__REAL(int, clone, int (*a)(void *b), void *c, int d, void *e); + + return _REAL(clone, fn, child_stack, flags, arg); +} + +} // namespace __sanitizer + +#endif diff --git a/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_placement_new.h b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_placement_new.h new file mode 100644 index 0000000000..1ceb8b9092 --- /dev/null +++ b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_placement_new.h @@ -0,0 +1,24 @@ +//===-- sanitizer_placement_new.h -------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// 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" + +inline void *operator new(__sanitizer::operator_new_size_type sz, void *p) { + return p; +} + +#endif // SANITIZER_PLACEMENT_NEW_H diff --git a/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_platform.h b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_platform.h new file mode 100644 index 0000000000..8de765cf66 --- /dev/null +++ b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_platform.h @@ -0,0 +1,419 @@ +//===-- sanitizer_platform.h ------------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// Common platform macros. +//===----------------------------------------------------------------------===// + +#ifndef SANITIZER_PLATFORM_H +#define SANITIZER_PLATFORM_H + +#if !defined(__linux__) && !defined(__FreeBSD__) && !defined(__NetBSD__) && \ + !defined(__APPLE__) && !defined(_WIN32) && !defined(__Fuchsia__) && \ + !(defined(__sun__) && defined(__svr4__)) +# error "This operating system is not supported" +#endif + +// Get __GLIBC__ on a glibc platform. Exclude Android: features.h includes C +// function declarations into a .S file which doesn't compile. +// https://crbug.com/1162741 +#if __has_include(<features.h>) && !defined(__ANDROID__) +# include <features.h> +#endif + +#if defined(__linux__) +# define SANITIZER_LINUX 1 +#else +# define SANITIZER_LINUX 0 +#endif + +#if defined(__GLIBC__) +# define SANITIZER_GLIBC 1 +#else +# define SANITIZER_GLIBC 0 +#endif + +#if defined(__FreeBSD__) +# define SANITIZER_FREEBSD 1 +#else +# define SANITIZER_FREEBSD 0 +#endif + +#if defined(__NetBSD__) +# define SANITIZER_NETBSD 1 +#else +# define SANITIZER_NETBSD 0 +#endif + +#if defined(__sun__) && defined(__svr4__) +# define SANITIZER_SOLARIS 1 +#else +# define SANITIZER_SOLARIS 0 +#endif + +#if defined(__APPLE__) +# define SANITIZER_MAC 1 +# include <TargetConditionals.h> +# if TARGET_OS_OSX +# define SANITIZER_OSX 1 +# else +# define SANITIZER_OSX 0 +# endif +# if TARGET_OS_IPHONE +# define SANITIZER_IOS 1 +# else +# define SANITIZER_IOS 0 +# endif +# if TARGET_OS_SIMULATOR +# define SANITIZER_IOSSIM 1 +# else +# define SANITIZER_IOSSIM 0 +# endif +#else +# define SANITIZER_MAC 0 +# define SANITIZER_IOS 0 +# define SANITIZER_IOSSIM 0 +# define SANITIZER_OSX 0 +#endif + +#if defined(__APPLE__) && TARGET_OS_IPHONE && TARGET_OS_WATCH +# define SANITIZER_WATCHOS 1 +#else +# define SANITIZER_WATCHOS 0 +#endif + +#if defined(__APPLE__) && TARGET_OS_IPHONE && TARGET_OS_TV +# define SANITIZER_TVOS 1 +#else +# define SANITIZER_TVOS 0 +#endif + +#if defined(_WIN32) +# define SANITIZER_WINDOWS 1 +#else +# define SANITIZER_WINDOWS 0 +#endif + +#if defined(_WIN64) +# define SANITIZER_WINDOWS64 1 +#else +# define SANITIZER_WINDOWS64 0 +#endif + +#if defined(__ANDROID__) +# define SANITIZER_ANDROID 1 +#else +# define SANITIZER_ANDROID 0 +#endif + +#if defined(__Fuchsia__) +# define SANITIZER_FUCHSIA 1 +#else +# define SANITIZER_FUCHSIA 0 +#endif + +#define SANITIZER_POSIX \ + (SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_MAC || \ + SANITIZER_NETBSD || SANITIZER_SOLARIS) + +#if __LP64__ || defined(_WIN64) +# define SANITIZER_WORDSIZE 64 +#else +# define SANITIZER_WORDSIZE 32 +#endif + +#if SANITIZER_WORDSIZE == 64 +# define FIRST_32_SECOND_64(a, b) (b) +#else +# define FIRST_32_SECOND_64(a, b) (a) +#endif + +#if defined(__x86_64__) && !defined(_LP64) +# define SANITIZER_X32 1 +#else +# define SANITIZER_X32 0 +#endif + +#if defined(__x86_64__) || defined(_M_X64) +# define SANITIZER_X64 1 +#else +# define SANITIZER_X64 0 +#endif + +#if defined(__i386__) || defined(_M_IX86) +# define SANITIZER_I386 1 +#else +# define SANITIZER_I386 0 +#endif + +#if defined(__mips__) +# define SANITIZER_MIPS 1 +# if defined(__mips64) +# define SANITIZER_MIPS32 0 +# define SANITIZER_MIPS64 1 +# else +# define SANITIZER_MIPS32 1 +# define SANITIZER_MIPS64 0 +# endif +#else +# define SANITIZER_MIPS 0 +# define SANITIZER_MIPS32 0 +# define SANITIZER_MIPS64 0 +#endif + +#if defined(__s390__) +# define SANITIZER_S390 1 +# if defined(__s390x__) +# define SANITIZER_S390_31 0 +# define SANITIZER_S390_64 1 +# else +# define SANITIZER_S390_31 1 +# define SANITIZER_S390_64 0 +# endif +#else +# define SANITIZER_S390 0 +# define SANITIZER_S390_31 0 +# define SANITIZER_S390_64 0 +#endif + +#if defined(__powerpc__) +# define SANITIZER_PPC 1 +# if defined(__powerpc64__) +# define SANITIZER_PPC32 0 +# define SANITIZER_PPC64 1 +// 64-bit PPC has two ABIs (v1 and v2). The old powerpc64 target is +// big-endian, and uses v1 ABI (known for its function descriptors), +// while the new powerpc64le target is little-endian and uses v2. +// In theory, you could convince gcc to compile for their evil twins +// (eg. big-endian v2), but you won't find such combinations in the wild +// (it'd require bootstrapping a whole system, which would be quite painful +// - there's no target triple for that). LLVM doesn't support them either. +# if _CALL_ELF == 2 +# define SANITIZER_PPC64V1 0 +# define SANITIZER_PPC64V2 1 +# else +# define SANITIZER_PPC64V1 1 +# define SANITIZER_PPC64V2 0 +# endif +# else +# define SANITIZER_PPC32 1 +# define SANITIZER_PPC64 0 +# define SANITIZER_PPC64V1 0 +# define SANITIZER_PPC64V2 0 +# endif +#else +# define SANITIZER_PPC 0 +# define SANITIZER_PPC32 0 +# define SANITIZER_PPC64 0 +# define SANITIZER_PPC64V1 0 +# define SANITIZER_PPC64V2 0 +#endif + +#if defined(__arm__) || defined(_M_ARM) +# define SANITIZER_ARM 1 +#else +# define SANITIZER_ARM 0 +#endif + +#if defined(__aarch64__) || defined(_M_ARM64) +# define SANITIZER_ARM64 1 +#else +# define SANITIZER_ARM64 0 +#endif + +#if SANITIZER_SOLARIS && SANITIZER_WORDSIZE == 32 +# define SANITIZER_SOLARIS32 1 +#else +# define SANITIZER_SOLARIS32 0 +#endif + +#if defined(__riscv) && (__riscv_xlen == 64) +# define SANITIZER_RISCV64 1 +#else +# define SANITIZER_RISCV64 0 +#endif + +// By default we allow to use SizeClassAllocator64 on 64-bit platform. +// But in some cases (e.g. AArch64's 39-bit address space) SizeClassAllocator64 +// does not work well and we need to fallback to SizeClassAllocator32. +// For such platforms build this code with -DSANITIZER_CAN_USE_ALLOCATOR64=0 or +// change the definition of SANITIZER_CAN_USE_ALLOCATOR64 here. +#ifndef SANITIZER_CAN_USE_ALLOCATOR64 +# if (SANITIZER_ANDROID && defined(__aarch64__)) || SANITIZER_FUCHSIA +# define SANITIZER_CAN_USE_ALLOCATOR64 1 +# elif defined(__mips64) || defined(__aarch64__) +# define SANITIZER_CAN_USE_ALLOCATOR64 0 +# else +# define SANITIZER_CAN_USE_ALLOCATOR64 (SANITIZER_WORDSIZE == 64) +# endif +#endif + +// The range of addresses which can be returned my mmap. +// FIXME: this value should be different on different platforms. Larger values +// will still work but will consume more memory for TwoLevelByteMap. +#if defined(__mips__) +# if SANITIZER_GO && defined(__mips64) +# define SANITIZER_MMAP_RANGE_SIZE FIRST_32_SECOND_64(1ULL << 32, 1ULL << 47) +# else +# define SANITIZER_MMAP_RANGE_SIZE FIRST_32_SECOND_64(1ULL << 32, 1ULL << 40) +# endif +#elif SANITIZER_RISCV64 +# define SANITIZER_MMAP_RANGE_SIZE FIRST_32_SECOND_64(1ULL << 32, 1ULL << 38) +#elif defined(__aarch64__) +# if SANITIZER_MAC +# if SANITIZER_OSX || SANITIZER_IOSSIM +# define SANITIZER_MMAP_RANGE_SIZE \ + FIRST_32_SECOND_64(1ULL << 32, 1ULL << 47) +# else +// Darwin iOS/ARM64 has a 36-bit VMA, 64GiB VM +# define SANITIZER_MMAP_RANGE_SIZE \ + FIRST_32_SECOND_64(1ULL << 32, 1ULL << 36) +# endif +# else +# define SANITIZER_MMAP_RANGE_SIZE FIRST_32_SECOND_64(1ULL << 32, 1ULL << 48) +# endif +#elif defined(__sparc__) +# define SANITIZER_MMAP_RANGE_SIZE FIRST_32_SECOND_64(1ULL << 32, 1ULL << 52) +#else +# define SANITIZER_MMAP_RANGE_SIZE FIRST_32_SECOND_64(1ULL << 32, 1ULL << 47) +#endif + +// Whether the addresses are sign-extended from the VMA range to the word. +// The SPARC64 Linux port implements this to split the VMA space into two +// non-contiguous halves with a huge hole in the middle. +#if defined(__sparc__) && SANITIZER_WORDSIZE == 64 +# define SANITIZER_SIGN_EXTENDED_ADDRESSES 1 +#else +# define SANITIZER_SIGN_EXTENDED_ADDRESSES 0 +#endif + +// The AArch64 and RISC-V linux ports use the canonical syscall set as +// mandated by the upstream linux community for all new ports. Other ports +// may still use legacy syscalls. +#ifndef SANITIZER_USES_CANONICAL_LINUX_SYSCALLS +# if (defined(__aarch64__) || defined(__riscv) || defined(__hexagon__)) && \ + SANITIZER_LINUX +# define SANITIZER_USES_CANONICAL_LINUX_SYSCALLS 1 +# else +# define SANITIZER_USES_CANONICAL_LINUX_SYSCALLS 0 +# endif +#endif + +// udi16 syscalls can only be used when the following conditions are +// met: +// * target is one of arm32, x86-32, sparc32, sh or m68k +// * libc version is libc5, glibc-2.0, glibc-2.1 or glibc-2.2 to 2.15 +// built against > linux-2.2 kernel headers +// Since we don't want to include libc headers here, we check the +// target only. +#if defined(__arm__) || SANITIZER_X32 || defined(__sparc__) +# define SANITIZER_USES_UID16_SYSCALLS 1 +#else +# define SANITIZER_USES_UID16_SYSCALLS 0 +#endif + +#if defined(__mips__) +# define SANITIZER_POINTER_FORMAT_LENGTH FIRST_32_SECOND_64(8, 10) +#else +# define SANITIZER_POINTER_FORMAT_LENGTH FIRST_32_SECOND_64(8, 12) +#endif + +/// \macro MSC_PREREQ +/// \brief Is the compiler MSVC of at least the specified version? +/// The common \param version values to check for are: +/// * 1800: Microsoft Visual Studio 2013 / 12.0 +/// * 1900: Microsoft Visual Studio 2015 / 14.0 +#ifdef _MSC_VER +# define MSC_PREREQ(version) (_MSC_VER >= (version)) +#else +# define MSC_PREREQ(version) 0 +#endif + +#if SANITIZER_MAC && !(defined(__arm64__) && SANITIZER_IOS) +# define SANITIZER_NON_UNIQUE_TYPEINFO 0 +#else +# define SANITIZER_NON_UNIQUE_TYPEINFO 1 +#endif + +// On linux, some architectures had an ABI transition from 64-bit long double +// (ie. same as double) to 128-bit long double. On those, glibc symbols +// involving long doubles come in two versions, and we need to pass the +// correct one to dlvsym when intercepting them. +#if SANITIZER_LINUX && (SANITIZER_S390 || SANITIZER_PPC32 || SANITIZER_PPC64V1) +# define SANITIZER_NLDBL_VERSION "GLIBC_2.4" +#endif + +#if SANITIZER_GO == 0 +# define SANITIZER_GO 0 +#endif + +// On PowerPC and ARM Thumb, calling pthread_exit() causes LSan to detect leaks. +// pthread_exit() performs unwinding that leads to dlopen'ing libgcc_s.so. +// dlopen mallocs "libgcc_s.so" string which confuses LSan, it fails to realize +// that this allocation happens in dynamic linker and should be ignored. +#if SANITIZER_PPC || defined(__thumb__) +# define SANITIZER_SUPPRESS_LEAK_ON_PTHREAD_EXIT 1 +#else +# define SANITIZER_SUPPRESS_LEAK_ON_PTHREAD_EXIT 0 +#endif + +#if SANITIZER_FREEBSD || SANITIZER_MAC || SANITIZER_NETBSD || SANITIZER_SOLARIS +# define SANITIZER_MADVISE_DONTNEED MADV_FREE +#else +# define SANITIZER_MADVISE_DONTNEED MADV_DONTNEED +#endif + +// Older gcc have issues aligning to a constexpr, and require an integer. +// See https://gcc.gnu.org/bugzilla/show_bug.cgi?id=56859 among others. +#if defined(__powerpc__) || defined(__powerpc64__) +# define SANITIZER_CACHE_LINE_SIZE 128 +#else +# define SANITIZER_CACHE_LINE_SIZE 64 +#endif + +// Enable offline markup symbolizer for Fuchsia. +#if SANITIZER_FUCHSIA +# define SANITIZER_SYMBOLIZER_MARKUP 1 +#else +# define SANITIZER_SYMBOLIZER_MARKUP 0 +#endif + +// Enable ability to support sanitizer initialization that is +// compatible with the sanitizer library being loaded via +// `dlopen()`. +#if SANITIZER_MAC +# define SANITIZER_SUPPORTS_INIT_FOR_DLOPEN 1 +#else +# define SANITIZER_SUPPORTS_INIT_FOR_DLOPEN 0 +#endif + +// SANITIZER_SUPPORTS_THREADLOCAL +// 1 - THREADLOCAL macro is supported by target +// 0 - THREADLOCAL macro is not supported by target +#ifndef __has_feature +// TODO: Support other compilers here +# define SANITIZER_SUPPORTS_THREADLOCAL 1 +#else +# if __has_feature(tls) +# define SANITIZER_SUPPORTS_THREADLOCAL 1 +# else +# define SANITIZER_SUPPORTS_THREADLOCAL 0 +# endif +#endif + +#if defined(__thumb__) && defined(__linux__) +// Workaround for +// https://lab.llvm.org/buildbot/#/builders/clang-thumbv7-full-2stage +// or +// https://lab.llvm.org/staging/#/builders/clang-thumbv7-full-2stage +// It fails *rss_limit_mb_test* without meaningful errors. +# define SANITIZER_START_BACKGROUND_THREAD_IN_ASAN_INTERNAL 1 +#else +# define SANITIZER_START_BACKGROUND_THREAD_IN_ASAN_INTERNAL 0 +#endif + +#endif // SANITIZER_PLATFORM_H diff --git a/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_platform_interceptors.h b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_platform_interceptors.h new file mode 100644 index 0000000000..00ed28b5e4 --- /dev/null +++ b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_platform_interceptors.h @@ -0,0 +1,614 @@ +//===-- sanitizer_platform_interceptors.h -----------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file defines macro telling whether sanitizer tools can/should intercept +// given library functions on a given platform. +// +//===----------------------------------------------------------------------===// +#ifndef SANITIZER_PLATFORM_INTERCEPTORS_H +#define SANITIZER_PLATFORM_INTERCEPTORS_H + +#include "sanitizer_glibc_version.h" +#include "sanitizer_internal_defs.h" +#include "sanitizer_platform.h" + +#if SANITIZER_POSIX +#define SI_POSIX 1 +#else +#define SI_POSIX 0 +#endif + +#if !SANITIZER_WINDOWS +#define SI_WINDOWS 0 +#else +#define SI_WINDOWS 1 +#endif + +#if SI_WINDOWS && SI_POSIX +#error "Windows is not POSIX!" +#endif + +#if SI_POSIX +#include "sanitizer_platform_limits_freebsd.h" +#include "sanitizer_platform_limits_netbsd.h" +#include "sanitizer_platform_limits_posix.h" +#include "sanitizer_platform_limits_solaris.h" +#endif + +#if SANITIZER_LINUX && !SANITIZER_ANDROID +#define SI_LINUX_NOT_ANDROID 1 +#else +#define SI_LINUX_NOT_ANDROID 0 +#endif + +#if SANITIZER_GLIBC +#define SI_GLIBC 1 +#else +#define SI_GLIBC 0 +#endif + +#if SANITIZER_ANDROID +#define SI_ANDROID 1 +#else +#define SI_ANDROID 0 +#endif + +#if SANITIZER_FREEBSD +#define SI_FREEBSD 1 +#else +#define SI_FREEBSD 0 +#endif + +#if SANITIZER_NETBSD +#define SI_NETBSD 1 +#else +#define SI_NETBSD 0 +#endif + +#if SANITIZER_LINUX +#define SI_LINUX 1 +#else +#define SI_LINUX 0 +#endif + +#if SANITIZER_MAC +#define SI_MAC 1 +#define SI_NOT_MAC 0 +#else +#define SI_MAC 0 +#define SI_NOT_MAC 1 +#endif + +#if SANITIZER_IOS +#define SI_IOS 1 +#else +#define SI_IOS 0 +#endif + +#if SANITIZER_IOSSIM +#define SI_IOSSIM 1 +#else +#define SI_IOSSIM 0 +#endif + +#if SANITIZER_WATCHOS +#define SI_WATCHOS 1 +#else +#define SI_WATCHOS 0 +#endif + +#if SANITIZER_TVOS +#define SI_TVOS 1 +#else +#define SI_TVOS 0 +#endif + +#if SANITIZER_FUCHSIA +#define SI_NOT_FUCHSIA 0 +#else +#define SI_NOT_FUCHSIA 1 +#endif + +#if SANITIZER_SOLARIS +#define SI_SOLARIS 1 +#else +#define SI_SOLARIS 0 +#endif + +#if SANITIZER_SOLARIS32 +#define SI_SOLARIS32 1 +#else +#define SI_SOLARIS32 0 +#endif + +#if SANITIZER_POSIX && !SANITIZER_MAC +#define SI_POSIX_NOT_MAC 1 +#else +#define SI_POSIX_NOT_MAC 0 +#endif + +#if SANITIZER_LINUX && !SANITIZER_FREEBSD +#define SI_LINUX_NOT_FREEBSD 1 +#else +#define SI_LINUX_NOT_FREEBSD 0 +#endif + +#define SANITIZER_INTERCEPT_STRLEN SI_NOT_FUCHSIA +#define SANITIZER_INTERCEPT_STRNLEN (SI_NOT_MAC && SI_NOT_FUCHSIA) +#define SANITIZER_INTERCEPT_STRCMP SI_NOT_FUCHSIA +#define SANITIZER_INTERCEPT_STRSTR SI_NOT_FUCHSIA +#define SANITIZER_INTERCEPT_STRCASESTR SI_POSIX +#define SANITIZER_INTERCEPT_STRTOK SI_NOT_FUCHSIA +#define SANITIZER_INTERCEPT_STRCHR SI_NOT_FUCHSIA +#define SANITIZER_INTERCEPT_STRCHRNUL SI_POSIX_NOT_MAC +#define SANITIZER_INTERCEPT_STRRCHR SI_NOT_FUCHSIA +#define SANITIZER_INTERCEPT_STRSPN SI_NOT_FUCHSIA +#define SANITIZER_INTERCEPT_STRPBRK SI_NOT_FUCHSIA +#define SANITIZER_INTERCEPT_TEXTDOMAIN SI_LINUX_NOT_ANDROID || SI_SOLARIS +#define SANITIZER_INTERCEPT_STRCASECMP SI_POSIX +#define SANITIZER_INTERCEPT_MEMSET 1 +#define SANITIZER_INTERCEPT_MEMMOVE 1 +#define SANITIZER_INTERCEPT_MEMCPY 1 +#define SANITIZER_INTERCEPT_MEMCMP SI_NOT_FUCHSIA +#define SANITIZER_INTERCEPT_BCMP \ + SANITIZER_INTERCEPT_MEMCMP && \ + ((SI_POSIX && _GNU_SOURCE) || SI_NETBSD || SI_FREEBSD) +#define SANITIZER_INTERCEPT_STRNDUP SI_POSIX +#define SANITIZER_INTERCEPT___STRNDUP SI_GLIBC +#if defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__) && \ + __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ < 1070 +#define SI_MAC_DEPLOYMENT_BELOW_10_7 1 +#else +#define SI_MAC_DEPLOYMENT_BELOW_10_7 0 +#endif +// memmem on Darwin doesn't exist on 10.6 +// FIXME: enable memmem on Windows. +#define SANITIZER_INTERCEPT_MEMMEM (SI_POSIX && !SI_MAC_DEPLOYMENT_BELOW_10_7) +#define SANITIZER_INTERCEPT_MEMCHR SI_NOT_FUCHSIA +#define SANITIZER_INTERCEPT_MEMRCHR (SI_FREEBSD || SI_LINUX || SI_NETBSD) + +#define SANITIZER_INTERCEPT_READ SI_POSIX +#define SANITIZER_INTERCEPT_PREAD SI_POSIX +#define SANITIZER_INTERCEPT_WRITE SI_POSIX +#define SANITIZER_INTERCEPT_PWRITE SI_POSIX + +#define SANITIZER_INTERCEPT_FREAD SI_POSIX +#define SANITIZER_INTERCEPT_FWRITE SI_POSIX +#define SANITIZER_INTERCEPT_FGETS SI_POSIX +#define SANITIZER_INTERCEPT_FPUTS SI_POSIX +#define SANITIZER_INTERCEPT_PUTS SI_POSIX + +#define SANITIZER_INTERCEPT_PREAD64 (SI_GLIBC || SI_SOLARIS32) +#define SANITIZER_INTERCEPT_PWRITE64 (SI_GLIBC || SI_SOLARIS32) + +#define SANITIZER_INTERCEPT_READV SI_POSIX +#define SANITIZER_INTERCEPT_WRITEV SI_POSIX + +#define SANITIZER_INTERCEPT_PREADV \ + (SI_FREEBSD || SI_NETBSD || SI_LINUX_NOT_ANDROID) +#define SANITIZER_INTERCEPT_PWRITEV SI_LINUX_NOT_ANDROID +#define SANITIZER_INTERCEPT_PREADV64 SI_GLIBC +#define SANITIZER_INTERCEPT_PWRITEV64 SI_GLIBC + +#define SANITIZER_INTERCEPT_PRCTL SI_LINUX + +#define SANITIZER_INTERCEPT_LOCALTIME_AND_FRIENDS SI_POSIX +#define SANITIZER_INTERCEPT_STRPTIME SI_POSIX + +#define SANITIZER_INTERCEPT_SCANF SI_POSIX +#define SANITIZER_INTERCEPT_ISOC99_SCANF SI_GLIBC + +#ifndef SANITIZER_INTERCEPT_PRINTF +#define SANITIZER_INTERCEPT_PRINTF SI_POSIX +#define SANITIZER_INTERCEPT_PRINTF_L (SI_FREEBSD || SI_NETBSD) +#define SANITIZER_INTERCEPT_ISOC99_PRINTF SI_GLIBC +#endif + +#define SANITIZER_INTERCEPT___PRINTF_CHK \ + (SANITIZER_INTERCEPT_PRINTF && SI_GLIBC) + +#define SANITIZER_INTERCEPT_FREXP SI_NOT_FUCHSIA +#define SANITIZER_INTERCEPT_FREXPF_FREXPL SI_POSIX + +#define SANITIZER_INTERCEPT_GETPWNAM_AND_FRIENDS SI_POSIX +#define SANITIZER_INTERCEPT_GETPWNAM_R_AND_FRIENDS \ + (SI_FREEBSD || SI_NETBSD || SI_MAC || SI_LINUX_NOT_ANDROID || SI_SOLARIS) +#define SANITIZER_INTERCEPT_GETPWENT \ + (SI_FREEBSD || SI_NETBSD || SI_MAC || SI_LINUX_NOT_ANDROID || SI_SOLARIS) +#define SANITIZER_INTERCEPT_FGETGRENT_R (SI_GLIBC || SI_SOLARIS) +#define SANITIZER_INTERCEPT_FGETPWENT SI_LINUX_NOT_ANDROID || SI_SOLARIS +#define SANITIZER_INTERCEPT_GETPWENT_R \ + (SI_FREEBSD || SI_NETBSD || SI_GLIBC || SI_SOLARIS) +#define SANITIZER_INTERCEPT_FGETPWENT_R (SI_FREEBSD || SI_GLIBC || SI_SOLARIS) +#define SANITIZER_INTERCEPT_SETPWENT \ + (SI_MAC || SI_LINUX_NOT_ANDROID || SI_SOLARIS) +#define SANITIZER_INTERCEPT_CLOCK_GETTIME \ + (SI_FREEBSD || SI_NETBSD || SI_LINUX || SI_SOLARIS) +#define SANITIZER_INTERCEPT_CLOCK_GETCPUCLOCKID \ + (SI_LINUX || SI_FREEBSD || SI_NETBSD) +#define SANITIZER_INTERCEPT_GETITIMER SI_POSIX +#define SANITIZER_INTERCEPT_TIME SI_POSIX +#define SANITIZER_INTERCEPT_GLOB (SI_GLIBC || SI_SOLARIS) +#define SANITIZER_INTERCEPT_GLOB64 SI_GLIBC +#define SANITIZER_INTERCEPT_POSIX_SPAWN SI_POSIX +#define SANITIZER_INTERCEPT_WAIT SI_POSIX +#define SANITIZER_INTERCEPT_INET SI_POSIX +#define SANITIZER_INTERCEPT_PTHREAD_GETSCHEDPARAM SI_POSIX +#define SANITIZER_INTERCEPT_GETADDRINFO SI_POSIX +#define SANITIZER_INTERCEPT_GETNAMEINFO SI_POSIX +#define SANITIZER_INTERCEPT_GETSOCKNAME SI_POSIX +#define SANITIZER_INTERCEPT_GETHOSTBYNAME SI_POSIX +#define SANITIZER_INTERCEPT_GETHOSTBYNAME2 SI_POSIX && !SI_SOLARIS +#define SANITIZER_INTERCEPT_GETHOSTBYNAME_R \ + (SI_FREEBSD || SI_LINUX || SI_SOLARIS) +#define SANITIZER_INTERCEPT_GETHOSTBYNAME2_R \ + (SI_FREEBSD || SI_LINUX_NOT_ANDROID) +#define SANITIZER_INTERCEPT_GETHOSTBYADDR_R \ + (SI_FREEBSD || SI_LINUX_NOT_ANDROID || SI_SOLARIS) +#define SANITIZER_INTERCEPT_GETHOSTENT_R (SI_FREEBSD || SI_GLIBC || SI_SOLARIS) +#define SANITIZER_INTERCEPT_GETSOCKOPT SI_POSIX +#define SANITIZER_INTERCEPT_ACCEPT SI_POSIX +#define SANITIZER_INTERCEPT_ACCEPT4 \ + (SI_LINUX_NOT_ANDROID || SI_NETBSD || SI_FREEBSD) +#define SANITIZER_INTERCEPT_PACCEPT SI_NETBSD +#define SANITIZER_INTERCEPT_MODF SI_POSIX +#define SANITIZER_INTERCEPT_RECVMSG SI_POSIX +#define SANITIZER_INTERCEPT_SENDMSG SI_POSIX +#define SANITIZER_INTERCEPT_RECVMMSG SI_LINUX +#define SANITIZER_INTERCEPT_SENDMMSG SI_LINUX +#define SANITIZER_INTERCEPT_SYSMSG SI_LINUX_NOT_ANDROID +#define SANITIZER_INTERCEPT_GETPEERNAME SI_POSIX +#define SANITIZER_INTERCEPT_IOCTL SI_POSIX +#define SANITIZER_INTERCEPT_INET_ATON SI_POSIX +#define SANITIZER_INTERCEPT_SYSINFO SI_LINUX +#define SANITIZER_INTERCEPT_READDIR SI_POSIX +#define SANITIZER_INTERCEPT_READDIR64 SI_LINUX_NOT_ANDROID || SI_SOLARIS32 +#if SI_LINUX_NOT_ANDROID && \ + (defined(__i386) || defined(__x86_64) || defined(__mips64) || \ + defined(__powerpc64__) || defined(__aarch64__) || defined(__arm__) || \ + defined(__s390__) || SANITIZER_RISCV64) +#define SANITIZER_INTERCEPT_PTRACE 1 +#else +#define SANITIZER_INTERCEPT_PTRACE 0 +#endif +#define SANITIZER_INTERCEPT_SETLOCALE SI_POSIX +#define SANITIZER_INTERCEPT_GETCWD SI_POSIX +#define SANITIZER_INTERCEPT_GET_CURRENT_DIR_NAME SI_LINUX_NOT_ANDROID +#define SANITIZER_INTERCEPT_STRTOIMAX SI_POSIX +#define SANITIZER_INTERCEPT_MBSTOWCS SI_POSIX +#define SANITIZER_INTERCEPT_MBSNRTOWCS \ + (SI_MAC || SI_LINUX_NOT_ANDROID || SI_SOLARIS) +#define SANITIZER_INTERCEPT_WCSTOMBS SI_POSIX +#define SANITIZER_INTERCEPT_STRXFRM SI_POSIX +#define SANITIZER_INTERCEPT___STRXFRM_L SI_LINUX +#define SANITIZER_INTERCEPT_WCSXFRM SI_POSIX +#define SANITIZER_INTERCEPT___WCSXFRM_L SI_LINUX +#define SANITIZER_INTERCEPT_WCSNRTOMBS \ + (SI_FREEBSD || SI_NETBSD || SI_MAC || SI_LINUX_NOT_ANDROID || SI_SOLARIS) +#define SANITIZER_INTERCEPT_WCRTOMB \ + (SI_FREEBSD || SI_NETBSD || SI_MAC || SI_LINUX_NOT_ANDROID || SI_SOLARIS) +#define SANITIZER_INTERCEPT_WCTOMB \ + (SI_FREEBSD || SI_NETBSD || SI_MAC || SI_LINUX_NOT_ANDROID || SI_SOLARIS) +#define SANITIZER_INTERCEPT_TCGETATTR SI_LINUX_NOT_ANDROID || SI_SOLARIS +#define SANITIZER_INTERCEPT_REALPATH SI_POSIX +#define SANITIZER_INTERCEPT_CANONICALIZE_FILE_NAME (SI_GLIBC || SI_SOLARIS) +#define SANITIZER_INTERCEPT_CONFSTR \ + (SI_FREEBSD || SI_NETBSD || SI_MAC || SI_LINUX_NOT_ANDROID || SI_SOLARIS) +#define SANITIZER_INTERCEPT_SCHED_GETAFFINITY SI_LINUX_NOT_ANDROID +#define SANITIZER_INTERCEPT_SCHED_GETPARAM SI_LINUX_NOT_ANDROID || SI_SOLARIS +#define SANITIZER_INTERCEPT_STRERROR SI_POSIX +#define SANITIZER_INTERCEPT_STRERROR_R SI_POSIX +#define SANITIZER_INTERCEPT_XPG_STRERROR_R SI_LINUX_NOT_ANDROID +#define SANITIZER_INTERCEPT_SCANDIR \ + (SI_FREEBSD || SI_NETBSD || SI_LINUX_NOT_ANDROID || SI_SOLARIS) +#define SANITIZER_INTERCEPT_SCANDIR64 SI_LINUX_NOT_ANDROID || SI_SOLARIS32 +#define SANITIZER_INTERCEPT_GETGROUPS SI_POSIX +#define SANITIZER_INTERCEPT_POLL SI_POSIX +#define SANITIZER_INTERCEPT_PPOLL SI_LINUX_NOT_ANDROID || SI_SOLARIS +#define SANITIZER_INTERCEPT_WORDEXP \ + (SI_FREEBSD || SI_NETBSD || (SI_MAC && !SI_IOS) || SI_LINUX_NOT_ANDROID || \ + SI_SOLARIS) +#define SANITIZER_INTERCEPT_SIGWAIT SI_POSIX +#define SANITIZER_INTERCEPT_SIGWAITINFO SI_LINUX_NOT_ANDROID || SI_SOLARIS +#define SANITIZER_INTERCEPT_SIGTIMEDWAIT SI_LINUX_NOT_ANDROID || SI_SOLARIS +#define SANITIZER_INTERCEPT_SIGSETOPS \ + (SI_FREEBSD || SI_NETBSD || SI_MAC || SI_LINUX_NOT_ANDROID || SI_SOLARIS) +#define SANITIZER_INTERCEPT_SIGSET_LOGICOPS SI_LINUX_NOT_ANDROID +#define SANITIZER_INTERCEPT_SIGPENDING SI_POSIX +#define SANITIZER_INTERCEPT_SIGPROCMASK SI_POSIX +#define SANITIZER_INTERCEPT_PTHREAD_SIGMASK SI_POSIX +#define SANITIZER_INTERCEPT_BACKTRACE \ + (SI_FREEBSD || SI_NETBSD || SI_GLIBC || SI_SOLARIS) +#define SANITIZER_INTERCEPT_GETMNTENT SI_LINUX +#define SANITIZER_INTERCEPT_GETMNTENT_R SI_LINUX_NOT_ANDROID +#define SANITIZER_INTERCEPT_STATFS \ + (SI_FREEBSD || SI_MAC || SI_LINUX_NOT_ANDROID || SI_SOLARIS) +#define SANITIZER_INTERCEPT_STATFS64 \ + (((SI_MAC && !TARGET_CPU_ARM64) && !SI_IOS) || SI_LINUX_NOT_ANDROID) +#define SANITIZER_INTERCEPT_STATVFS \ + (SI_FREEBSD || SI_NETBSD || SI_LINUX_NOT_ANDROID) +#define SANITIZER_INTERCEPT_STATVFS64 SI_LINUX_NOT_ANDROID +#define SANITIZER_INTERCEPT_INITGROUPS SI_POSIX +#define SANITIZER_INTERCEPT_ETHER_NTOA_ATON SI_POSIX +#define SANITIZER_INTERCEPT_ETHER_HOST \ + (SI_FREEBSD || SI_MAC || SI_LINUX_NOT_ANDROID) +#define SANITIZER_INTERCEPT_ETHER_R (SI_FREEBSD || SI_LINUX_NOT_ANDROID) +#define SANITIZER_INTERCEPT_SHMCTL \ + (((SI_FREEBSD || SI_LINUX_NOT_ANDROID) && SANITIZER_WORDSIZE == 64) || \ + SI_NETBSD || SI_SOLARIS) +#define SANITIZER_INTERCEPT_RANDOM_R SI_GLIBC +#define SANITIZER_INTERCEPT_PTHREAD_ATTR_GET SI_POSIX +#define SANITIZER_INTERCEPT_PTHREAD_ATTR_GETINHERITSCHED \ + (SI_FREEBSD || SI_NETBSD || SI_MAC || SI_LINUX_NOT_ANDROID || SI_SOLARIS) +#define SANITIZER_INTERCEPT_PTHREAD_ATTR_GETAFFINITY_NP SI_GLIBC +#define SANITIZER_INTERCEPT_PTHREAD_ATTR_GET_SCHED SI_POSIX +#define SANITIZER_INTERCEPT_PTHREAD_MUTEXATTR_GETPSHARED \ + (SI_POSIX && !SI_NETBSD) +#define SANITIZER_INTERCEPT_PTHREAD_MUTEXATTR_GETTYPE SI_POSIX +#define SANITIZER_INTERCEPT_PTHREAD_MUTEXATTR_GETPROTOCOL \ + (SI_MAC || SI_NETBSD || SI_LINUX_NOT_ANDROID || SI_SOLARIS) +#define SANITIZER_INTERCEPT_PTHREAD_MUTEXATTR_GETPRIOCEILING \ + (SI_MAC || SI_NETBSD || SI_LINUX_NOT_ANDROID || SI_SOLARIS) +#define SANITIZER_INTERCEPT_PTHREAD_MUTEXATTR_GETROBUST \ + (SI_LINUX_NOT_ANDROID || SI_SOLARIS) +#define SANITIZER_INTERCEPT_PTHREAD_MUTEXATTR_GETROBUST_NP SI_LINUX_NOT_ANDROID +#define SANITIZER_INTERCEPT_PTHREAD_RWLOCKATTR_GETPSHARED \ + (SI_POSIX && !SI_NETBSD) +#define SANITIZER_INTERCEPT_PTHREAD_RWLOCKATTR_GETKIND_NP SI_GLIBC +#define SANITIZER_INTERCEPT_PTHREAD_CONDATTR_GETPSHARED (SI_POSIX && !SI_NETBSD) +#define SANITIZER_INTERCEPT_PTHREAD_CONDATTR_GETCLOCK \ + (SI_LINUX_NOT_ANDROID || SI_SOLARIS) +#define SANITIZER_INTERCEPT_PTHREAD_BARRIERATTR_GETPSHARED \ + (SI_LINUX_NOT_ANDROID && !SI_NETBSD) +#define SANITIZER_INTERCEPT_THR_EXIT SI_FREEBSD +#define SANITIZER_INTERCEPT_TMPNAM SI_POSIX +#define SANITIZER_INTERCEPT_TMPNAM_R (SI_GLIBC || SI_SOLARIS) +#define SANITIZER_INTERCEPT_PTSNAME SI_LINUX +#define SANITIZER_INTERCEPT_PTSNAME_R SI_LINUX +#define SANITIZER_INTERCEPT_TTYNAME SI_POSIX +#define SANITIZER_INTERCEPT_TTYNAME_R SI_POSIX +#define SANITIZER_INTERCEPT_TEMPNAM SI_POSIX +#define SANITIZER_INTERCEPT_SINCOS SI_LINUX || SI_SOLARIS +#define SANITIZER_INTERCEPT_REMQUO SI_POSIX +#define SANITIZER_INTERCEPT_REMQUOL (SI_POSIX && !SI_NETBSD) +#define SANITIZER_INTERCEPT_LGAMMA SI_POSIX +#define SANITIZER_INTERCEPT_LGAMMAL (SI_POSIX && !SI_NETBSD) +#define SANITIZER_INTERCEPT_LGAMMA_R (SI_FREEBSD || SI_LINUX || SI_SOLARIS) +#define SANITIZER_INTERCEPT_LGAMMAL_R SI_LINUX_NOT_ANDROID || SI_SOLARIS +#define SANITIZER_INTERCEPT_DRAND48_R SI_GLIBC +#define SANITIZER_INTERCEPT_RAND_R \ + (SI_FREEBSD || SI_NETBSD || SI_MAC || SI_LINUX_NOT_ANDROID || SI_SOLARIS) +#define SANITIZER_INTERCEPT_ICONV \ + (SI_FREEBSD || SI_NETBSD || SI_LINUX_NOT_ANDROID || SI_SOLARIS) +#define SANITIZER_INTERCEPT_TIMES SI_POSIX + +// FIXME: getline seems to be available on OSX 10.7 +#define SANITIZER_INTERCEPT_GETLINE \ + (SI_FREEBSD || SI_NETBSD || SI_LINUX_NOT_ANDROID || SI_SOLARIS) + +#define SANITIZER_INTERCEPT__EXIT \ + (SI_LINUX || SI_FREEBSD || SI_NETBSD || SI_MAC || SI_SOLARIS) + +#define SANITIZER_INTERCEPT_PTHREAD_MUTEX SI_POSIX +#define SANITIZER_INTERCEPT___PTHREAD_MUTEX SI_GLIBC +#define SANITIZER_INTERCEPT___LIBC_MUTEX SI_NETBSD +#define SANITIZER_INTERCEPT_PTHREAD_SETNAME_NP \ + (SI_FREEBSD || SI_NETBSD || SI_GLIBC || SI_SOLARIS) +#define SANITIZER_INTERCEPT_PTHREAD_GETNAME_NP \ + (SI_FREEBSD || SI_NETBSD || SI_GLIBC || SI_SOLARIS) + +#define SANITIZER_INTERCEPT_TLS_GET_ADDR \ + (SI_FREEBSD || SI_NETBSD || SI_LINUX_NOT_ANDROID || SI_SOLARIS) + +#define SANITIZER_INTERCEPT_LISTXATTR SI_LINUX +#define SANITIZER_INTERCEPT_GETXATTR SI_LINUX +#define SANITIZER_INTERCEPT_GETRESID SI_LINUX +#define SANITIZER_INTERCEPT_GETIFADDRS \ + (SI_FREEBSD || SI_NETBSD || SI_LINUX_NOT_ANDROID || SI_MAC || SI_SOLARIS) +#define SANITIZER_INTERCEPT_IF_INDEXTONAME \ + (SI_FREEBSD || SI_NETBSD || SI_LINUX_NOT_ANDROID || SI_MAC || SI_SOLARIS) +#define SANITIZER_INTERCEPT_CAPGET SI_LINUX_NOT_ANDROID +#if SI_LINUX && defined(__arm__) +#define SANITIZER_INTERCEPT_AEABI_MEM 1 +#else +#define SANITIZER_INTERCEPT_AEABI_MEM 0 +#endif +#define SANITIZER_INTERCEPT___BZERO SI_MAC || SI_GLIBC +#define SANITIZER_INTERCEPT_BZERO SI_LINUX_NOT_ANDROID +#define SANITIZER_INTERCEPT_FTIME (!SI_FREEBSD && !SI_NETBSD && SI_POSIX) +#define SANITIZER_INTERCEPT_XDR (SI_GLIBC || SI_SOLARIS) +#define SANITIZER_INTERCEPT_XDRREC SI_GLIBC +#define SANITIZER_INTERCEPT_TSEARCH \ + (SI_LINUX_NOT_ANDROID || SI_MAC || SI_NETBSD || SI_SOLARIS) +#define SANITIZER_INTERCEPT_LIBIO_INTERNALS SI_GLIBC +#define SANITIZER_INTERCEPT_FOPEN SI_POSIX +#define SANITIZER_INTERCEPT_FOPEN64 (SI_GLIBC || SI_SOLARIS32) +#define SANITIZER_INTERCEPT_OPEN_MEMSTREAM \ + (SI_LINUX_NOT_ANDROID || SI_NETBSD || SI_SOLARIS) +#define SANITIZER_INTERCEPT_OBSTACK SI_GLIBC +#define SANITIZER_INTERCEPT_FFLUSH SI_POSIX +#define SANITIZER_INTERCEPT_FCLOSE SI_POSIX + +#ifndef SANITIZER_INTERCEPT_DLOPEN_DLCLOSE +#define SANITIZER_INTERCEPT_DLOPEN_DLCLOSE \ + (SI_FREEBSD || SI_NETBSD || SI_LINUX_NOT_ANDROID || SI_MAC || SI_SOLARIS) +#endif + +#define SANITIZER_INTERCEPT_GETPASS \ + (SI_LINUX_NOT_ANDROID || SI_MAC || SI_NETBSD) +#define SANITIZER_INTERCEPT_TIMERFD SI_LINUX_NOT_ANDROID + +#define SANITIZER_INTERCEPT_MLOCKX SI_POSIX +#define SANITIZER_INTERCEPT_FOPENCOOKIE SI_LINUX_NOT_ANDROID +#define SANITIZER_INTERCEPT_SEM \ + (SI_LINUX || SI_FREEBSD || SI_NETBSD || SI_SOLARIS) +#define SANITIZER_INTERCEPT_PTHREAD_SETCANCEL SI_POSIX +#define SANITIZER_INTERCEPT_MINCORE \ + (SI_LINUX || SI_NETBSD || SI_FREEBSD || SI_SOLARIS) +#define SANITIZER_INTERCEPT_PROCESS_VM_READV SI_LINUX +#define SANITIZER_INTERCEPT_CTERMID \ + (SI_LINUX || SI_MAC || SI_FREEBSD || SI_NETBSD || SI_SOLARIS) +#define SANITIZER_INTERCEPT_CTERMID_R (SI_MAC || SI_FREEBSD || SI_SOLARIS) + +#define SANITIZER_INTERCEPTOR_HOOKS \ + (SI_LINUX || SI_MAC || SI_WINDOWS || SI_FREEBSD || SI_NETBSD || SI_SOLARIS) +#define SANITIZER_INTERCEPT_RECV_RECVFROM SI_POSIX +#define SANITIZER_INTERCEPT_SEND_SENDTO SI_POSIX +#define SANITIZER_INTERCEPT_EVENTFD_READ_WRITE SI_LINUX + +#define SI_STAT_LINUX (SI_LINUX && __GLIBC_PREREQ(2, 33)) +#define SANITIZER_INTERCEPT_STAT \ + (SI_FREEBSD || SI_MAC || SI_ANDROID || SI_NETBSD || SI_SOLARIS || \ + SI_STAT_LINUX) +#define SANITIZER_INTERCEPT_LSTAT (SI_NETBSD || SI_FREEBSD || SI_STAT_LINUX) +#define SANITIZER_INTERCEPT___XSTAT \ + ((!SANITIZER_INTERCEPT_STAT && SI_POSIX) || SI_STAT_LINUX) +#define SANITIZER_INTERCEPT___XSTAT64 SI_LINUX_NOT_ANDROID +#define SANITIZER_INTERCEPT___LXSTAT SANITIZER_INTERCEPT___XSTAT +#define SANITIZER_INTERCEPT___LXSTAT64 SI_LINUX_NOT_ANDROID + +#define SANITIZER_INTERCEPT_UTMP \ + (SI_POSIX && !SI_MAC && !SI_FREEBSD && !SI_NETBSD) +#define SANITIZER_INTERCEPT_UTMPX \ + (SI_LINUX_NOT_ANDROID || SI_MAC || SI_FREEBSD || SI_NETBSD) + +#define SANITIZER_INTERCEPT_GETLOADAVG \ + (SI_LINUX_NOT_ANDROID || SI_MAC || SI_FREEBSD || SI_NETBSD) + +#define SANITIZER_INTERCEPT_MMAP SI_POSIX +#define SANITIZER_INTERCEPT_MMAP64 SI_LINUX_NOT_ANDROID || SI_SOLARIS +#define SANITIZER_INTERCEPT_MALLOPT_AND_MALLINFO (SI_GLIBC || SI_ANDROID) +#define SANITIZER_INTERCEPT_MEMALIGN (!SI_FREEBSD && !SI_MAC && !SI_NETBSD) +#define SANITIZER_INTERCEPT___LIBC_MEMALIGN SI_GLIBC +#define SANITIZER_INTERCEPT_PVALLOC (SI_GLIBC || SI_ANDROID) +#define SANITIZER_INTERCEPT_CFREE (SI_GLIBC && !SANITIZER_RISCV64) +#define SANITIZER_INTERCEPT_REALLOCARRAY SI_POSIX +#define SANITIZER_INTERCEPT_ALIGNED_ALLOC (!SI_MAC) +#define SANITIZER_INTERCEPT_MALLOC_USABLE_SIZE (!SI_MAC && !SI_NETBSD) +#define SANITIZER_INTERCEPT_MCHECK_MPROBE SI_LINUX_NOT_ANDROID +#define SANITIZER_INTERCEPT_WCSCAT SI_POSIX +#define SANITIZER_INTERCEPT_WCSDUP SI_POSIX +#define SANITIZER_INTERCEPT_SIGNAL_AND_SIGACTION (!SI_WINDOWS && SI_NOT_FUCHSIA) +#define SANITIZER_INTERCEPT_BSD_SIGNAL SI_ANDROID + +#define SANITIZER_INTERCEPT_ACCT (SI_NETBSD || SI_FREEBSD) +#define SANITIZER_INTERCEPT_USER_FROM_UID SI_NETBSD +#define SANITIZER_INTERCEPT_UID_FROM_USER SI_NETBSD +#define SANITIZER_INTERCEPT_GROUP_FROM_GID SI_NETBSD +#define SANITIZER_INTERCEPT_GID_FROM_GROUP SI_NETBSD +#define SANITIZER_INTERCEPT_ACCESS (SI_NETBSD || SI_FREEBSD) +#define SANITIZER_INTERCEPT_FACCESSAT (SI_NETBSD || SI_FREEBSD) +#define SANITIZER_INTERCEPT_GETGROUPLIST \ + (SI_NETBSD || SI_FREEBSD || SI_LINUX) +#define SANITIZER_INTERCEPT_STRLCPY \ + (SI_NETBSD || SI_FREEBSD || SI_MAC || SI_ANDROID) + +#define SANITIZER_INTERCEPT_NAME_TO_HANDLE_AT SI_LINUX_NOT_ANDROID +#define SANITIZER_INTERCEPT_OPEN_BY_HANDLE_AT SI_LINUX_NOT_ANDROID + +#define SANITIZER_INTERCEPT_READLINK SI_POSIX +#if defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__) && \ + __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ < 101000 +#define SI_MAC_DEPLOYMENT_BELOW_10_10 1 +#else +#define SI_MAC_DEPLOYMENT_BELOW_10_10 0 +#endif +#define SANITIZER_INTERCEPT_READLINKAT \ + (SI_POSIX && !SI_MAC_DEPLOYMENT_BELOW_10_10) + +#define SANITIZER_INTERCEPT_DEVNAME (SI_NETBSD || SI_FREEBSD) +#define SANITIZER_INTERCEPT_DEVNAME_R (SI_NETBSD || SI_FREEBSD) +#define SANITIZER_INTERCEPT_FGETLN (SI_NETBSD || SI_FREEBSD) +#define SANITIZER_INTERCEPT_STRMODE (SI_NETBSD || SI_FREEBSD) +#define SANITIZER_INTERCEPT_TTYENT (SI_NETBSD || SI_FREEBSD) +#define SANITIZER_INTERCEPT_TTYENTPATH SI_NETBSD +#define SANITIZER_INTERCEPT_PROTOENT (SI_LINUX || SI_NETBSD || SI_FREEBSD) +#define SANITIZER_INTERCEPT_PROTOENT_R SI_GLIBC +#define SANITIZER_INTERCEPT_NETENT (SI_LINUX || SI_NETBSD || SI_FREEBSD) +#define SANITIZER_INTERCEPT_SETVBUF \ + (SI_NETBSD || SI_FREEBSD || SI_LINUX || SI_MAC) +#define SANITIZER_INTERCEPT_GETMNTINFO (SI_NETBSD || SI_FREEBSD || SI_MAC) +#define SANITIZER_INTERCEPT_MI_VECTOR_HASH SI_NETBSD +#define SANITIZER_INTERCEPT_GETVFSSTAT SI_NETBSD +#define SANITIZER_INTERCEPT_REGEX (SI_NETBSD || SI_FREEBSD || SI_LINUX) +#define SANITIZER_INTERCEPT_REGEXSUB SI_NETBSD +#define SANITIZER_INTERCEPT_FTS (SI_NETBSD || SI_FREEBSD) +#define SANITIZER_INTERCEPT_SYSCTL (SI_NETBSD || SI_FREEBSD || SI_MAC) +#define SANITIZER_INTERCEPT_ASYSCTL SI_NETBSD +#define SANITIZER_INTERCEPT_SYSCTLGETMIBINFO SI_NETBSD +#define SANITIZER_INTERCEPT_NL_LANGINFO (SI_NETBSD || SI_FREEBSD || SI_MAC) +#define SANITIZER_INTERCEPT_MODCTL SI_NETBSD +#define SANITIZER_INTERCEPT_CAPSICUM SI_FREEBSD +#define SANITIZER_INTERCEPT_STRTONUM (SI_NETBSD || SI_FREEBSD) +#define SANITIZER_INTERCEPT_FPARSELN (SI_NETBSD || SI_FREEBSD) +#define SANITIZER_INTERCEPT_STATVFS1 SI_NETBSD +#define SANITIZER_INTERCEPT_STRTOI SI_NETBSD +#define SANITIZER_INTERCEPT_CAPSICUM SI_FREEBSD +#define SANITIZER_INTERCEPT_SHA1 SI_NETBSD +#define SANITIZER_INTERCEPT_MD4 SI_NETBSD +#define SANITIZER_INTERCEPT_RMD160 SI_NETBSD +#define SANITIZER_INTERCEPT_MD5 (SI_NETBSD || SI_FREEBSD) +#define SANITIZER_INTERCEPT_FSEEK (SI_NETBSD || SI_FREEBSD) +#define SANITIZER_INTERCEPT_MD2 SI_NETBSD +#define SANITIZER_INTERCEPT_SHA2 (SI_NETBSD || SI_FREEBSD) +#define SANITIZER_INTERCEPT_CDB SI_NETBSD +#define SANITIZER_INTERCEPT_VIS (SI_NETBSD || SI_FREEBSD) +#define SANITIZER_INTERCEPT_POPEN SI_POSIX +#define SANITIZER_INTERCEPT_POPENVE SI_NETBSD +#define SANITIZER_INTERCEPT_PCLOSE SI_POSIX +#define SANITIZER_INTERCEPT_FUNOPEN (SI_NETBSD || SI_FREEBSD) +#define SANITIZER_INTERCEPT_FUNOPEN2 SI_NETBSD +#define SANITIZER_INTERCEPT_GETFSENT (SI_FREEBSD || SI_NETBSD || SI_MAC) +#define SANITIZER_INTERCEPT_ARC4RANDOM (SI_FREEBSD || SI_NETBSD || SI_MAC) +#define SANITIZER_INTERCEPT_FDEVNAME SI_FREEBSD +#define SANITIZER_INTERCEPT_GETUSERSHELL (SI_POSIX && !SI_ANDROID) +#define SANITIZER_INTERCEPT_SL_INIT (SI_FREEBSD || SI_NETBSD) +#define SANITIZER_INTERCEPT_CRYPT (SI_POSIX && !SI_ANDROID) +#define SANITIZER_INTERCEPT_CRYPT_R (SI_LINUX && !SI_ANDROID) + +#define SANITIZER_INTERCEPT_GETRANDOM \ + ((SI_LINUX && __GLIBC_PREREQ(2, 25)) || SI_FREEBSD) +#define SANITIZER_INTERCEPT___CXA_ATEXIT SI_NETBSD +#define SANITIZER_INTERCEPT_ATEXIT SI_NETBSD +#define SANITIZER_INTERCEPT_PTHREAD_ATFORK SI_NETBSD +#define SANITIZER_INTERCEPT_GETENTROPY SI_FREEBSD +#define SANITIZER_INTERCEPT_QSORT \ + (SI_POSIX && !SI_IOSSIM && !SI_WATCHOS && !SI_TVOS && !SI_ANDROID) +#define SANITIZER_INTERCEPT_QSORT_R SI_GLIBC +#define SANITIZER_INTERCEPT_BSEARCH \ + (SI_POSIX && !SI_IOSSIM && !SI_WATCHOS && !SI_TVOS && !SI_ANDROID) +// sigaltstack on i386 macOS cannot be intercepted due to setjmp() +// calling it and assuming that it does not clobber registers. +#define SANITIZER_INTERCEPT_SIGALTSTACK \ + (SI_POSIX && !(SANITIZER_MAC && SANITIZER_I386)) +#define SANITIZER_INTERCEPT_UNAME (SI_POSIX && !SI_FREEBSD) +#define SANITIZER_INTERCEPT___XUNAME SI_FREEBSD +#define SANITIZER_INTERCEPT_FLOPEN SI_FREEBSD + +// This macro gives a way for downstream users to override the above +// interceptor macros irrespective of the platform they are on. They have +// to do two things: +// 1. Build compiler-rt with -DSANITIZER_OVERRIDE_INTERCEPTORS. +// 2. Provide a header file named sanitizer_intercept_overriders.h in the +// include path for their compiler-rt build. +// An example of an overrider for strlen interceptor that one can list in +// sanitizer_intercept_overriders.h is as follows: +// +// #ifdef SANITIZER_INTERCEPT_STRLEN +// #undef SANITIZER_INTERCEPT_STRLEN +// #define SANITIZER_INTERCEPT_STRLEN <value of choice> +// #endif +// +// This "feature" is useful for downstream users who do not want some of +// their libc funtions to be intercepted. They can selectively disable +// interception of those functions. +#ifdef SANITIZER_OVERRIDE_INTERCEPTORS +#error #include <sanitizer_intercept_overriders.h> +#endif + +#endif // #ifndef SANITIZER_PLATFORM_INTERCEPTORS_H diff --git a/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_platform_limits_freebsd.cpp b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_platform_limits_freebsd.cpp new file mode 100644 index 0000000000..1f90775421 --- /dev/null +++ b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_platform_limits_freebsd.cpp @@ -0,0 +1,557 @@ +//===-- sanitizer_platform_limits_freebsd.cpp -----------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file is a part of Sanitizer common code. +// +// Sizes and layouts of platform-specific FreeBSD data structures. +//===----------------------------------------------------------------------===// + +#include "sanitizer_platform.h" + +#if SANITIZER_FREEBSD + +#error #include <sys/capsicum.h> +#error #include <sys/consio.h> +#include <sys/filio.h> +#include <sys/ipc.h> +#error #include <sys/kbio.h> +#error #include <sys/link_elf.h> +#include <sys/mman.h> +#include <sys/mount.h> +#error #include <sys/mqueue.h> +#include <sys/msg.h> +#include <sys/mtio.h> +#include <sys/ptrace.h> +#include <sys/resource.h> +#include <sys/signal.h> +#include <sys/socket.h> +#include <sys/sockio.h> +#include <sys/soundcard.h> +#include <sys/stat.h> +#include <sys/statvfs.h> +#include <sys/time.h> +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-W#warnings" +#include <sys/timeb.h> +#pragma clang diagnostic pop +#include <sys/times.h> +#include <sys/timespec.h> +#include <sys/types.h> +#include <sys/ucontext.h> +#include <sys/utsname.h> +// +#include <arpa/inet.h> +#include <net/ethernet.h> +#include <net/if.h> +#error #include <net/ppp_defs.h> +#include <net/route.h> +#include <netdb.h> +#include <netinet/in.h> +#error #include <netinet/ip_mroute.h> +// +#include <dirent.h> +#include <dlfcn.h> +#include <fstab.h> +#include <fts.h> +#include <glob.h> +#include <grp.h> +#include <ifaddrs.h> +#include <limits.h> +#include <poll.h> +#include <pthread.h> +#include <pwd.h> +#include <regex.h> +#include <semaphore.h> +#include <signal.h> +#include <stddef.h> +#error #include <md5.h> +#error #include <sha224.h> +#error #include <sha256.h> +#error #include <sha384.h> +#error #include <sha512.h> +#include <stdio.h> +#error #include <stringlist.h> +#include <term.h> +#include <termios.h> +#include <time.h> +#include <ttyent.h> +#include <utime.h> +#include <utmpx.h> +#include <vis.h> +#include <wchar.h> +#include <wordexp.h> + +#define _KERNEL // to declare 'shminfo' structure +#include <sys/shm.h> +#undef _KERNEL + +#undef IOC_DIRMASK + +// Include these after system headers to avoid name clashes and ambiguities. +#include "sanitizer_internal_defs.h" +#include "sanitizer_libc.h" +#include "sanitizer_platform_limits_freebsd.h" + +namespace __sanitizer { +void *__sanitizer_get_link_map_by_dlopen_handle(void *handle) { + void *p = nullptr; + return internal_dlinfo(handle, RTLD_DI_LINKMAP, &p) == 0 ? p : nullptr; +} + +unsigned struct_cap_rights_sz = sizeof(cap_rights_t); +unsigned struct_utsname_sz = sizeof(struct utsname); +unsigned struct_stat_sz = sizeof(struct stat); +unsigned struct_rusage_sz = sizeof(struct rusage); +unsigned struct_tm_sz = sizeof(struct tm); +unsigned struct_passwd_sz = sizeof(struct passwd); +unsigned struct_group_sz = sizeof(struct group); +unsigned siginfo_t_sz = sizeof(siginfo_t); +unsigned struct_sigaction_sz = sizeof(struct sigaction); +unsigned struct_stack_t_sz = sizeof(stack_t); +unsigned struct_itimerval_sz = sizeof(struct itimerval); +unsigned pthread_t_sz = sizeof(pthread_t); +unsigned pthread_mutex_t_sz = sizeof(pthread_mutex_t); +unsigned pthread_cond_t_sz = sizeof(pthread_cond_t); +unsigned pid_t_sz = sizeof(pid_t); +unsigned timeval_sz = sizeof(timeval); +unsigned uid_t_sz = sizeof(uid_t); +unsigned gid_t_sz = sizeof(gid_t); +unsigned fpos_t_sz = sizeof(fpos_t); +unsigned mbstate_t_sz = sizeof(mbstate_t); +unsigned sigset_t_sz = sizeof(sigset_t); +unsigned struct_timezone_sz = sizeof(struct timezone); +unsigned struct_tms_sz = sizeof(struct tms); +unsigned struct_sigevent_sz = sizeof(struct sigevent); +unsigned struct_sched_param_sz = sizeof(struct sched_param); +unsigned struct_statfs_sz = sizeof(struct statfs); +unsigned struct_sockaddr_sz = sizeof(struct sockaddr); +unsigned ucontext_t_sz(void *ctx) { return sizeof(ucontext_t); } +unsigned struct_rlimit_sz = sizeof(struct rlimit); +unsigned struct_timespec_sz = sizeof(struct timespec); +unsigned struct_utimbuf_sz = sizeof(struct utimbuf); +unsigned struct_itimerspec_sz = sizeof(struct itimerspec); +unsigned struct_timeb_sz = sizeof(struct timeb); +unsigned struct_msqid_ds_sz = sizeof(struct msqid_ds); +unsigned struct_mq_attr_sz = sizeof(struct mq_attr); +unsigned struct_statvfs_sz = sizeof(struct statvfs); +unsigned struct_shminfo_sz = sizeof(struct shminfo); +unsigned struct_shm_info_sz = sizeof(struct shm_info); +unsigned struct_regmatch_sz = sizeof(regmatch_t); +unsigned struct_regex_sz = sizeof(regex_t); +unsigned struct_fstab_sz = sizeof(struct fstab); +unsigned struct_FTS_sz = sizeof(FTS); +unsigned struct_FTSENT_sz = sizeof(FTSENT); +unsigned struct_StringList_sz = sizeof(StringList); + +const uptr sig_ign = (uptr)SIG_IGN; +const uptr sig_dfl = (uptr)SIG_DFL; +const uptr sig_err = (uptr)SIG_ERR; +const uptr sa_siginfo = (uptr)SA_SIGINFO; + +int shmctl_ipc_stat = (int)IPC_STAT; +int shmctl_ipc_info = (int)IPC_INFO; +int shmctl_shm_info = (int)SHM_INFO; +int shmctl_shm_stat = (int)SHM_STAT; +unsigned struct_utmpx_sz = sizeof(struct utmpx); + +int map_fixed = MAP_FIXED; + +int af_inet = (int)AF_INET; +int af_inet6 = (int)AF_INET6; + +uptr __sanitizer_in_addr_sz(int af) { + if (af == AF_INET) + return sizeof(struct in_addr); + else if (af == AF_INET6) + return sizeof(struct in6_addr); + else + return 0; +} + +unsigned struct_ElfW_Phdr_sz = sizeof(Elf_Phdr); +int glob_nomatch = GLOB_NOMATCH; +int glob_altdirfunc = GLOB_ALTDIRFUNC; +const int wordexp_wrde_dooffs = WRDE_DOOFFS; + +unsigned path_max = PATH_MAX; + +int struct_ttyent_sz = sizeof(struct ttyent); + +// ioctl arguments +unsigned struct_ifreq_sz = sizeof(struct ifreq); +unsigned struct_termios_sz = sizeof(struct termios); +unsigned struct_winsize_sz = sizeof(struct winsize); +#if SOUND_VERSION >= 0x040000 +unsigned struct_copr_buffer_sz = 0; +unsigned struct_copr_debug_buf_sz = 0; +unsigned struct_copr_msg_sz = 0; +#else +unsigned struct_copr_buffer_sz = sizeof(struct copr_buffer); +unsigned struct_copr_debug_buf_sz = sizeof(struct copr_debug_buf); +unsigned struct_copr_msg_sz = sizeof(struct copr_msg); +#endif +unsigned struct_midi_info_sz = sizeof(struct midi_info); +unsigned struct_mtget_sz = sizeof(struct mtget); +unsigned struct_mtop_sz = sizeof(struct mtop); +unsigned struct_sbi_instrument_sz = sizeof(struct sbi_instrument); +unsigned struct_seq_event_rec_sz = sizeof(struct seq_event_rec); +unsigned struct_synth_info_sz = sizeof(struct synth_info); +unsigned struct_audio_buf_info_sz = sizeof(struct audio_buf_info); +unsigned struct_ppp_stats_sz = sizeof(struct ppp_stats); +unsigned struct_sioc_sg_req_sz = sizeof(struct sioc_sg_req); +unsigned struct_sioc_vif_req_sz = sizeof(struct sioc_vif_req); +const unsigned long __sanitizer_bufsiz = BUFSIZ; + +const unsigned IOCTL_NOT_PRESENT = 0; + +unsigned IOCTL_FIOASYNC = FIOASYNC; +unsigned IOCTL_FIOCLEX = FIOCLEX; +unsigned IOCTL_FIOGETOWN = FIOGETOWN; +unsigned IOCTL_FIONBIO = FIONBIO; +unsigned IOCTL_FIONCLEX = FIONCLEX; +unsigned IOCTL_FIOSETOWN = FIOSETOWN; +unsigned IOCTL_SIOCADDMULTI = SIOCADDMULTI; +unsigned IOCTL_SIOCATMARK = SIOCATMARK; +unsigned IOCTL_SIOCDELMULTI = SIOCDELMULTI; +unsigned IOCTL_SIOCGIFADDR = SIOCGIFADDR; +unsigned IOCTL_SIOCGIFBRDADDR = SIOCGIFBRDADDR; +unsigned IOCTL_SIOCGIFCONF = SIOCGIFCONF; +unsigned IOCTL_SIOCGIFDSTADDR = SIOCGIFDSTADDR; +unsigned IOCTL_SIOCGIFFLAGS = SIOCGIFFLAGS; +unsigned IOCTL_SIOCGIFMETRIC = SIOCGIFMETRIC; +unsigned IOCTL_SIOCGIFMTU = SIOCGIFMTU; +unsigned IOCTL_SIOCGIFNETMASK = SIOCGIFNETMASK; +unsigned IOCTL_SIOCGPGRP = SIOCGPGRP; +unsigned IOCTL_SIOCSIFADDR = SIOCSIFADDR; +unsigned IOCTL_SIOCSIFBRDADDR = SIOCSIFBRDADDR; +unsigned IOCTL_SIOCSIFDSTADDR = SIOCSIFDSTADDR; +unsigned IOCTL_SIOCSIFFLAGS = SIOCSIFFLAGS; +unsigned IOCTL_SIOCSIFMETRIC = SIOCSIFMETRIC; +unsigned IOCTL_SIOCSIFMTU = SIOCSIFMTU; +unsigned IOCTL_SIOCSIFNETMASK = SIOCSIFNETMASK; +unsigned IOCTL_SIOCSPGRP = SIOCSPGRP; +unsigned IOCTL_TIOCCONS = TIOCCONS; +unsigned IOCTL_TIOCEXCL = TIOCEXCL; +unsigned IOCTL_TIOCGETD = TIOCGETD; +unsigned IOCTL_TIOCGPGRP = TIOCGPGRP; +unsigned IOCTL_TIOCGWINSZ = TIOCGWINSZ; +unsigned IOCTL_TIOCMBIC = TIOCMBIC; +unsigned IOCTL_TIOCMBIS = TIOCMBIS; +unsigned IOCTL_TIOCMGET = TIOCMGET; +unsigned IOCTL_TIOCMSET = TIOCMSET; +unsigned IOCTL_TIOCNOTTY = TIOCNOTTY; +unsigned IOCTL_TIOCNXCL = TIOCNXCL; +unsigned IOCTL_TIOCOUTQ = TIOCOUTQ; +unsigned IOCTL_TIOCPKT = TIOCPKT; +unsigned IOCTL_TIOCSCTTY = TIOCSCTTY; +unsigned IOCTL_TIOCSETD = TIOCSETD; +unsigned IOCTL_TIOCSPGRP = TIOCSPGRP; +unsigned IOCTL_TIOCSTI = TIOCSTI; +unsigned IOCTL_TIOCSWINSZ = TIOCSWINSZ; +unsigned IOCTL_SIOCGETSGCNT = SIOCGETSGCNT; +unsigned IOCTL_SIOCGETVIFCNT = SIOCGETVIFCNT; +unsigned IOCTL_MTIOCGET = MTIOCGET; +unsigned IOCTL_MTIOCTOP = MTIOCTOP; +unsigned IOCTL_SNDCTL_DSP_GETBLKSIZE = SNDCTL_DSP_GETBLKSIZE; +unsigned IOCTL_SNDCTL_DSP_GETFMTS = SNDCTL_DSP_GETFMTS; +unsigned IOCTL_SNDCTL_DSP_NONBLOCK = SNDCTL_DSP_NONBLOCK; +unsigned IOCTL_SNDCTL_DSP_POST = SNDCTL_DSP_POST; +unsigned IOCTL_SNDCTL_DSP_RESET = SNDCTL_DSP_RESET; +unsigned IOCTL_SNDCTL_DSP_SETFMT = SNDCTL_DSP_SETFMT; +unsigned IOCTL_SNDCTL_DSP_SETFRAGMENT = SNDCTL_DSP_SETFRAGMENT; +unsigned IOCTL_SNDCTL_DSP_SPEED = SNDCTL_DSP_SPEED; +unsigned IOCTL_SNDCTL_DSP_STEREO = SNDCTL_DSP_STEREO; +unsigned IOCTL_SNDCTL_DSP_SUBDIVIDE = SNDCTL_DSP_SUBDIVIDE; +unsigned IOCTL_SNDCTL_DSP_SYNC = SNDCTL_DSP_SYNC; +unsigned IOCTL_SNDCTL_FM_4OP_ENABLE = SNDCTL_FM_4OP_ENABLE; +unsigned IOCTL_SNDCTL_FM_LOAD_INSTR = SNDCTL_FM_LOAD_INSTR; +unsigned IOCTL_SNDCTL_MIDI_INFO = SNDCTL_MIDI_INFO; +unsigned IOCTL_SNDCTL_MIDI_PRETIME = SNDCTL_MIDI_PRETIME; +unsigned IOCTL_SNDCTL_SEQ_CTRLRATE = SNDCTL_SEQ_CTRLRATE; +unsigned IOCTL_SNDCTL_SEQ_GETINCOUNT = SNDCTL_SEQ_GETINCOUNT; +unsigned IOCTL_SNDCTL_SEQ_GETOUTCOUNT = SNDCTL_SEQ_GETOUTCOUNT; +unsigned IOCTL_SNDCTL_SEQ_NRMIDIS = SNDCTL_SEQ_NRMIDIS; +unsigned IOCTL_SNDCTL_SEQ_NRSYNTHS = SNDCTL_SEQ_NRSYNTHS; +unsigned IOCTL_SNDCTL_SEQ_OUTOFBAND = SNDCTL_SEQ_OUTOFBAND; +unsigned IOCTL_SNDCTL_SEQ_PANIC = SNDCTL_SEQ_PANIC; +unsigned IOCTL_SNDCTL_SEQ_PERCMODE = SNDCTL_SEQ_PERCMODE; +unsigned IOCTL_SNDCTL_SEQ_RESET = SNDCTL_SEQ_RESET; +unsigned IOCTL_SNDCTL_SEQ_RESETSAMPLES = SNDCTL_SEQ_RESETSAMPLES; +unsigned IOCTL_SNDCTL_SEQ_SYNC = SNDCTL_SEQ_SYNC; +unsigned IOCTL_SNDCTL_SEQ_TESTMIDI = SNDCTL_SEQ_TESTMIDI; +unsigned IOCTL_SNDCTL_SEQ_THRESHOLD = SNDCTL_SEQ_THRESHOLD; +unsigned IOCTL_SNDCTL_SYNTH_INFO = SNDCTL_SYNTH_INFO; +unsigned IOCTL_SNDCTL_SYNTH_MEMAVL = SNDCTL_SYNTH_MEMAVL; +unsigned IOCTL_SNDCTL_TMR_CONTINUE = SNDCTL_TMR_CONTINUE; +unsigned IOCTL_SNDCTL_TMR_METRONOME = SNDCTL_TMR_METRONOME; +unsigned IOCTL_SNDCTL_TMR_SELECT = SNDCTL_TMR_SELECT; +unsigned IOCTL_SNDCTL_TMR_SOURCE = SNDCTL_TMR_SOURCE; +unsigned IOCTL_SNDCTL_TMR_START = SNDCTL_TMR_START; +unsigned IOCTL_SNDCTL_TMR_STOP = SNDCTL_TMR_STOP; +unsigned IOCTL_SNDCTL_TMR_TEMPO = SNDCTL_TMR_TEMPO; +unsigned IOCTL_SNDCTL_TMR_TIMEBASE = SNDCTL_TMR_TIMEBASE; +unsigned IOCTL_SOUND_MIXER_READ_ALTPCM = SOUND_MIXER_READ_ALTPCM; +unsigned IOCTL_SOUND_MIXER_READ_BASS = SOUND_MIXER_READ_BASS; +unsigned IOCTL_SOUND_MIXER_READ_CAPS = SOUND_MIXER_READ_CAPS; +unsigned IOCTL_SOUND_MIXER_READ_CD = SOUND_MIXER_READ_CD; +unsigned IOCTL_SOUND_MIXER_READ_DEVMASK = SOUND_MIXER_READ_DEVMASK; +unsigned IOCTL_SOUND_MIXER_READ_ENHANCE = SOUND_MIXER_READ_ENHANCE; +unsigned IOCTL_SOUND_MIXER_READ_IGAIN = SOUND_MIXER_READ_IGAIN; +unsigned IOCTL_SOUND_MIXER_READ_IMIX = SOUND_MIXER_READ_IMIX; +unsigned IOCTL_SOUND_MIXER_READ_LINE = SOUND_MIXER_READ_LINE; +unsigned IOCTL_SOUND_MIXER_READ_LINE1 = SOUND_MIXER_READ_LINE1; +unsigned IOCTL_SOUND_MIXER_READ_LINE2 = SOUND_MIXER_READ_LINE2; +unsigned IOCTL_SOUND_MIXER_READ_LINE3 = SOUND_MIXER_READ_LINE3; +unsigned IOCTL_SOUND_MIXER_READ_LOUD = SOUND_MIXER_READ_LOUD; +unsigned IOCTL_SOUND_MIXER_READ_MIC = SOUND_MIXER_READ_MIC; +unsigned IOCTL_SOUND_MIXER_READ_MUTE = SOUND_MIXER_READ_MUTE; +unsigned IOCTL_SOUND_MIXER_READ_OGAIN = SOUND_MIXER_READ_OGAIN; +unsigned IOCTL_SOUND_MIXER_READ_PCM = SOUND_MIXER_READ_PCM; +unsigned IOCTL_SOUND_MIXER_READ_RECLEV = SOUND_MIXER_READ_RECLEV; +unsigned IOCTL_SOUND_MIXER_READ_RECMASK = SOUND_MIXER_READ_RECMASK; +unsigned IOCTL_SOUND_MIXER_READ_RECSRC = SOUND_MIXER_READ_RECSRC; +unsigned IOCTL_SOUND_MIXER_READ_SPEAKER = SOUND_MIXER_READ_SPEAKER; +unsigned IOCTL_SOUND_MIXER_READ_STEREODEVS = SOUND_MIXER_READ_STEREODEVS; +unsigned IOCTL_SOUND_MIXER_READ_SYNTH = SOUND_MIXER_READ_SYNTH; +unsigned IOCTL_SOUND_MIXER_READ_TREBLE = SOUND_MIXER_READ_TREBLE; +unsigned IOCTL_SOUND_MIXER_READ_VOLUME = SOUND_MIXER_READ_VOLUME; +unsigned IOCTL_SOUND_MIXER_WRITE_ALTPCM = SOUND_MIXER_WRITE_ALTPCM; +unsigned IOCTL_SOUND_MIXER_WRITE_BASS = SOUND_MIXER_WRITE_BASS; +unsigned IOCTL_SOUND_MIXER_WRITE_CD = SOUND_MIXER_WRITE_CD; +unsigned IOCTL_SOUND_MIXER_WRITE_ENHANCE = SOUND_MIXER_WRITE_ENHANCE; +unsigned IOCTL_SOUND_MIXER_WRITE_IGAIN = SOUND_MIXER_WRITE_IGAIN; +unsigned IOCTL_SOUND_MIXER_WRITE_IMIX = SOUND_MIXER_WRITE_IMIX; +unsigned IOCTL_SOUND_MIXER_WRITE_LINE = SOUND_MIXER_WRITE_LINE; +unsigned IOCTL_SOUND_MIXER_WRITE_LINE1 = SOUND_MIXER_WRITE_LINE1; +unsigned IOCTL_SOUND_MIXER_WRITE_LINE2 = SOUND_MIXER_WRITE_LINE2; +unsigned IOCTL_SOUND_MIXER_WRITE_LINE3 = SOUND_MIXER_WRITE_LINE3; +unsigned IOCTL_SOUND_MIXER_WRITE_LOUD = SOUND_MIXER_WRITE_LOUD; +unsigned IOCTL_SOUND_MIXER_WRITE_MIC = SOUND_MIXER_WRITE_MIC; +unsigned IOCTL_SOUND_MIXER_WRITE_MUTE = SOUND_MIXER_WRITE_MUTE; +unsigned IOCTL_SOUND_MIXER_WRITE_OGAIN = SOUND_MIXER_WRITE_OGAIN; +unsigned IOCTL_SOUND_MIXER_WRITE_PCM = SOUND_MIXER_WRITE_PCM; +unsigned IOCTL_SOUND_MIXER_WRITE_RECLEV = SOUND_MIXER_WRITE_RECLEV; +unsigned IOCTL_SOUND_MIXER_WRITE_RECSRC = SOUND_MIXER_WRITE_RECSRC; +unsigned IOCTL_SOUND_MIXER_WRITE_SPEAKER = SOUND_MIXER_WRITE_SPEAKER; +unsigned IOCTL_SOUND_MIXER_WRITE_SYNTH = SOUND_MIXER_WRITE_SYNTH; +unsigned IOCTL_SOUND_MIXER_WRITE_TREBLE = SOUND_MIXER_WRITE_TREBLE; +unsigned IOCTL_SOUND_MIXER_WRITE_VOLUME = SOUND_MIXER_WRITE_VOLUME; +unsigned IOCTL_VT_ACTIVATE = VT_ACTIVATE; +unsigned IOCTL_VT_GETMODE = VT_GETMODE; +unsigned IOCTL_VT_OPENQRY = VT_OPENQRY; +unsigned IOCTL_VT_RELDISP = VT_RELDISP; +unsigned IOCTL_VT_SETMODE = VT_SETMODE; +unsigned IOCTL_VT_WAITACTIVE = VT_WAITACTIVE; +unsigned IOCTL_GIO_SCRNMAP = GIO_SCRNMAP; +unsigned IOCTL_KDDISABIO = KDDISABIO; +unsigned IOCTL_KDENABIO = KDENABIO; +unsigned IOCTL_KDGETLED = KDGETLED; +unsigned IOCTL_KDGETMODE = KDGETMODE; +unsigned IOCTL_KDGKBMODE = KDGKBMODE; +unsigned IOCTL_KDGKBTYPE = KDGKBTYPE; +unsigned IOCTL_KDMKTONE = KDMKTONE; +unsigned IOCTL_KDSETLED = KDSETLED; +unsigned IOCTL_KDSETMODE = KDSETMODE; +unsigned IOCTL_KDSKBMODE = KDSKBMODE; +unsigned IOCTL_KIOCSOUND = KIOCSOUND; +unsigned IOCTL_PIO_SCRNMAP = PIO_SCRNMAP; +unsigned IOCTL_SNDCTL_DSP_GETISPACE = SNDCTL_DSP_GETISPACE; + +const int si_SEGV_MAPERR = SEGV_MAPERR; +const int si_SEGV_ACCERR = SEGV_ACCERR; +const int unvis_valid = UNVIS_VALID; +const int unvis_validpush = UNVIS_VALIDPUSH; + +const unsigned MD5_CTX_sz = sizeof(MD5_CTX); +const unsigned MD5_return_length = MD5_DIGEST_STRING_LENGTH; + +#define SHA2_CONST(LEN) \ + const unsigned SHA##LEN##_CTX_sz = sizeof(SHA##LEN##_CTX); \ + const unsigned SHA##LEN##_return_length = SHA##LEN##_DIGEST_STRING_LENGTH; \ + const unsigned SHA##LEN##_block_length = SHA##LEN##_BLOCK_LENGTH; \ + const unsigned SHA##LEN##_digest_length = SHA##LEN##_DIGEST_LENGTH + +SHA2_CONST(224); +SHA2_CONST(256); +SHA2_CONST(384); +SHA2_CONST(512); + +#undef SHA2_CONST +} // namespace __sanitizer + +using namespace __sanitizer; + +COMPILER_CHECK(sizeof(__sanitizer_pthread_attr_t) >= sizeof(pthread_attr_t)); + +COMPILER_CHECK(sizeof(socklen_t) == sizeof(unsigned)); +CHECK_TYPE_SIZE(pthread_key_t); + +// There are more undocumented fields in dl_phdr_info that we are not interested +// in. +COMPILER_CHECK(sizeof(__sanitizer_dl_phdr_info) <= sizeof(dl_phdr_info)); +CHECK_SIZE_AND_OFFSET(dl_phdr_info, dlpi_addr); +CHECK_SIZE_AND_OFFSET(dl_phdr_info, dlpi_name); +CHECK_SIZE_AND_OFFSET(dl_phdr_info, dlpi_phdr); +CHECK_SIZE_AND_OFFSET(dl_phdr_info, dlpi_phnum); + +CHECK_TYPE_SIZE(glob_t); +CHECK_SIZE_AND_OFFSET(glob_t, gl_pathc); +CHECK_SIZE_AND_OFFSET(glob_t, gl_pathv); +CHECK_SIZE_AND_OFFSET(glob_t, gl_offs); +CHECK_SIZE_AND_OFFSET(glob_t, gl_flags); +CHECK_SIZE_AND_OFFSET(glob_t, gl_closedir); +CHECK_SIZE_AND_OFFSET(glob_t, gl_readdir); +CHECK_SIZE_AND_OFFSET(glob_t, gl_opendir); +CHECK_SIZE_AND_OFFSET(glob_t, gl_lstat); +CHECK_SIZE_AND_OFFSET(glob_t, gl_stat); + +CHECK_TYPE_SIZE(addrinfo); +CHECK_SIZE_AND_OFFSET(addrinfo, ai_flags); +CHECK_SIZE_AND_OFFSET(addrinfo, ai_family); +CHECK_SIZE_AND_OFFSET(addrinfo, ai_socktype); +CHECK_SIZE_AND_OFFSET(addrinfo, ai_protocol); +CHECK_SIZE_AND_OFFSET(addrinfo, ai_protocol); +CHECK_SIZE_AND_OFFSET(addrinfo, ai_addrlen); +CHECK_SIZE_AND_OFFSET(addrinfo, ai_canonname); +CHECK_SIZE_AND_OFFSET(addrinfo, ai_addr); + +CHECK_TYPE_SIZE(hostent); +CHECK_SIZE_AND_OFFSET(hostent, h_name); +CHECK_SIZE_AND_OFFSET(hostent, h_aliases); +CHECK_SIZE_AND_OFFSET(hostent, h_addrtype); +CHECK_SIZE_AND_OFFSET(hostent, h_length); +CHECK_SIZE_AND_OFFSET(hostent, h_addr_list); + +CHECK_TYPE_SIZE(iovec); +CHECK_SIZE_AND_OFFSET(iovec, iov_base); +CHECK_SIZE_AND_OFFSET(iovec, iov_len); + +CHECK_TYPE_SIZE(msghdr); +CHECK_SIZE_AND_OFFSET(msghdr, msg_name); +CHECK_SIZE_AND_OFFSET(msghdr, msg_namelen); +CHECK_SIZE_AND_OFFSET(msghdr, msg_iov); +CHECK_SIZE_AND_OFFSET(msghdr, msg_iovlen); +CHECK_SIZE_AND_OFFSET(msghdr, msg_control); +CHECK_SIZE_AND_OFFSET(msghdr, msg_controllen); +CHECK_SIZE_AND_OFFSET(msghdr, msg_flags); + +CHECK_TYPE_SIZE(cmsghdr); +CHECK_SIZE_AND_OFFSET(cmsghdr, cmsg_len); +CHECK_SIZE_AND_OFFSET(cmsghdr, cmsg_level); +CHECK_SIZE_AND_OFFSET(cmsghdr, cmsg_type); + +COMPILER_CHECK(sizeof(__sanitizer_dirent) <= sizeof(dirent)); +CHECK_SIZE_AND_OFFSET(dirent, d_ino); +CHECK_SIZE_AND_OFFSET(dirent, d_reclen); + +CHECK_TYPE_SIZE(ifconf); +CHECK_SIZE_AND_OFFSET(ifconf, ifc_len); +CHECK_SIZE_AND_OFFSET(ifconf, ifc_ifcu); + +CHECK_TYPE_SIZE(pollfd); +CHECK_SIZE_AND_OFFSET(pollfd, fd); +CHECK_SIZE_AND_OFFSET(pollfd, events); +CHECK_SIZE_AND_OFFSET(pollfd, revents); + +CHECK_TYPE_SIZE(nfds_t); + +CHECK_TYPE_SIZE(sigset_t); + +COMPILER_CHECK(sizeof(__sanitizer_sigaction) == sizeof(struct sigaction)); +// Can't write checks for sa_handler and sa_sigaction due to them being +// preprocessor macros. +CHECK_STRUCT_SIZE_AND_OFFSET(sigaction, sa_mask); + +CHECK_TYPE_SIZE(wordexp_t); +CHECK_SIZE_AND_OFFSET(wordexp_t, we_wordc); +CHECK_SIZE_AND_OFFSET(wordexp_t, we_wordv); +CHECK_SIZE_AND_OFFSET(wordexp_t, we_offs); + +CHECK_TYPE_SIZE(tm); +CHECK_SIZE_AND_OFFSET(tm, tm_sec); +CHECK_SIZE_AND_OFFSET(tm, tm_min); +CHECK_SIZE_AND_OFFSET(tm, tm_hour); +CHECK_SIZE_AND_OFFSET(tm, tm_mday); +CHECK_SIZE_AND_OFFSET(tm, tm_mon); +CHECK_SIZE_AND_OFFSET(tm, tm_year); +CHECK_SIZE_AND_OFFSET(tm, tm_wday); +CHECK_SIZE_AND_OFFSET(tm, tm_yday); +CHECK_SIZE_AND_OFFSET(tm, tm_isdst); +CHECK_SIZE_AND_OFFSET(tm, tm_gmtoff); +CHECK_SIZE_AND_OFFSET(tm, tm_zone); + +CHECK_TYPE_SIZE(ether_addr); + +CHECK_TYPE_SIZE(ipc_perm); +CHECK_SIZE_AND_OFFSET(ipc_perm, key); +CHECK_SIZE_AND_OFFSET(ipc_perm, seq); +CHECK_SIZE_AND_OFFSET(ipc_perm, uid); +CHECK_SIZE_AND_OFFSET(ipc_perm, gid); +CHECK_SIZE_AND_OFFSET(ipc_perm, cuid); +CHECK_SIZE_AND_OFFSET(ipc_perm, cgid); + +CHECK_TYPE_SIZE(shmid_ds); +CHECK_SIZE_AND_OFFSET(shmid_ds, shm_perm); +CHECK_SIZE_AND_OFFSET(shmid_ds, shm_segsz); +CHECK_SIZE_AND_OFFSET(shmid_ds, shm_atime); +CHECK_SIZE_AND_OFFSET(shmid_ds, shm_dtime); +CHECK_SIZE_AND_OFFSET(shmid_ds, shm_ctime); +CHECK_SIZE_AND_OFFSET(shmid_ds, shm_cpid); +CHECK_SIZE_AND_OFFSET(shmid_ds, shm_lpid); +CHECK_SIZE_AND_OFFSET(shmid_ds, shm_nattch); + +CHECK_TYPE_SIZE(clock_t); + +CHECK_TYPE_SIZE(ifaddrs); +CHECK_SIZE_AND_OFFSET(ifaddrs, ifa_next); +CHECK_SIZE_AND_OFFSET(ifaddrs, ifa_name); +CHECK_SIZE_AND_OFFSET(ifaddrs, ifa_addr); +CHECK_SIZE_AND_OFFSET(ifaddrs, ifa_netmask); +#undef ifa_dstaddr +CHECK_SIZE_AND_OFFSET(ifaddrs, ifa_dstaddr); +CHECK_SIZE_AND_OFFSET(ifaddrs, ifa_data); + +CHECK_TYPE_SIZE(timeb); +CHECK_SIZE_AND_OFFSET(timeb, time); +CHECK_SIZE_AND_OFFSET(timeb, millitm); +CHECK_SIZE_AND_OFFSET(timeb, timezone); +CHECK_SIZE_AND_OFFSET(timeb, dstflag); + +CHECK_TYPE_SIZE(passwd); +CHECK_SIZE_AND_OFFSET(passwd, pw_name); +CHECK_SIZE_AND_OFFSET(passwd, pw_passwd); +CHECK_SIZE_AND_OFFSET(passwd, pw_uid); +CHECK_SIZE_AND_OFFSET(passwd, pw_gid); +CHECK_SIZE_AND_OFFSET(passwd, pw_dir); +CHECK_SIZE_AND_OFFSET(passwd, pw_shell); + +CHECK_SIZE_AND_OFFSET(passwd, pw_gecos); + +CHECK_TYPE_SIZE(group); +CHECK_SIZE_AND_OFFSET(group, gr_name); +CHECK_SIZE_AND_OFFSET(group, gr_passwd); +CHECK_SIZE_AND_OFFSET(group, gr_gid); +CHECK_SIZE_AND_OFFSET(group, gr_mem); + +#if HAVE_RPC_XDR_H +CHECK_TYPE_SIZE(XDR); +CHECK_SIZE_AND_OFFSET(XDR, x_op); +CHECK_SIZE_AND_OFFSET(XDR, x_ops); +CHECK_SIZE_AND_OFFSET(XDR, x_public); +CHECK_SIZE_AND_OFFSET(XDR, x_private); +CHECK_SIZE_AND_OFFSET(XDR, x_base); +CHECK_SIZE_AND_OFFSET(XDR, x_handy); +COMPILER_CHECK(__sanitizer_XDR_ENCODE == XDR_ENCODE); +COMPILER_CHECK(__sanitizer_XDR_DECODE == XDR_DECODE); +COMPILER_CHECK(__sanitizer_XDR_FREE == XDR_FREE); +#endif + +CHECK_TYPE_SIZE(sem_t); + +COMPILER_CHECK(sizeof(__sanitizer_cap_rights_t) >= sizeof(cap_rights_t)); +#endif // SANITIZER_FREEBSD diff --git a/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_platform_limits_freebsd.h b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_platform_limits_freebsd.h new file mode 100644 index 0000000000..9859c52ec6 --- /dev/null +++ b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_platform_limits_freebsd.h @@ -0,0 +1,698 @@ +//===-- sanitizer_platform_limits_freebsd.h -------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file is a part of Sanitizer common code. +// +// Sizes and layouts of platform-specific FreeBSD data structures. +//===----------------------------------------------------------------------===// + +#ifndef SANITIZER_PLATFORM_LIMITS_FREEBSD_H +#define SANITIZER_PLATFORM_LIMITS_FREEBSD_H + +#if SANITIZER_FREEBSD + +# include "sanitizer_internal_defs.h" +# include "sanitizer_platform.h" +# include "sanitizer_platform_limits_posix.h" + +// Get sys/_types.h, because that tells us whether 64-bit inodes are +// used in struct dirent below. +# include <sys/_types.h> + +namespace __sanitizer { +void *__sanitizer_get_link_map_by_dlopen_handle(void *handle); +# define GET_LINK_MAP_BY_DLOPEN_HANDLE(handle) \ + (link_map *)__sanitizer_get_link_map_by_dlopen_handle(handle) + +extern unsigned struct_utsname_sz; +extern unsigned struct_stat_sz; +# if defined(__powerpc64__) +const unsigned struct___old_kernel_stat_sz = 0; +# else +const unsigned struct___old_kernel_stat_sz = 32; +# endif +extern unsigned struct_rusage_sz; +extern unsigned siginfo_t_sz; +extern unsigned struct_itimerval_sz; +extern unsigned pthread_t_sz; +extern unsigned pthread_mutex_t_sz; +extern unsigned pthread_cond_t_sz; +extern unsigned pid_t_sz; +extern unsigned timeval_sz; +extern unsigned uid_t_sz; +extern unsigned gid_t_sz; +extern unsigned fpos_t_sz; +extern unsigned mbstate_t_sz; +extern unsigned struct_timezone_sz; +extern unsigned struct_tms_sz; +extern unsigned struct_itimerspec_sz; +extern unsigned struct_sigevent_sz; +extern unsigned struct_stack_t_sz; +extern unsigned struct_sched_param_sz; +extern unsigned struct_statfs64_sz; +extern unsigned struct_statfs_sz; +extern unsigned struct_sockaddr_sz; +unsigned ucontext_t_sz(void *ctx); +extern unsigned struct_rlimit_sz; +extern unsigned struct_utimbuf_sz; +extern unsigned struct_timespec_sz; +extern unsigned struct_regmatch_sz; +extern unsigned struct_regex_sz; +extern unsigned struct_FTS_sz; +extern unsigned struct_FTSENT_sz; +extern const int unvis_valid; +extern const int unvis_validpush; + +struct __sanitizer_iocb { + u64 aio_data; + u32 aio_key_or_aio_reserved1; // Simply crazy. + u32 aio_reserved1_or_aio_key; // Luckily, we don't need these. + u16 aio_lio_opcode; + s16 aio_reqprio; + u32 aio_fildes; + u64 aio_buf; + u64 aio_nbytes; + s64 aio_offset; + u64 aio_reserved2; + u64 aio_reserved3; +}; + +struct __sanitizer_io_event { + u64 data; + u64 obj; + u64 res; + u64 res2; +}; + +const unsigned iocb_cmd_pread = 0; +const unsigned iocb_cmd_pwrite = 1; +const unsigned iocb_cmd_preadv = 7; +const unsigned iocb_cmd_pwritev = 8; + +struct __sanitizer___sysctl_args { + int *name; + int nlen; + void *oldval; + uptr *oldlenp; + void *newval; + uptr newlen; + unsigned long ___unused[4]; +}; + +struct __sanitizer_ipc_perm { + unsigned int cuid; + unsigned int cgid; + unsigned int uid; + unsigned int gid; + unsigned short mode; + unsigned short seq; + long key; +}; + +struct __sanitizer_protoent { + char *p_name; + char **p_aliases; + int p_proto; +}; + +struct __sanitizer_netent { + char *n_name; + char **n_aliases; + int n_addrtype; + u32 n_net; +}; + +# if !defined(__i386__) +typedef long long __sanitizer_time_t; +# else +typedef long __sanitizer_time_t; +# endif + +struct __sanitizer_shmid_ds { + __sanitizer_ipc_perm shm_perm; + unsigned long shm_segsz; + unsigned int shm_lpid; + unsigned int shm_cpid; + int shm_nattch; + __sanitizer_time_t shm_atime; + __sanitizer_time_t shm_dtime; + __sanitizer_time_t shm_ctime; +}; + +extern unsigned struct_msqid_ds_sz; +extern unsigned struct_mq_attr_sz; +extern unsigned struct_timeb_sz; +extern unsigned struct_statvfs_sz; + +struct __sanitizer_iovec { + void *iov_base; + uptr iov_len; +}; + +struct __sanitizer_ifaddrs { + struct __sanitizer_ifaddrs *ifa_next; + char *ifa_name; + unsigned int ifa_flags; + void *ifa_addr; // (struct sockaddr *) + void *ifa_netmask; // (struct sockaddr *) +# undef ifa_dstaddr + void *ifa_dstaddr; // (struct sockaddr *) + void *ifa_data; +}; + +typedef unsigned __sanitizer_pthread_key_t; + +struct __sanitizer_passwd { + char *pw_name; + char *pw_passwd; + int pw_uid; + int pw_gid; + __sanitizer_time_t pw_change; + char *pw_class; + char *pw_gecos; + char *pw_dir; + char *pw_shell; + __sanitizer_time_t pw_expire; + int pw_fields; +}; + +struct __sanitizer_group { + char *gr_name; + char *gr_passwd; + int gr_gid; + char **gr_mem; +}; + +typedef long __sanitizer_suseconds_t; + +struct __sanitizer_timeval { + __sanitizer_time_t tv_sec; + __sanitizer_suseconds_t tv_usec; +}; + +struct __sanitizer_itimerval { + struct __sanitizer_timeval it_interval; + struct __sanitizer_timeval it_value; +}; + +struct __sanitizer_timeb { + __sanitizer_time_t time; + unsigned short millitm; + short timezone; + short dstflag; +}; + +struct __sanitizer_ether_addr { + u8 octet[6]; +}; + +struct __sanitizer_tm { + int tm_sec; + int tm_min; + int tm_hour; + int tm_mday; + int tm_mon; + int tm_year; + int tm_wday; + int tm_yday; + int tm_isdst; + long int tm_gmtoff; + const char *tm_zone; +}; + +struct __sanitizer_msghdr { + void *msg_name; + unsigned msg_namelen; + struct __sanitizer_iovec *msg_iov; + unsigned msg_iovlen; + void *msg_control; + unsigned msg_controllen; + int msg_flags; +}; + +struct __sanitizer_cmsghdr { + unsigned cmsg_len; + int cmsg_level; + int cmsg_type; +}; + +struct __sanitizer_dirent { +# if defined(__INO64) + unsigned long long d_fileno; + unsigned long long d_off; +# else + unsigned int d_fileno; +# endif + unsigned short d_reclen; + // more fields that we don't care about +}; + +// 'clock_t' is 32 bits wide on x64 FreeBSD +typedef int __sanitizer_clock_t; +typedef int __sanitizer_clockid_t; + +# if defined(_LP64) || defined(__x86_64__) || defined(__powerpc__) || \ + defined(__mips__) +typedef unsigned __sanitizer___kernel_uid_t; +typedef unsigned __sanitizer___kernel_gid_t; +# else +typedef unsigned short __sanitizer___kernel_uid_t; +typedef unsigned short __sanitizer___kernel_gid_t; +# endif +typedef long long __sanitizer___kernel_off_t; + +# if defined(__powerpc__) || defined(__mips__) +typedef unsigned int __sanitizer___kernel_old_uid_t; +typedef unsigned int __sanitizer___kernel_old_gid_t; +# else +typedef unsigned short __sanitizer___kernel_old_uid_t; +typedef unsigned short __sanitizer___kernel_old_gid_t; +# endif + +typedef long long __sanitizer___kernel_loff_t; +typedef struct { + unsigned long fds_bits[1024 / (8 * sizeof(long))]; +} __sanitizer___kernel_fd_set; + +// This thing depends on the platform. We are only interested in the upper +// limit. Verified with a compiler assert in .cpp. +union __sanitizer_pthread_attr_t { + char size[128]; + void *align; +}; + +const unsigned old_sigset_t_sz = sizeof(unsigned long); + +struct __sanitizer_sigset_t { + // uint32_t * 4 + unsigned int __bits[4]; +}; + +typedef __sanitizer_sigset_t __sanitizer_kernel_sigset_t; + +struct __sanitizer_siginfo { + // The size is determined by looking at sizeof of real siginfo_t on linux. + u64 opaque[128 / sizeof(u64)]; +}; + +using __sanitizer_sighandler_ptr = void (*)(int sig); +using __sanitizer_sigactionhandler_ptr = void (*)(int sig, + __sanitizer_siginfo *siginfo, + void *uctx); + +struct __sanitizer_sigaction { + union { + __sanitizer_sigactionhandler_ptr sigaction; + __sanitizer_sighandler_ptr handler; + }; + int sa_flags; + __sanitizer_sigset_t sa_mask; +}; + +struct __sanitizer_sem_t { + u32 data[4]; +}; + +extern const uptr sig_ign; +extern const uptr sig_dfl; +extern const uptr sig_err; +extern const uptr sa_siginfo; + +extern int af_inet; +extern int af_inet6; +uptr __sanitizer_in_addr_sz(int af); + +struct __sanitizer_dl_phdr_info { + uptr dlpi_addr; + const char *dlpi_name; + const void *dlpi_phdr; + short dlpi_phnum; +}; + +extern unsigned struct_ElfW_Phdr_sz; + +struct __sanitizer_addrinfo { + int ai_flags; + int ai_family; + int ai_socktype; + int ai_protocol; + unsigned ai_addrlen; + char *ai_canonname; + void *ai_addr; + struct __sanitizer_addrinfo *ai_next; +}; + +struct __sanitizer_hostent { + char *h_name; + char **h_aliases; + int h_addrtype; + int h_length; + char **h_addr_list; +}; + +struct __sanitizer_pollfd { + int fd; + short events; + short revents; +}; + +typedef unsigned __sanitizer_nfds_t; + +struct __sanitizer_glob_t { + uptr gl_pathc; + uptr gl_matchc; + uptr gl_offs; + int gl_flags; + char **gl_pathv; + int (*gl_errfunc)(const char *, int); + void (*gl_closedir)(void *dirp); + struct dirent *(*gl_readdir)(void *dirp); + void *(*gl_opendir)(const char *); + int (*gl_lstat)(const char *, void * /* struct stat* */); + int (*gl_stat)(const char *, void * /* struct stat* */); +}; + +extern int glob_nomatch; +extern int glob_altdirfunc; +extern const int wordexp_wrde_dooffs; + +extern unsigned path_max; + +extern int struct_ttyent_sz; + +struct __sanitizer_wordexp_t { + uptr we_wordc; + char **we_wordv; + uptr we_offs; + char *we_strings; + uptr we_nbytes; +}; + +typedef void __sanitizer_FILE; + +extern unsigned struct_shminfo_sz; +extern unsigned struct_shm_info_sz; +extern int shmctl_ipc_stat; +extern int shmctl_ipc_info; +extern int shmctl_shm_info; +extern int shmctl_shm_stat; + +extern unsigned struct_utmpx_sz; + +extern int map_fixed; + +// ioctl arguments +struct __sanitizer_ifconf { + int ifc_len; + union { + void *ifcu_req; + } ifc_ifcu; +}; + +struct __sanitizer__ttyent { + char *ty_name; + char *ty_getty; + char *ty_type; + int ty_status; + char *ty_window; + char *ty_comment; + char *ty_group; +}; + +# define IOC_NRBITS 8 +# define IOC_TYPEBITS 8 +# if defined(__powerpc__) || defined(__powerpc64__) || defined(__mips__) +# define IOC_SIZEBITS 13 +# define IOC_DIRBITS 3 +# define IOC_NONE 1U +# define IOC_WRITE 4U +# define IOC_READ 2U +# else +# define IOC_SIZEBITS 14 +# define IOC_DIRBITS 2 +# define IOC_NONE 0U +# define IOC_WRITE 1U +# define IOC_READ 2U +# endif +# define IOC_NRMASK ((1 << IOC_NRBITS) - 1) +# define IOC_TYPEMASK ((1 << IOC_TYPEBITS) - 1) +# define IOC_SIZEMASK ((1 << IOC_SIZEBITS) - 1) +# if defined(IOC_DIRMASK) +# undef IOC_DIRMASK +# endif +# define IOC_DIRMASK ((1 << IOC_DIRBITS) - 1) +# define IOC_NRSHIFT 0 +# define IOC_TYPESHIFT (IOC_NRSHIFT + IOC_NRBITS) +# define IOC_SIZESHIFT (IOC_TYPESHIFT + IOC_TYPEBITS) +# define IOC_DIRSHIFT (IOC_SIZESHIFT + IOC_SIZEBITS) +# define EVIOC_EV_MAX 0x1f +# define EVIOC_ABS_MAX 0x3f + +# define IOC_DIR(nr) (((nr) >> IOC_DIRSHIFT) & IOC_DIRMASK) +# define IOC_TYPE(nr) (((nr) >> IOC_TYPESHIFT) & IOC_TYPEMASK) +# define IOC_NR(nr) (((nr) >> IOC_NRSHIFT) & IOC_NRMASK) +# define IOC_SIZE(nr) (((nr) >> IOC_SIZESHIFT) & IOC_SIZEMASK) + +extern unsigned struct_ifreq_sz; +extern unsigned struct_termios_sz; +extern unsigned struct_winsize_sz; + +extern unsigned struct_copr_buffer_sz; +extern unsigned struct_copr_debug_buf_sz; +extern unsigned struct_copr_msg_sz; +extern unsigned struct_midi_info_sz; +extern unsigned struct_mtget_sz; +extern unsigned struct_mtop_sz; +extern unsigned struct_rtentry_sz; +extern unsigned struct_sbi_instrument_sz; +extern unsigned struct_seq_event_rec_sz; +extern unsigned struct_synth_info_sz; +extern unsigned struct_vt_mode_sz; + +extern const unsigned long __sanitizer_bufsiz; +extern unsigned struct_audio_buf_info_sz; +extern unsigned struct_ppp_stats_sz; +extern unsigned struct_sioc_sg_req_sz; +extern unsigned struct_sioc_vif_req_sz; + +// ioctl request identifiers + +// A special value to mark ioctls that are not present on the target platform, +// when it can not be determined without including any system headers. +extern const unsigned IOCTL_NOT_PRESENT; + +extern unsigned IOCTL_FIOASYNC; +extern unsigned IOCTL_FIOCLEX; +extern unsigned IOCTL_FIOGETOWN; +extern unsigned IOCTL_FIONBIO; +extern unsigned IOCTL_FIONCLEX; +extern unsigned IOCTL_FIOSETOWN; +extern unsigned IOCTL_SIOCADDMULTI; +extern unsigned IOCTL_SIOCATMARK; +extern unsigned IOCTL_SIOCDELMULTI; +extern unsigned IOCTL_SIOCGIFADDR; +extern unsigned IOCTL_SIOCGIFBRDADDR; +extern unsigned IOCTL_SIOCGIFCONF; +extern unsigned IOCTL_SIOCGIFDSTADDR; +extern unsigned IOCTL_SIOCGIFFLAGS; +extern unsigned IOCTL_SIOCGIFMETRIC; +extern unsigned IOCTL_SIOCGIFMTU; +extern unsigned IOCTL_SIOCGIFNETMASK; +extern unsigned IOCTL_SIOCGPGRP; +extern unsigned IOCTL_SIOCSIFADDR; +extern unsigned IOCTL_SIOCSIFBRDADDR; +extern unsigned IOCTL_SIOCSIFDSTADDR; +extern unsigned IOCTL_SIOCSIFFLAGS; +extern unsigned IOCTL_SIOCSIFMETRIC; +extern unsigned IOCTL_SIOCSIFMTU; +extern unsigned IOCTL_SIOCSIFNETMASK; +extern unsigned IOCTL_SIOCSPGRP; +extern unsigned IOCTL_TIOCCONS; +extern unsigned IOCTL_TIOCEXCL; +extern unsigned IOCTL_TIOCGETD; +extern unsigned IOCTL_TIOCGPGRP; +extern unsigned IOCTL_TIOCGWINSZ; +extern unsigned IOCTL_TIOCMBIC; +extern unsigned IOCTL_TIOCMBIS; +extern unsigned IOCTL_TIOCMGET; +extern unsigned IOCTL_TIOCMSET; +extern unsigned IOCTL_TIOCNOTTY; +extern unsigned IOCTL_TIOCNXCL; +extern unsigned IOCTL_TIOCOUTQ; +extern unsigned IOCTL_TIOCPKT; +extern unsigned IOCTL_TIOCSCTTY; +extern unsigned IOCTL_TIOCSETD; +extern unsigned IOCTL_TIOCSPGRP; +extern unsigned IOCTL_TIOCSTI; +extern unsigned IOCTL_TIOCSWINSZ; +extern unsigned IOCTL_SIOCGETSGCNT; +extern unsigned IOCTL_SIOCGETVIFCNT; +extern unsigned IOCTL_MTIOCGET; +extern unsigned IOCTL_MTIOCTOP; +extern unsigned IOCTL_SIOCADDRT; +extern unsigned IOCTL_SIOCDELRT; +extern unsigned IOCTL_SNDCTL_DSP_GETBLKSIZE; +extern unsigned IOCTL_SNDCTL_DSP_GETFMTS; +extern unsigned IOCTL_SNDCTL_DSP_NONBLOCK; +extern unsigned IOCTL_SNDCTL_DSP_POST; +extern unsigned IOCTL_SNDCTL_DSP_RESET; +extern unsigned IOCTL_SNDCTL_DSP_SETFMT; +extern unsigned IOCTL_SNDCTL_DSP_SETFRAGMENT; +extern unsigned IOCTL_SNDCTL_DSP_SPEED; +extern unsigned IOCTL_SNDCTL_DSP_STEREO; +extern unsigned IOCTL_SNDCTL_DSP_SUBDIVIDE; +extern unsigned IOCTL_SNDCTL_DSP_SYNC; +extern unsigned IOCTL_SNDCTL_FM_4OP_ENABLE; +extern unsigned IOCTL_SNDCTL_FM_LOAD_INSTR; +extern unsigned IOCTL_SNDCTL_MIDI_INFO; +extern unsigned IOCTL_SNDCTL_MIDI_PRETIME; +extern unsigned IOCTL_SNDCTL_SEQ_CTRLRATE; +extern unsigned IOCTL_SNDCTL_SEQ_GETINCOUNT; +extern unsigned IOCTL_SNDCTL_SEQ_GETOUTCOUNT; +extern unsigned IOCTL_SNDCTL_SEQ_NRMIDIS; +extern unsigned IOCTL_SNDCTL_SEQ_NRSYNTHS; +extern unsigned IOCTL_SNDCTL_SEQ_OUTOFBAND; +extern unsigned IOCTL_SNDCTL_SEQ_PANIC; +extern unsigned IOCTL_SNDCTL_SEQ_PERCMODE; +extern unsigned IOCTL_SNDCTL_SEQ_RESET; +extern unsigned IOCTL_SNDCTL_SEQ_RESETSAMPLES; +extern unsigned IOCTL_SNDCTL_SEQ_SYNC; +extern unsigned IOCTL_SNDCTL_SEQ_TESTMIDI; +extern unsigned IOCTL_SNDCTL_SEQ_THRESHOLD; +extern unsigned IOCTL_SNDCTL_SYNTH_INFO; +extern unsigned IOCTL_SNDCTL_SYNTH_MEMAVL; +extern unsigned IOCTL_SNDCTL_TMR_CONTINUE; +extern unsigned IOCTL_SNDCTL_TMR_METRONOME; +extern unsigned IOCTL_SNDCTL_TMR_SELECT; +extern unsigned IOCTL_SNDCTL_TMR_SOURCE; +extern unsigned IOCTL_SNDCTL_TMR_START; +extern unsigned IOCTL_SNDCTL_TMR_STOP; +extern unsigned IOCTL_SNDCTL_TMR_TEMPO; +extern unsigned IOCTL_SNDCTL_TMR_TIMEBASE; +extern unsigned IOCTL_SOUND_MIXER_READ_ALTPCM; +extern unsigned IOCTL_SOUND_MIXER_READ_BASS; +extern unsigned IOCTL_SOUND_MIXER_READ_CAPS; +extern unsigned IOCTL_SOUND_MIXER_READ_CD; +extern unsigned IOCTL_SOUND_MIXER_READ_DEVMASK; +extern unsigned IOCTL_SOUND_MIXER_READ_ENHANCE; +extern unsigned IOCTL_SOUND_MIXER_READ_IGAIN; +extern unsigned IOCTL_SOUND_MIXER_READ_IMIX; +extern unsigned IOCTL_SOUND_MIXER_READ_LINE1; +extern unsigned IOCTL_SOUND_MIXER_READ_LINE2; +extern unsigned IOCTL_SOUND_MIXER_READ_LINE3; +extern unsigned IOCTL_SOUND_MIXER_READ_LINE; +extern unsigned IOCTL_SOUND_MIXER_READ_LOUD; +extern unsigned IOCTL_SOUND_MIXER_READ_MIC; +extern unsigned IOCTL_SOUND_MIXER_READ_MUTE; +extern unsigned IOCTL_SOUND_MIXER_READ_OGAIN; +extern unsigned IOCTL_SOUND_MIXER_READ_PCM; +extern unsigned IOCTL_SOUND_MIXER_READ_RECLEV; +extern unsigned IOCTL_SOUND_MIXER_READ_RECMASK; +extern unsigned IOCTL_SOUND_MIXER_READ_RECSRC; +extern unsigned IOCTL_SOUND_MIXER_READ_SPEAKER; +extern unsigned IOCTL_SOUND_MIXER_READ_STEREODEVS; +extern unsigned IOCTL_SOUND_MIXER_READ_SYNTH; +extern unsigned IOCTL_SOUND_MIXER_READ_TREBLE; +extern unsigned IOCTL_SOUND_MIXER_READ_VOLUME; +extern unsigned IOCTL_SOUND_MIXER_WRITE_ALTPCM; +extern unsigned IOCTL_SOUND_MIXER_WRITE_BASS; +extern unsigned IOCTL_SOUND_MIXER_WRITE_CD; +extern unsigned IOCTL_SOUND_MIXER_WRITE_ENHANCE; +extern unsigned IOCTL_SOUND_MIXER_WRITE_IGAIN; +extern unsigned IOCTL_SOUND_MIXER_WRITE_IMIX; +extern unsigned IOCTL_SOUND_MIXER_WRITE_LINE1; +extern unsigned IOCTL_SOUND_MIXER_WRITE_LINE2; +extern unsigned IOCTL_SOUND_MIXER_WRITE_LINE3; +extern unsigned IOCTL_SOUND_MIXER_WRITE_LINE; +extern unsigned IOCTL_SOUND_MIXER_WRITE_LOUD; +extern unsigned IOCTL_SOUND_MIXER_WRITE_MIC; +extern unsigned IOCTL_SOUND_MIXER_WRITE_MUTE; +extern unsigned IOCTL_SOUND_MIXER_WRITE_OGAIN; +extern unsigned IOCTL_SOUND_MIXER_WRITE_PCM; +extern unsigned IOCTL_SOUND_MIXER_WRITE_RECLEV; +extern unsigned IOCTL_SOUND_MIXER_WRITE_RECSRC; +extern unsigned IOCTL_SOUND_MIXER_WRITE_SPEAKER; +extern unsigned IOCTL_SOUND_MIXER_WRITE_SYNTH; +extern unsigned IOCTL_SOUND_MIXER_WRITE_TREBLE; +extern unsigned IOCTL_SOUND_MIXER_WRITE_VOLUME; +extern unsigned IOCTL_SOUND_PCM_READ_BITS; +extern unsigned IOCTL_SOUND_PCM_READ_CHANNELS; +extern unsigned IOCTL_SOUND_PCM_READ_FILTER; +extern unsigned IOCTL_SOUND_PCM_READ_RATE; +extern unsigned IOCTL_SOUND_PCM_WRITE_CHANNELS; +extern unsigned IOCTL_SOUND_PCM_WRITE_FILTER; +extern unsigned IOCTL_VT_ACTIVATE; +extern unsigned IOCTL_VT_GETMODE; +extern unsigned IOCTL_VT_OPENQRY; +extern unsigned IOCTL_VT_RELDISP; +extern unsigned IOCTL_VT_SETMODE; +extern unsigned IOCTL_VT_WAITACTIVE; +extern unsigned IOCTL_GIO_SCRNMAP; +extern unsigned IOCTL_KDDISABIO; +extern unsigned IOCTL_KDENABIO; +extern unsigned IOCTL_KDGETLED; +extern unsigned IOCTL_KDGETMODE; +extern unsigned IOCTL_KDGKBMODE; +extern unsigned IOCTL_KDGKBTYPE; +extern unsigned IOCTL_KDMKTONE; +extern unsigned IOCTL_KDSETLED; +extern unsigned IOCTL_KDSETMODE; +extern unsigned IOCTL_KDSKBMODE; + +extern const int si_SEGV_MAPERR; +extern const int si_SEGV_ACCERR; + +extern const unsigned MD5_CTX_sz; +extern const unsigned MD5_return_length; + +#define SHA2_EXTERN(LEN) \ + extern const unsigned SHA##LEN##_CTX_sz; \ + extern const unsigned SHA##LEN##_return_length; \ + extern const unsigned SHA##LEN##_block_length; \ + extern const unsigned SHA##LEN##_digest_length + +SHA2_EXTERN(224); +SHA2_EXTERN(256); +SHA2_EXTERN(384); +SHA2_EXTERN(512); + +#undef SHA2_EXTERN + +struct __sanitizer_cap_rights { + u64 cr_rights[2]; +}; + +typedef struct __sanitizer_cap_rights __sanitizer_cap_rights_t; +extern unsigned struct_cap_rights_sz; + +extern unsigned struct_fstab_sz; +extern unsigned struct_StringList_sz; +} // namespace __sanitizer + +# define CHECK_TYPE_SIZE(TYPE) \ + COMPILER_CHECK(sizeof(__sanitizer_##TYPE) == sizeof(TYPE)) + +# define CHECK_SIZE_AND_OFFSET(CLASS, MEMBER) \ + COMPILER_CHECK(sizeof(((__sanitizer_##CLASS *)NULL)->MEMBER) == \ + sizeof(((CLASS *)NULL)->MEMBER)); \ + COMPILER_CHECK(offsetof(__sanitizer_##CLASS, MEMBER) == \ + offsetof(CLASS, MEMBER)) + +// For sigaction, which is a function and struct at the same time, +// and thus requires explicit "struct" in sizeof() expression. +# define CHECK_STRUCT_SIZE_AND_OFFSET(CLASS, MEMBER) \ + COMPILER_CHECK(sizeof(((struct __sanitizer_##CLASS *)NULL)->MEMBER) == \ + sizeof(((struct CLASS *)NULL)->MEMBER)); \ + COMPILER_CHECK(offsetof(struct __sanitizer_##CLASS, MEMBER) == \ + offsetof(struct CLASS, MEMBER)) + +# define SIGACTION_SYMNAME sigaction + +#endif + +#endif // SANITIZER_FREEBSD diff --git a/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_platform_limits_linux.cpp b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_platform_limits_linux.cpp new file mode 100644 index 0000000000..9d577570ea --- /dev/null +++ b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_platform_limits_linux.cpp @@ -0,0 +1,108 @@ +//===-- sanitizer_platform_limits_linux.cpp -------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file is a part of Sanitizer common code. +// +// Sizes and layouts of linux kernel data structures. +//===----------------------------------------------------------------------===// + +// This is a separate compilation unit for linux headers that conflict with +// userspace headers. +// Most "normal" includes go in sanitizer_platform_limits_posix.cpp + +#include "sanitizer_platform.h" +#if SANITIZER_LINUX + +#include "sanitizer_internal_defs.h" +#include "sanitizer_platform_limits_posix.h" + +// For offsetof -> __builtin_offsetof definition. +#include <stddef.h> + +// With old kernels (and even new kernels on powerpc) asm/stat.h uses types that +// are not defined anywhere in userspace headers. Fake them. This seems to work +// fine with newer headers, too. +#include <linux/posix_types.h> +# if defined(__x86_64__) || defined(__mips__) || defined(__hexagon__) +# include <sys/stat.h> +# else +# define ino_t __kernel_ino_t +# define mode_t __kernel_mode_t +# define nlink_t __kernel_nlink_t +# define uid_t __kernel_uid_t +# define gid_t __kernel_gid_t +# define off_t __kernel_off_t +# define time_t __kernel_time_t +// This header seems to contain the definitions of _kernel_ stat* structs. +# include <asm/stat.h> +# undef ino_t +# undef mode_t +# undef nlink_t +# undef uid_t +# undef gid_t +# undef off_t +# endif + +# include <linux/aio_abi.h> + +# if !SANITIZER_ANDROID +# include <sys/statfs.h> +# include <linux/perf_event.h> +# endif + +using namespace __sanitizer; + +namespace __sanitizer { +#if !SANITIZER_ANDROID + unsigned struct_statfs64_sz = sizeof(struct statfs64); +#endif +} // namespace __sanitizer + +# if !defined(__powerpc64__) && !defined(__x86_64__) && \ + !defined(__aarch64__) && !defined(__mips__) && !defined(__s390__) && \ + !defined(__sparc__) && !defined(__riscv) && !defined(__hexagon__) +COMPILER_CHECK(struct___old_kernel_stat_sz == sizeof(struct __old_kernel_stat)); +#endif + +COMPILER_CHECK(struct_kernel_stat_sz == sizeof(struct stat)); + +#if defined(__i386__) +COMPILER_CHECK(struct_kernel_stat64_sz == sizeof(struct stat64)); +#endif + +CHECK_TYPE_SIZE(io_event); +CHECK_SIZE_AND_OFFSET(io_event, data); +CHECK_SIZE_AND_OFFSET(io_event, obj); +CHECK_SIZE_AND_OFFSET(io_event, res); +CHECK_SIZE_AND_OFFSET(io_event, res2); + +#if !SANITIZER_ANDROID +COMPILER_CHECK(sizeof(struct __sanitizer_perf_event_attr) <= + sizeof(struct perf_event_attr)); +CHECK_SIZE_AND_OFFSET(perf_event_attr, type); +CHECK_SIZE_AND_OFFSET(perf_event_attr, size); +#endif + +COMPILER_CHECK(iocb_cmd_pread == IOCB_CMD_PREAD); +COMPILER_CHECK(iocb_cmd_pwrite == IOCB_CMD_PWRITE); +#if !SANITIZER_ANDROID +COMPILER_CHECK(iocb_cmd_preadv == IOCB_CMD_PREADV); +COMPILER_CHECK(iocb_cmd_pwritev == IOCB_CMD_PWRITEV); +#endif + +CHECK_TYPE_SIZE(iocb); +CHECK_SIZE_AND_OFFSET(iocb, aio_data); +// Skip aio_key, it's weird. +CHECK_SIZE_AND_OFFSET(iocb, aio_lio_opcode); +CHECK_SIZE_AND_OFFSET(iocb, aio_reqprio); +CHECK_SIZE_AND_OFFSET(iocb, aio_fildes); +CHECK_SIZE_AND_OFFSET(iocb, aio_buf); +CHECK_SIZE_AND_OFFSET(iocb, aio_nbytes); +CHECK_SIZE_AND_OFFSET(iocb, aio_offset); + +#endif // SANITIZER_LINUX diff --git a/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_platform_limits_netbsd.cpp b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_platform_limits_netbsd.cpp new file mode 100644 index 0000000000..076bfd0407 --- /dev/null +++ b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_platform_limits_netbsd.cpp @@ -0,0 +1,2740 @@ +//===-- sanitizer_platform_limits_netbsd.cpp ------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file is a part of Sanitizer common code. +// +// Sizes and layouts of platform-specific NetBSD data structures. +//===----------------------------------------------------------------------===// + +#include "sanitizer_platform.h" + +#if SANITIZER_NETBSD + +#define _KMEMUSER +#define RAY_DO_SIGLEV +#define __LEGACY_PT_LWPINFO + +// clang-format off +#include <sys/param.h> +#include <sys/types.h> +#include <sys/sysctl.h> +#include <sys/disk.h> +#include <sys/disklabel.h> +#include <sys/mount.h> +#error #include <sys/agpio.h> +#error #include <sys/ataio.h> +#error #include <sys/audioio.h> +#error #include <sys/cdbr.h> +#error #include <sys/cdio.h> +#error #include <sys/chio.h> +#error #include <sys/clockctl.h> +#error #include <sys/cpuio.h> +#error #include <sys/dkbad.h> +#error #include <sys/dkio.h> +#error #include <sys/drvctlio.h> +#error #include <sys/dvdio.h> +#error #include <sys/envsys.h> +#include <sys/event.h> +#error #include <sys/fdio.h> +#include <sys/filio.h> +#error #include <sys/gpio.h> +#include <sys/ioctl.h> +#error #include <sys/ioctl_compat.h> +#error #include <sys/joystick.h> +#error #include <sys/ksyms.h> +#error #include <sys/lua.h> +#error #include <sys/midiio.h> +#include <sys/mtio.h> +#error #include <sys/power.h> +#error #include <sys/radioio.h> +#error #include <sys/rndio.h> +#error #include <sys/scanio.h> +#error #include <sys/scsiio.h> +#include <sys/sockio.h> +#error #include <sys/timepps.h> +#include <sys/ttycom.h> +#error #include <sys/verified_exec.h> +#include <sys/videoio.h> +#error #include <sys/wdog.h> +#include <sys/event.h> +#include <sys/filio.h> +#include <sys/ipc.h> +#error #include <sys/ipmi.h> +#error #include <sys/kcov.h> +#include <sys/mman.h> +#include <sys/module.h> +#include <sys/mount.h> +#error #include <sys/mqueue.h> +#include <sys/msg.h> +#include <sys/mtio.h> +#include <sys/ptrace.h> + +// Compat for NetBSD < 9.99.30. +#ifndef PT_LWPSTATUS +#define PT_LWPSTATUS 24 +#endif +#ifndef PT_LWPNEXT +#define PT_LWPNEXT 25 +#endif + +#include <sys/resource.h> +#include <sys/sem.h> +#error #include <sys/scsiio.h> +#error #include <sys/sha1.h> +#error #include <sys/sha2.h> +#include <sys/shm.h> +#include <sys/signal.h> +#include <sys/socket.h> +#include <sys/sockio.h> +#include <sys/soundcard.h> +#include <sys/stat.h> +#include <sys/statvfs.h> +#include <sys/time.h> +#include <sys/timeb.h> +#include <sys/times.h> +#include <sys/timespec.h> +#include <sys/timex.h> +#include <sys/types.h> +#include <sys/ucontext.h> +#include <sys/utsname.h> +#error #include <altq/altq.h> +#error #include <altq/altq_afmap.h> +#error #include <altq/altq_blue.h> +#error #include <altq/altq_cbq.h> +#error #include <altq/altq_cdnr.h> +#error #include <altq/altq_fifoq.h> +#error #include <altq/altq_hfsc.h> +#error #include <altq/altq_jobs.h> +#error #include <altq/altq_priq.h> +#error #include <altq/altq_red.h> +#error #include <altq/altq_rio.h> +#error #include <altq/altq_wfq.h> +#include <arpa/inet.h> +#include <crypto/cryptodev.h> +#error #include <dev/apm/apmio.h> +#error #include <dev/dm/netbsd-dm.h> +#error #include <dev/dmover/dmover_io.h> +#error #include <dev/dtv/dtvio_demux.h> +#error #include <dev/dtv/dtvio_frontend.h> +#if !__NetBSD_Prereq__(9, 99, 26) +#error #include <dev/filemon/filemon.h> +#else +#define FILEMON_SET_FD _IOWR('S', 1, int) +#define FILEMON_SET_PID _IOWR('S', 2, pid_t) +#endif +#error #include <dev/hdaudio/hdaudioio.h> +#error #include <dev/hdmicec/hdmicecio.h> +#error #include <dev/hpc/hpcfbio.h> +#error #include <dev/i2o/iopio.h> +#error #include <dev/ic/athioctl.h> +#error #include <dev/ic/bt8xx.h> +#error #include <dev/ic/icp_ioctl.h> +#error #include <dev/ic/isp_ioctl.h> +#error #include <dev/ic/mlxio.h> +#error #include <dev/ic/qemufwcfgio.h> +#error #include <dev/ic/nvmeio.h> +#error #include <dev/ir/irdaio.h> +#error #include <dev/isa/isvio.h> +#error #include <dev/isa/wtreg.h> +#if __has_include(<dev/iscsi/iscsi_ioctl.h>) +#error #include <dev/iscsi/iscsi_ioctl.h> +#else +/* Fallback for MKISCSI=no */ + +typedef struct { + uint32_t status; + uint32_t session_id; + uint32_t connection_id; +} iscsi_conn_status_parameters_t; + +typedef struct { + uint32_t status; + uint16_t interface_version; + uint16_t major; + uint16_t minor; + uint8_t version_string[224]; +} iscsi_get_version_parameters_t; + +typedef struct { + uint32_t status; + uint32_t session_id; + uint32_t connection_id; + struct { + unsigned int immediate : 1; + } options; + uint64_t lun; + scsireq_t req; /* from <sys/scsiio.h> */ +} iscsi_iocommand_parameters_t; + +typedef enum { + ISCSI_AUTH_None = 0, + ISCSI_AUTH_CHAP = 1, + ISCSI_AUTH_KRB5 = 2, + ISCSI_AUTH_SRP = 3 +} iscsi_auth_types_t; + +typedef enum { + ISCSI_LOGINTYPE_DISCOVERY = 0, + ISCSI_LOGINTYPE_NOMAP = 1, + ISCSI_LOGINTYPE_MAP = 2 +} iscsi_login_session_type_t; + +typedef enum { ISCSI_DIGEST_None = 0, ISCSI_DIGEST_CRC32C = 1 } iscsi_digest_t; + +typedef enum { + ISCSI_SESSION_TERMINATED = 1, + ISCSI_CONNECTION_TERMINATED, + ISCSI_RECOVER_CONNECTION, + ISCSI_DRIVER_TERMINATING +} iscsi_event_t; + +typedef struct { + unsigned int mutual_auth : 1; + unsigned int is_secure : 1; + unsigned int auth_number : 4; + iscsi_auth_types_t auth_type[4]; +} iscsi_auth_info_t; + +typedef struct { + uint32_t status; + int socket; + struct { + unsigned int HeaderDigest : 1; + unsigned int DataDigest : 1; + unsigned int MaxConnections : 1; + unsigned int DefaultTime2Wait : 1; + unsigned int DefaultTime2Retain : 1; + unsigned int MaxRecvDataSegmentLength : 1; + unsigned int auth_info : 1; + unsigned int user_name : 1; + unsigned int password : 1; + unsigned int target_password : 1; + unsigned int TargetName : 1; + unsigned int TargetAlias : 1; + unsigned int ErrorRecoveryLevel : 1; + } is_present; + iscsi_auth_info_t auth_info; + iscsi_login_session_type_t login_type; + iscsi_digest_t HeaderDigest; + iscsi_digest_t DataDigest; + uint32_t session_id; + uint32_t connection_id; + uint32_t MaxRecvDataSegmentLength; + uint16_t MaxConnections; + uint16_t DefaultTime2Wait; + uint16_t DefaultTime2Retain; + uint16_t ErrorRecoveryLevel; + void *user_name; + void *password; + void *target_password; + void *TargetName; + void *TargetAlias; +} iscsi_login_parameters_t; + +typedef struct { + uint32_t status; + uint32_t session_id; +} iscsi_logout_parameters_t; + +typedef struct { + uint32_t status; + uint32_t event_id; +} iscsi_register_event_parameters_t; + +typedef struct { + uint32_t status; + uint32_t session_id; + uint32_t connection_id; +} iscsi_remove_parameters_t; + +typedef struct { + uint32_t status; + uint32_t session_id; + void *response_buffer; + uint32_t response_size; + uint32_t response_used; + uint32_t response_total; + uint8_t key[224]; +} iscsi_send_targets_parameters_t; + +typedef struct { + uint32_t status; + uint8_t InitiatorName[224]; + uint8_t InitiatorAlias[224]; + uint8_t ISID[6]; +} iscsi_set_node_name_parameters_t; + +typedef struct { + uint32_t status; + uint32_t event_id; + iscsi_event_t event_kind; + uint32_t session_id; + uint32_t connection_id; + uint32_t reason; +} iscsi_wait_event_parameters_t; + +#define ISCSI_GET_VERSION _IOWR(0, 1, iscsi_get_version_parameters_t) +#define ISCSI_LOGIN _IOWR(0, 2, iscsi_login_parameters_t) +#define ISCSI_LOGOUT _IOWR(0, 3, iscsi_logout_parameters_t) +#define ISCSI_ADD_CONNECTION _IOWR(0, 4, iscsi_login_parameters_t) +#define ISCSI_RESTORE_CONNECTION _IOWR(0, 5, iscsi_login_parameters_t) +#define ISCSI_REMOVE_CONNECTION _IOWR(0, 6, iscsi_remove_parameters_t) +#define ISCSI_CONNECTION_STATUS _IOWR(0, 7, iscsi_conn_status_parameters_t) +#define ISCSI_SEND_TARGETS _IOWR(0, 8, iscsi_send_targets_parameters_t) +#define ISCSI_SET_NODE_NAME _IOWR(0, 9, iscsi_set_node_name_parameters_t) +#define ISCSI_IO_COMMAND _IOWR(0, 10, iscsi_iocommand_parameters_t) +#define ISCSI_REGISTER_EVENT _IOWR(0, 11, iscsi_register_event_parameters_t) +#define ISCSI_DEREGISTER_EVENT _IOWR(0, 12, iscsi_register_event_parameters_t) +#define ISCSI_WAIT_EVENT _IOWR(0, 13, iscsi_wait_event_parameters_t) +#define ISCSI_POLL_EVENT _IOWR(0, 14, iscsi_wait_event_parameters_t) +#endif +#error #include <dev/ofw/openfirmio.h> +#error #include <dev/pci/amrio.h> +#error #include <dev/pci/mlyreg.h> +#error #include <dev/pci/mlyio.h> +#error #include <dev/pci/pciio.h> +#error #include <dev/pci/tweio.h> +#error #include <dev/pcmcia/if_cnwioctl.h> +#include <net/bpf.h> +#error #include <net/if_gre.h> +#error #include <net/ppp_defs.h> +#include <net/if_ppp.h> +#error #include <net/if_pppoe.h> +#error #include <net/if_sppp.h> +#error #include <net/if_srt.h> +#error #include <net/if_tap.h> +#error #include <net/if_tun.h> +#error #include <net/npf.h> +#include <net/pfvar.h> +#error #include <net/slip.h> +#error #include <netbt/hci.h> +#error #include <netinet/ip_compat.h> +#if __has_include(<netinet/ip_fil.h>) +#error #include <netinet/ip_fil.h> +#error #include <netinet/ip_nat.h> +#error #include <netinet/ip_proxy.h> +#else +/* Fallback for MKIPFILTER=no */ + +typedef struct ap_control { + char apc_label[16]; + char apc_config[16]; + unsigned char apc_p; + unsigned long apc_cmd; + unsigned long apc_arg; + void *apc_data; + size_t apc_dsize; +} ap_ctl_t; + +typedef struct ipftq { + ipfmutex_t ifq_lock; + unsigned int ifq_ttl; + void *ifq_head; + void **ifq_tail; + void *ifq_next; + void **ifq_pnext; + int ifq_ref; + unsigned int ifq_flags; +} ipftq_t; + +typedef struct ipfobj { + uint32_t ipfo_rev; + uint32_t ipfo_size; + void *ipfo_ptr; + int ipfo_type; + int ipfo_offset; + int ipfo_retval; + unsigned char ipfo_xxxpad[28]; +} ipfobj_t; + +#define SIOCADNAT _IOW('r', 60, struct ipfobj) +#define SIOCRMNAT _IOW('r', 61, struct ipfobj) +#define SIOCGNATS _IOWR('r', 62, struct ipfobj) +#define SIOCGNATL _IOWR('r', 63, struct ipfobj) +#define SIOCPURGENAT _IOWR('r', 100, struct ipfobj) +#endif +#error #include <netinet6/in6_var.h> +#error #include <netinet6/nd6.h> +#if !__NetBSD_Prereq__(9, 99, 51) +#error #include <netsmb/smb_dev.h> +#else +struct smbioc_flags { + int ioc_level; + int ioc_mask; + int ioc_flags; +}; +struct smbioc_oshare { + int ioc_opt; + int ioc_stype; + char ioc_share[129]; + char ioc_password[129]; + uid_t ioc_owner; + gid_t ioc_group; + mode_t ioc_mode; + mode_t ioc_rights; +}; +struct smbioc_ossn { + int ioc_opt; + uint32_t ioc_svlen; + struct sockaddr *ioc_server; + uint32_t ioc_lolen; + struct sockaddr *ioc_local; + char ioc_srvname[16]; + int ioc_timeout; + int ioc_retrycount; + char ioc_localcs[16]; + char ioc_servercs[16]; + char ioc_user[129]; + char ioc_workgroup[129]; + char ioc_password[129]; + uid_t ioc_owner; + gid_t ioc_group; + mode_t ioc_mode; + mode_t ioc_rights; +}; +struct smbioc_lookup { + int ioc_level; + int ioc_flags; + struct smbioc_ossn ioc_ssn; + struct smbioc_oshare ioc_sh; +}; +struct smbioc_rq { + u_char ioc_cmd; + u_char ioc_twc; + void *ioc_twords; + u_short ioc_tbc; + void *ioc_tbytes; + int ioc_rpbufsz; + char *ioc_rpbuf; + u_char ioc_rwc; + u_short ioc_rbc; +}; +struct smbioc_rw { + u_int16_t ioc_fh; + char *ioc_base; + off_t ioc_offset; + int ioc_cnt; +}; +#define SMBIOC_OPENSESSION _IOW('n', 100, struct smbioc_ossn) +#define SMBIOC_OPENSHARE _IOW('n', 101, struct smbioc_oshare) +#define SMBIOC_REQUEST _IOWR('n', 102, struct smbioc_rq) +#define SMBIOC_T2RQ _IOWR('n', 103, struct smbioc_t2rq) +#define SMBIOC_SETFLAGS _IOW('n', 104, struct smbioc_flags) +#define SMBIOC_LOOKUP _IOW('n', 106, struct smbioc_lookup) +#define SMBIOC_READ _IOWR('n', 107, struct smbioc_rw) +#define SMBIOC_WRITE _IOWR('n', 108, struct smbioc_rw) +#endif +#error #include <dev/biovar.h> +#error #include <dev/bluetooth/btdev.h> +#error #include <dev/bluetooth/btsco.h> +#error #include <dev/ccdvar.h> +#error #include <dev/cgdvar.h> +#error #include <dev/fssvar.h> +#error #include <dev/kttcpio.h> +#error #include <dev/lockstat.h> +#error #include <dev/md.h> +#error #include <net/if_ether.h> +#error #include <dev/pcmcia/if_rayreg.h> +#include <stdio.h> +#error #include <dev/raidframe/raidframeio.h> +#error #include <dev/sbus/mbppio.h> +#error #include <dev/scsipi/ses.h> +#error #include <dev/spi/spi_io.h> +#error #include <dev/spkrio.h> +#error #include <dev/sun/disklabel.h> +#error #include <dev/sun/fbio.h> +#error #include <dev/sun/kbio.h> +#error #include <dev/sun/vuid_event.h> +#error #include <dev/tc/sticio.h> +#error #include <dev/usb/ukyopon.h> +#if !__NetBSD_Prereq__(9, 99, 44) +#error #include <dev/usb/urio.h> +#else +struct urio_command { + unsigned short length; + int request; + int requesttype; + int value; + int index; + void *buffer; + int timeout; +}; +#define URIO_SEND_COMMAND _IOWR('U', 200, struct urio_command) +#define URIO_RECV_COMMAND _IOWR('U', 201, struct urio_command) +#endif +#error #include <dev/usb/usb.h> +#error #include <dev/usb/utoppy.h> +#error #include <dev/vme/xio.h> +#error #include <dev/vndvar.h> +#error #include <dev/wscons/wsconsio.h> +#error #include <dev/wscons/wsdisplay_usl_io.h> +#error #include <fs/autofs/autofs_ioctl.h> +#include <dirent.h> +#include <dlfcn.h> +#include <glob.h> +#include <grp.h> +#include <ifaddrs.h> +#include <limits.h> +#error #include <link_elf.h> +#include <net/if.h> +#include <net/route.h> +#include <netdb.h> +#include <netinet/in.h> +#error #include <netinet/ip_mroute.h> +#include <netinet/sctp_uio.h> +#include <poll.h> +#include <pthread.h> +#include <pwd.h> +#include <semaphore.h> +#include <signal.h> +#include <stddef.h> +#include <md2.h> +#include <md4.h> +#error #include <md5.h> +#error #include <rmd160.h> +#include <soundcard.h> +#include <term.h> +#include <termios.h> +#include <time.h> +#include <ttyent.h> +#include <utime.h> +#include <utmp.h> +#include <utmpx.h> +#include <vis.h> +#include <wchar.h> +#include <wordexp.h> +#include <ttyent.h> +#include <fts.h> +#include <regex.h> +#include <fstab.h> +#error #include <stringlist.h> + +#if defined(__x86_64__) +#error #include <nvmm.h> +#endif +// clang-format on + +// Include these after system headers to avoid name clashes and ambiguities. +#include "sanitizer_internal_defs.h" +#include "sanitizer_libc.h" +#include "sanitizer_platform_limits_netbsd.h" + +namespace __sanitizer { +void *__sanitizer_get_link_map_by_dlopen_handle(void *handle) { + void *p = nullptr; + return internal_dlinfo(handle, RTLD_DI_LINKMAP, &p) == 0 ? p : nullptr; +} + +unsigned struct_utsname_sz = sizeof(struct utsname); +unsigned struct_stat_sz = sizeof(struct stat); +unsigned struct_rusage_sz = sizeof(struct rusage); +unsigned struct_tm_sz = sizeof(struct tm); +unsigned struct_passwd_sz = sizeof(struct passwd); +unsigned struct_group_sz = sizeof(struct group); +unsigned siginfo_t_sz = sizeof(siginfo_t); +unsigned struct_sigaction_sz = sizeof(struct sigaction); +unsigned struct_stack_t_sz = sizeof(stack_t); +unsigned struct_itimerval_sz = sizeof(struct itimerval); +unsigned pthread_t_sz = sizeof(pthread_t); +unsigned pthread_mutex_t_sz = sizeof(pthread_mutex_t); +unsigned pthread_cond_t_sz = sizeof(pthread_cond_t); +unsigned pid_t_sz = sizeof(pid_t); +unsigned timeval_sz = sizeof(timeval); +unsigned uid_t_sz = sizeof(uid_t); +unsigned gid_t_sz = sizeof(gid_t); +unsigned mbstate_t_sz = sizeof(mbstate_t); +unsigned sigset_t_sz = sizeof(sigset_t); +unsigned struct_timezone_sz = sizeof(struct timezone); +unsigned struct_tms_sz = sizeof(struct tms); +unsigned struct_sigevent_sz = sizeof(struct sigevent); +unsigned struct_sched_param_sz = sizeof(struct sched_param); +unsigned struct_sockaddr_sz = sizeof(struct sockaddr); +unsigned ucontext_t_sz(void *ctx) { return sizeof(ucontext_t); } +unsigned struct_rlimit_sz = sizeof(struct rlimit); +unsigned struct_timespec_sz = sizeof(struct timespec); +unsigned struct_sembuf_sz = sizeof(struct sembuf); +unsigned struct_kevent_sz = sizeof(struct kevent); +unsigned struct_FTS_sz = sizeof(FTS); +unsigned struct_FTSENT_sz = sizeof(FTSENT); +unsigned struct_regex_sz = sizeof(regex_t); +unsigned struct_regmatch_sz = sizeof(regmatch_t); +unsigned struct_fstab_sz = sizeof(struct fstab); +unsigned struct_utimbuf_sz = sizeof(struct utimbuf); +unsigned struct_itimerspec_sz = sizeof(struct itimerspec); +unsigned struct_timex_sz = sizeof(struct timex); +unsigned struct_msqid_ds_sz = sizeof(struct msqid_ds); +unsigned struct_mq_attr_sz = sizeof(struct mq_attr); +unsigned struct_statvfs_sz = sizeof(struct statvfs); +unsigned struct_sigaltstack_sz = sizeof(stack_t); + +const uptr sig_ign = (uptr)SIG_IGN; +const uptr sig_dfl = (uptr)SIG_DFL; +const uptr sig_err = (uptr)SIG_ERR; +const uptr sa_siginfo = (uptr)SA_SIGINFO; + +const unsigned long __sanitizer_bufsiz = BUFSIZ; + +int ptrace_pt_io = PT_IO; +int ptrace_pt_lwpinfo = PT_LWPINFO; +int ptrace_pt_set_event_mask = PT_SET_EVENT_MASK; +int ptrace_pt_get_event_mask = PT_GET_EVENT_MASK; +int ptrace_pt_get_process_state = PT_GET_PROCESS_STATE; +int ptrace_pt_set_siginfo = PT_SET_SIGINFO; +int ptrace_pt_get_siginfo = PT_GET_SIGINFO; +int ptrace_pt_lwpstatus = PT_LWPSTATUS; +int ptrace_pt_lwpnext = PT_LWPNEXT; +int ptrace_piod_read_d = PIOD_READ_D; +int ptrace_piod_write_d = PIOD_WRITE_D; +int ptrace_piod_read_i = PIOD_READ_I; +int ptrace_piod_write_i = PIOD_WRITE_I; +int ptrace_piod_read_auxv = PIOD_READ_AUXV; + +#if defined(PT_SETREGS) && defined(PT_GETREGS) +int ptrace_pt_setregs = PT_SETREGS; +int ptrace_pt_getregs = PT_GETREGS; +#else +int ptrace_pt_setregs = -1; +int ptrace_pt_getregs = -1; +#endif + +#if defined(PT_SETFPREGS) && defined(PT_GETFPREGS) +int ptrace_pt_setfpregs = PT_SETFPREGS; +int ptrace_pt_getfpregs = PT_GETFPREGS; +#else +int ptrace_pt_setfpregs = -1; +int ptrace_pt_getfpregs = -1; +#endif + +#if defined(PT_SETDBREGS) && defined(PT_GETDBREGS) +int ptrace_pt_setdbregs = PT_SETDBREGS; +int ptrace_pt_getdbregs = PT_GETDBREGS; +#else +int ptrace_pt_setdbregs = -1; +int ptrace_pt_getdbregs = -1; +#endif + +unsigned struct_ptrace_ptrace_io_desc_struct_sz = sizeof(struct ptrace_io_desc); +unsigned struct_ptrace_ptrace_lwpinfo_struct_sz = sizeof(struct ptrace_lwpinfo); +unsigned struct_ptrace_ptrace_lwpstatus_struct_sz = + sizeof(struct __sanitizer_ptrace_lwpstatus); +unsigned struct_ptrace_ptrace_event_struct_sz = sizeof(ptrace_event_t); +unsigned struct_ptrace_ptrace_siginfo_struct_sz = sizeof(ptrace_siginfo_t); + +#if defined(PT_SETREGS) +unsigned struct_ptrace_reg_struct_sz = sizeof(struct reg); +#else +unsigned struct_ptrace_reg_struct_sz = -1; +#endif + +#if defined(PT_SETFPREGS) +unsigned struct_ptrace_fpreg_struct_sz = sizeof(struct fpreg); +#else +unsigned struct_ptrace_fpreg_struct_sz = -1; +#endif + +#if defined(PT_SETDBREGS) +unsigned struct_ptrace_dbreg_struct_sz = sizeof(struct dbreg); +#else +unsigned struct_ptrace_dbreg_struct_sz = -1; +#endif + +int shmctl_ipc_stat = (int)IPC_STAT; + +unsigned struct_utmp_sz = sizeof(struct utmp); +unsigned struct_utmpx_sz = sizeof(struct utmpx); + +int map_fixed = MAP_FIXED; + +int af_inet = (int)AF_INET; +int af_inet6 = (int)AF_INET6; + +uptr __sanitizer_in_addr_sz(int af) { + if (af == AF_INET) + return sizeof(struct in_addr); + else if (af == AF_INET6) + return sizeof(struct in6_addr); + else + return 0; +} + +unsigned struct_ElfW_Phdr_sz = sizeof(Elf_Phdr); + +int glob_nomatch = GLOB_NOMATCH; +int glob_altdirfunc = GLOB_ALTDIRFUNC; +const int wordexp_wrde_dooffs = WRDE_DOOFFS; + +unsigned path_max = PATH_MAX; + +int struct_ttyent_sz = sizeof(struct ttyent); + +struct __sanitizer_nvlist_ref_t { + void *buf; + uptr len; + int flags; +}; + +typedef __sanitizer_nvlist_ref_t nvlist_ref_t; + +// ioctl arguments +unsigned struct_altqreq_sz = sizeof(altqreq); +unsigned struct_amr_user_ioctl_sz = sizeof(amr_user_ioctl); +unsigned struct_ap_control_sz = sizeof(ap_control); +unsigned struct_apm_ctl_sz = sizeof(apm_ctl); +unsigned struct_apm_event_info_sz = sizeof(apm_event_info); +unsigned struct_apm_power_info_sz = sizeof(apm_power_info); +unsigned struct_atabusiodetach_args_sz = sizeof(atabusiodetach_args); +unsigned struct_atabusioscan_args_sz = sizeof(atabusioscan_args); +unsigned struct_ath_diag_sz = sizeof(ath_diag); +unsigned struct_atm_flowmap_sz = sizeof(atm_flowmap); +unsigned struct_audio_buf_info_sz = sizeof(audio_buf_info); +unsigned struct_audio_device_sz = sizeof(audio_device); +unsigned struct_audio_encoding_sz = sizeof(audio_encoding); +unsigned struct_audio_info_sz = sizeof(audio_info); +unsigned struct_audio_offset_sz = sizeof(audio_offset); +unsigned struct_bio_locate_sz = sizeof(bio_locate); +unsigned struct_bioc_alarm_sz = sizeof(bioc_alarm); +unsigned struct_bioc_blink_sz = sizeof(bioc_blink); +unsigned struct_bioc_disk_sz = sizeof(bioc_disk); +unsigned struct_bioc_inq_sz = sizeof(bioc_inq); +unsigned struct_bioc_setstate_sz = sizeof(bioc_setstate); +unsigned struct_bioc_vol_sz = sizeof(bioc_vol); +unsigned struct_bioc_volops_sz = sizeof(bioc_volops); +unsigned struct_bktr_chnlset_sz = sizeof(bktr_chnlset); +unsigned struct_bktr_remote_sz = sizeof(bktr_remote); +unsigned struct_blue_conf_sz = sizeof(blue_conf); +unsigned struct_blue_interface_sz = sizeof(blue_interface); +unsigned struct_blue_stats_sz = sizeof(blue_stats); +unsigned struct_bpf_dltlist_sz = sizeof(bpf_dltlist); +unsigned struct_bpf_program_sz = sizeof(bpf_program); +unsigned struct_bpf_stat_old_sz = sizeof(bpf_stat_old); +unsigned struct_bpf_stat_sz = sizeof(bpf_stat); +unsigned struct_bpf_version_sz = sizeof(bpf_version); +unsigned struct_btreq_sz = sizeof(btreq); +unsigned struct_btsco_info_sz = sizeof(btsco_info); +unsigned struct_buffmem_desc_sz = sizeof(buffmem_desc); +unsigned struct_cbq_add_class_sz = sizeof(cbq_add_class); +unsigned struct_cbq_add_filter_sz = sizeof(cbq_add_filter); +unsigned struct_cbq_delete_class_sz = sizeof(cbq_delete_class); +unsigned struct_cbq_delete_filter_sz = sizeof(cbq_delete_filter); +unsigned struct_cbq_getstats_sz = sizeof(cbq_getstats); +unsigned struct_cbq_interface_sz = sizeof(cbq_interface); +unsigned struct_cbq_modify_class_sz = sizeof(cbq_modify_class); +unsigned struct_ccd_ioctl_sz = sizeof(ccd_ioctl); +unsigned struct_cdnr_add_element_sz = sizeof(cdnr_add_element); +unsigned struct_cdnr_add_filter_sz = sizeof(cdnr_add_filter); +unsigned struct_cdnr_add_tbmeter_sz = sizeof(cdnr_add_tbmeter); +unsigned struct_cdnr_add_trtcm_sz = sizeof(cdnr_add_trtcm); +unsigned struct_cdnr_add_tswtcm_sz = sizeof(cdnr_add_tswtcm); +unsigned struct_cdnr_delete_element_sz = sizeof(cdnr_delete_element); +unsigned struct_cdnr_delete_filter_sz = sizeof(cdnr_delete_filter); +unsigned struct_cdnr_get_stats_sz = sizeof(cdnr_get_stats); +unsigned struct_cdnr_interface_sz = sizeof(cdnr_interface); +unsigned struct_cdnr_modify_tbmeter_sz = sizeof(cdnr_modify_tbmeter); +unsigned struct_cdnr_modify_trtcm_sz = sizeof(cdnr_modify_trtcm); +unsigned struct_cdnr_modify_tswtcm_sz = sizeof(cdnr_modify_tswtcm); +unsigned struct_cdnr_tbmeter_stats_sz = sizeof(cdnr_tbmeter_stats); +unsigned struct_cdnr_tcm_stats_sz = sizeof(cdnr_tcm_stats); +unsigned struct_cgd_ioctl_sz = sizeof(cgd_ioctl); +unsigned struct_cgd_user_sz = sizeof(cgd_user); +unsigned struct_changer_element_status_request_sz = + sizeof(changer_element_status_request); +unsigned struct_changer_exchange_request_sz = sizeof(changer_exchange_request); +unsigned struct_changer_move_request_sz = sizeof(changer_move_request); +unsigned struct_changer_params_sz = sizeof(changer_params); +unsigned struct_changer_position_request_sz = sizeof(changer_position_request); +unsigned struct_changer_set_voltag_request_sz = + sizeof(changer_set_voltag_request); +unsigned struct_clockctl_adjtime_sz = sizeof(clockctl_adjtime); +unsigned struct_clockctl_clock_settime_sz = sizeof(clockctl_clock_settime); +unsigned struct_clockctl_ntp_adjtime_sz = sizeof(clockctl_ntp_adjtime); +unsigned struct_clockctl_settimeofday_sz = sizeof(clockctl_settimeofday); +unsigned struct_cnwistats_sz = sizeof(cnwistats); +unsigned struct_cnwitrail_sz = sizeof(cnwitrail); +unsigned struct_cnwstatus_sz = sizeof(cnwstatus); +unsigned struct_count_info_sz = sizeof(count_info); +unsigned struct_cpu_ucode_sz = sizeof(cpu_ucode); +unsigned struct_cpu_ucode_version_sz = sizeof(cpu_ucode_version); +unsigned struct_crypt_kop_sz = sizeof(crypt_kop); +unsigned struct_crypt_mkop_sz = sizeof(crypt_mkop); +unsigned struct_crypt_mop_sz = sizeof(crypt_mop); +unsigned struct_crypt_op_sz = sizeof(crypt_op); +unsigned struct_crypt_result_sz = sizeof(crypt_result); +unsigned struct_crypt_sfop_sz = sizeof(crypt_sfop); +unsigned struct_crypt_sgop_sz = sizeof(crypt_sgop); +unsigned struct_cryptret_sz = sizeof(cryptret); +unsigned struct_devdetachargs_sz = sizeof(devdetachargs); +unsigned struct_devlistargs_sz = sizeof(devlistargs); +unsigned struct_devpmargs_sz = sizeof(devpmargs); +unsigned struct_devrescanargs_sz = sizeof(devrescanargs); +unsigned struct_disk_badsecinfo_sz = sizeof(disk_badsecinfo); +unsigned struct_disk_strategy_sz = sizeof(disk_strategy); +unsigned struct_disklabel_sz = sizeof(disklabel); +unsigned struct_dkbad_sz = sizeof(dkbad); +unsigned struct_dkwedge_info_sz = sizeof(dkwedge_info); +unsigned struct_dkwedge_list_sz = sizeof(dkwedge_list); +unsigned struct_dmio_setfunc_sz = sizeof(dmio_setfunc); +unsigned struct_dmx_pes_filter_params_sz = sizeof(dmx_pes_filter_params); +unsigned struct_dmx_sct_filter_params_sz = sizeof(dmx_sct_filter_params); +unsigned struct_dmx_stc_sz = sizeof(dmx_stc); +unsigned struct_dvb_diseqc_master_cmd_sz = sizeof(dvb_diseqc_master_cmd); +unsigned struct_dvb_diseqc_slave_reply_sz = sizeof(dvb_diseqc_slave_reply); +unsigned struct_dvb_frontend_event_sz = sizeof(dvb_frontend_event); +unsigned struct_dvb_frontend_info_sz = sizeof(dvb_frontend_info); +unsigned struct_dvb_frontend_parameters_sz = sizeof(dvb_frontend_parameters); +unsigned struct_eccapreq_sz = sizeof(eccapreq); +unsigned struct_fbcmap_sz = sizeof(fbcmap); +unsigned struct_fbcurpos_sz = sizeof(fbcurpos); +unsigned struct_fbcursor_sz = sizeof(fbcursor); +unsigned struct_fbgattr_sz = sizeof(fbgattr); +unsigned struct_fbsattr_sz = sizeof(fbsattr); +unsigned struct_fbtype_sz = sizeof(fbtype); +unsigned struct_fdformat_cmd_sz = sizeof(fdformat_cmd); +unsigned struct_fdformat_parms_sz = sizeof(fdformat_parms); +unsigned struct_fifoq_conf_sz = sizeof(fifoq_conf); +unsigned struct_fifoq_getstats_sz = sizeof(fifoq_getstats); +unsigned struct_fifoq_interface_sz = sizeof(fifoq_interface); +unsigned struct_format_op_sz = sizeof(format_op); +unsigned struct_fss_get_sz = sizeof(fss_get); +unsigned struct_fss_set_sz = sizeof(fss_set); +unsigned struct_gpio_attach_sz = sizeof(gpio_attach); +unsigned struct_gpio_info_sz = sizeof(gpio_info); +unsigned struct_gpio_req_sz = sizeof(gpio_req); +unsigned struct_gpio_set_sz = sizeof(gpio_set); +unsigned struct_hfsc_add_class_sz = sizeof(hfsc_add_class); +unsigned struct_hfsc_add_filter_sz = sizeof(hfsc_add_filter); +unsigned struct_hfsc_attach_sz = sizeof(hfsc_attach); +unsigned struct_hfsc_class_stats_sz = sizeof(hfsc_class_stats); +unsigned struct_hfsc_delete_class_sz = sizeof(hfsc_delete_class); +unsigned struct_hfsc_delete_filter_sz = sizeof(hfsc_delete_filter); +unsigned struct_hfsc_interface_sz = sizeof(hfsc_interface); +unsigned struct_hfsc_modify_class_sz = sizeof(hfsc_modify_class); +unsigned struct_hpcfb_dsp_op_sz = sizeof(hpcfb_dsp_op); +unsigned struct_hpcfb_dspconf_sz = sizeof(hpcfb_dspconf); +unsigned struct_hpcfb_fbconf_sz = sizeof(hpcfb_fbconf); +unsigned struct_if_addrprefreq_sz = sizeof(if_addrprefreq); +unsigned struct_if_clonereq_sz = sizeof(if_clonereq); +unsigned struct_if_laddrreq_sz = sizeof(if_laddrreq); +unsigned struct_ifaddr_sz = sizeof(ifaddr); +unsigned struct_ifaliasreq_sz = sizeof(ifaliasreq); +unsigned struct_ifcapreq_sz = sizeof(ifcapreq); +unsigned struct_ifconf_sz = sizeof(ifconf); +unsigned struct_ifdatareq_sz = sizeof(ifdatareq); +unsigned struct_ifdrv_sz = sizeof(ifdrv); +unsigned struct_ifmediareq_sz = sizeof(ifmediareq); +unsigned struct_ifpppcstatsreq_sz = sizeof(ifpppcstatsreq); +unsigned struct_ifpppstatsreq_sz = sizeof(ifpppstatsreq); +unsigned struct_ifreq_sz = sizeof(ifreq); +unsigned struct_in6_addrpolicy_sz = sizeof(in6_addrpolicy); +unsigned struct_in6_ndireq_sz = sizeof(in6_ndireq); +unsigned struct_ioc_load_unload_sz = sizeof(ioc_load_unload); +unsigned struct_ioc_patch_sz = sizeof(ioc_patch); +unsigned struct_ioc_play_blocks_sz = sizeof(ioc_play_blocks); +unsigned struct_ioc_play_msf_sz = sizeof(ioc_play_msf); +unsigned struct_ioc_play_track_sz = sizeof(ioc_play_track); +unsigned struct_ioc_read_subchannel_sz = sizeof(ioc_read_subchannel); +unsigned struct_ioc_read_toc_entry_sz = sizeof(ioc_read_toc_entry); +unsigned struct_ioc_toc_header_sz = sizeof(ioc_toc_header); +unsigned struct_ioc_vol_sz = sizeof(ioc_vol); +unsigned struct_ioctl_pt_sz = sizeof(ioctl_pt); +unsigned struct_ioppt_sz = sizeof(ioppt); +unsigned struct_iovec_sz = sizeof(iovec); +unsigned struct_ipfobj_sz = sizeof(ipfobj); +unsigned struct_irda_params_sz = sizeof(irda_params); +unsigned struct_isp_fc_device_sz = sizeof(isp_fc_device); +unsigned struct_isp_fc_tsk_mgmt_sz = sizeof(isp_fc_tsk_mgmt); +unsigned struct_isp_hba_device_sz = sizeof(isp_hba_device); +unsigned struct_isv_cmd_sz = sizeof(isv_cmd); +unsigned struct_jobs_add_class_sz = sizeof(jobs_add_class); +unsigned struct_jobs_add_filter_sz = sizeof(jobs_add_filter); +unsigned struct_jobs_attach_sz = sizeof(jobs_attach); +unsigned struct_jobs_class_stats_sz = sizeof(jobs_class_stats); +unsigned struct_jobs_delete_class_sz = sizeof(jobs_delete_class); +unsigned struct_jobs_delete_filter_sz = sizeof(jobs_delete_filter); +unsigned struct_jobs_interface_sz = sizeof(jobs_interface); +unsigned struct_jobs_modify_class_sz = sizeof(jobs_modify_class); +unsigned struct_kbentry_sz = sizeof(kbentry); +unsigned struct_kfilter_mapping_sz = sizeof(kfilter_mapping); +unsigned struct_kiockeymap_sz = sizeof(kiockeymap); +unsigned struct_ksyms_gsymbol_sz = sizeof(ksyms_gsymbol); +unsigned struct_ksyms_gvalue_sz = sizeof(ksyms_gvalue); +unsigned struct_ksyms_ogsymbol_sz = sizeof(ksyms_ogsymbol); +unsigned struct_kttcp_io_args_sz = sizeof(kttcp_io_args); +unsigned struct_ltchars_sz = sizeof(ltchars); +unsigned struct_lua_create_sz = sizeof(struct lua_create); +unsigned struct_lua_info_sz = sizeof(struct lua_info); +unsigned struct_lua_load_sz = sizeof(struct lua_load); +unsigned struct_lua_require_sz = sizeof(lua_require); +unsigned struct_mbpp_param_sz = sizeof(mbpp_param); +unsigned struct_md_conf_sz = sizeof(md_conf); +unsigned struct_meteor_capframe_sz = sizeof(meteor_capframe); +unsigned struct_meteor_counts_sz = sizeof(meteor_counts); +unsigned struct_meteor_geomet_sz = sizeof(meteor_geomet); +unsigned struct_meteor_pixfmt_sz = sizeof(meteor_pixfmt); +unsigned struct_meteor_video_sz = sizeof(meteor_video); +unsigned struct_mlx_cinfo_sz = sizeof(mlx_cinfo); +unsigned struct_mlx_pause_sz = sizeof(mlx_pause); +unsigned struct_mlx_rebuild_request_sz = sizeof(mlx_rebuild_request); +unsigned struct_mlx_rebuild_status_sz = sizeof(mlx_rebuild_status); +unsigned struct_mlx_usercommand_sz = sizeof(mlx_usercommand); +unsigned struct_mly_user_command_sz = sizeof(mly_user_command); +unsigned struct_mly_user_health_sz = sizeof(mly_user_health); +unsigned struct_mtget_sz = sizeof(mtget); +unsigned struct_mtop_sz = sizeof(mtop); +unsigned struct_npf_ioctl_table_sz = sizeof(npf_ioctl_table); +unsigned struct_npioctl_sz = sizeof(npioctl); +unsigned struct_nvme_pt_command_sz = sizeof(nvme_pt_command); +unsigned struct_ochanger_element_status_request_sz = + sizeof(ochanger_element_status_request); +unsigned struct_ofiocdesc_sz = sizeof(ofiocdesc); +unsigned struct_okiockey_sz = sizeof(okiockey); +unsigned struct_ortentry_sz = sizeof(ortentry); +unsigned struct_oscsi_addr_sz = sizeof(oscsi_addr); +unsigned struct_oss_audioinfo_sz = sizeof(oss_audioinfo); +unsigned struct_oss_sysinfo_sz = sizeof(oss_sysinfo); +unsigned struct_pciio_bdf_cfgreg_sz = sizeof(pciio_bdf_cfgreg); +unsigned struct_pciio_businfo_sz = sizeof(pciio_businfo); +unsigned struct_pciio_cfgreg_sz = sizeof(pciio_cfgreg); +unsigned struct_pciio_drvname_sz = sizeof(pciio_drvname); +unsigned struct_pciio_drvnameonbus_sz = sizeof(pciio_drvnameonbus); +unsigned struct_pcvtid_sz = sizeof(pcvtid); +unsigned struct_pf_osfp_ioctl_sz = sizeof(pf_osfp_ioctl); +unsigned struct_pf_status_sz = sizeof(pf_status); +unsigned struct_pfioc_altq_sz = sizeof(pfioc_altq); +unsigned struct_pfioc_if_sz = sizeof(pfioc_if); +unsigned struct_pfioc_iface_sz = sizeof(pfioc_iface); +unsigned struct_pfioc_limit_sz = sizeof(pfioc_limit); +unsigned struct_pfioc_natlook_sz = sizeof(pfioc_natlook); +unsigned struct_pfioc_pooladdr_sz = sizeof(pfioc_pooladdr); +unsigned struct_pfioc_qstats_sz = sizeof(pfioc_qstats); +unsigned struct_pfioc_rule_sz = sizeof(pfioc_rule); +unsigned struct_pfioc_ruleset_sz = sizeof(pfioc_ruleset); +unsigned struct_pfioc_src_node_kill_sz = sizeof(pfioc_src_node_kill); +unsigned struct_pfioc_src_nodes_sz = sizeof(pfioc_src_nodes); +unsigned struct_pfioc_state_kill_sz = sizeof(pfioc_state_kill); +unsigned struct_pfioc_state_sz = sizeof(pfioc_state); +unsigned struct_pfioc_states_sz = sizeof(pfioc_states); +unsigned struct_pfioc_table_sz = sizeof(pfioc_table); +unsigned struct_pfioc_tm_sz = sizeof(pfioc_tm); +unsigned struct_pfioc_trans_sz = sizeof(pfioc_trans); +unsigned struct_plistref_sz = sizeof(plistref); +unsigned struct_power_type_sz = sizeof(power_type); +unsigned struct_ppp_idle_sz = sizeof(ppp_idle); +unsigned struct_ppp_option_data_sz = sizeof(ppp_option_data); +unsigned struct_ppp_rawin_sz = sizeof(ppp_rawin); +unsigned struct_pppoeconnectionstate_sz = sizeof(pppoeconnectionstate); +unsigned struct_pppoediscparms_sz = sizeof(pppoediscparms); +unsigned struct_priq_add_class_sz = sizeof(priq_add_class); +unsigned struct_priq_add_filter_sz = sizeof(priq_add_filter); +unsigned struct_priq_class_stats_sz = sizeof(priq_class_stats); +unsigned struct_priq_delete_class_sz = sizeof(priq_delete_class); +unsigned struct_priq_delete_filter_sz = sizeof(priq_delete_filter); +unsigned struct_priq_interface_sz = sizeof(priq_interface); +unsigned struct_priq_modify_class_sz = sizeof(priq_modify_class); +unsigned struct_ptmget_sz = sizeof(ptmget); +unsigned struct_radio_info_sz = sizeof(radio_info); +unsigned struct_red_conf_sz = sizeof(red_conf); +unsigned struct_red_interface_sz = sizeof(red_interface); +unsigned struct_red_stats_sz = sizeof(red_stats); +unsigned struct_redparams_sz = sizeof(redparams); +unsigned struct_rf_pmparams_sz = sizeof(rf_pmparams); +unsigned struct_rf_pmstat_sz = sizeof(rf_pmstat); +unsigned struct_rf_recon_req_sz = sizeof(rf_recon_req); +unsigned struct_rio_conf_sz = sizeof(rio_conf); +unsigned struct_rio_interface_sz = sizeof(rio_interface); +unsigned struct_rio_stats_sz = sizeof(rio_stats); +unsigned struct_scan_io_sz = sizeof(scan_io); +unsigned struct_scbusaccel_args_sz = sizeof(scbusaccel_args); +unsigned struct_scbusiodetach_args_sz = sizeof(scbusiodetach_args); +unsigned struct_scbusioscan_args_sz = sizeof(scbusioscan_args); +unsigned struct_scsi_addr_sz = sizeof(scsi_addr); +unsigned struct_seq_event_rec_sz = sizeof(seq_event_rec); +unsigned struct_session_op_sz = sizeof(session_op); +unsigned struct_sgttyb_sz = sizeof(sgttyb); +unsigned struct_sioc_sg_req_sz = sizeof(sioc_sg_req); +unsigned struct_sioc_vif_req_sz = sizeof(sioc_vif_req); +unsigned struct_smbioc_flags_sz = sizeof(smbioc_flags); +unsigned struct_smbioc_lookup_sz = sizeof(smbioc_lookup); +unsigned struct_smbioc_oshare_sz = sizeof(smbioc_oshare); +unsigned struct_smbioc_ossn_sz = sizeof(smbioc_ossn); +unsigned struct_smbioc_rq_sz = sizeof(smbioc_rq); +unsigned struct_smbioc_rw_sz = sizeof(smbioc_rw); +unsigned struct_spppauthcfg_sz = sizeof(spppauthcfg); +unsigned struct_spppauthfailuresettings_sz = sizeof(spppauthfailuresettings); +unsigned struct_spppauthfailurestats_sz = sizeof(spppauthfailurestats); +unsigned struct_spppdnsaddrs_sz = sizeof(spppdnsaddrs); +unsigned struct_spppdnssettings_sz = sizeof(spppdnssettings); +unsigned struct_spppidletimeout_sz = sizeof(spppidletimeout); +unsigned struct_spppkeepalivesettings_sz = sizeof(spppkeepalivesettings); +unsigned struct_sppplcpcfg_sz = sizeof(sppplcpcfg); +unsigned struct_spppstatus_sz = sizeof(spppstatus); +unsigned struct_spppstatusncp_sz = sizeof(spppstatusncp); +unsigned struct_srt_rt_sz = sizeof(srt_rt); +unsigned struct_stic_xinfo_sz = sizeof(stic_xinfo); +unsigned struct_sun_dkctlr_sz = sizeof(sun_dkctlr); +unsigned struct_sun_dkgeom_sz = sizeof(sun_dkgeom); +unsigned struct_sun_dkpart_sz = sizeof(sun_dkpart); +unsigned struct_synth_info_sz = sizeof(synth_info); +unsigned struct_tbrreq_sz = sizeof(tbrreq); +unsigned struct_tchars_sz = sizeof(tchars); +unsigned struct_termios_sz = sizeof(termios); +unsigned struct_timeval_sz = sizeof(timeval); +unsigned struct_twe_drivecommand_sz = sizeof(twe_drivecommand); +unsigned struct_twe_paramcommand_sz = sizeof(twe_paramcommand); +unsigned struct_twe_usercommand_sz = sizeof(twe_usercommand); +unsigned struct_ukyopon_identify_sz = sizeof(ukyopon_identify); +unsigned struct_urio_command_sz = sizeof(urio_command); +unsigned struct_usb_alt_interface_sz = sizeof(usb_alt_interface); +unsigned struct_usb_bulk_ra_wb_opt_sz = sizeof(usb_bulk_ra_wb_opt); +unsigned struct_usb_config_desc_sz = sizeof(usb_config_desc); +unsigned struct_usb_ctl_report_desc_sz = sizeof(usb_ctl_report_desc); +unsigned struct_usb_ctl_report_sz = sizeof(usb_ctl_report); +unsigned struct_usb_ctl_request_sz = sizeof(usb_ctl_request); +#if defined(__x86_64__) +unsigned struct_nvmm_ioc_capability_sz = sizeof(nvmm_ioc_capability); +unsigned struct_nvmm_ioc_machine_create_sz = sizeof(nvmm_ioc_machine_create); +unsigned struct_nvmm_ioc_machine_destroy_sz = sizeof(nvmm_ioc_machine_destroy); +unsigned struct_nvmm_ioc_machine_configure_sz = + sizeof(nvmm_ioc_machine_configure); +unsigned struct_nvmm_ioc_vcpu_create_sz = sizeof(nvmm_ioc_vcpu_create); +unsigned struct_nvmm_ioc_vcpu_destroy_sz = sizeof(nvmm_ioc_vcpu_destroy); +unsigned struct_nvmm_ioc_vcpu_configure_sz = sizeof(nvmm_ioc_vcpu_configure); +unsigned struct_nvmm_ioc_vcpu_setstate_sz = sizeof(nvmm_ioc_vcpu_destroy); +unsigned struct_nvmm_ioc_vcpu_getstate_sz = sizeof(nvmm_ioc_vcpu_getstate); +unsigned struct_nvmm_ioc_vcpu_inject_sz = sizeof(nvmm_ioc_vcpu_inject); +unsigned struct_nvmm_ioc_vcpu_run_sz = sizeof(nvmm_ioc_vcpu_run); +unsigned struct_nvmm_ioc_gpa_map_sz = sizeof(nvmm_ioc_gpa_map); +unsigned struct_nvmm_ioc_gpa_unmap_sz = sizeof(nvmm_ioc_gpa_unmap); +unsigned struct_nvmm_ioc_hva_map_sz = sizeof(nvmm_ioc_hva_map); +unsigned struct_nvmm_ioc_hva_unmap_sz = sizeof(nvmm_ioc_hva_unmap); +unsigned struct_nvmm_ioc_ctl_sz = sizeof(nvmm_ioc_ctl); +#endif +unsigned struct_spi_ioctl_configure_sz = sizeof(spi_ioctl_configure); +unsigned struct_spi_ioctl_transfer_sz = sizeof(spi_ioctl_transfer); +unsigned struct_autofs_daemon_request_sz = sizeof(autofs_daemon_request); +unsigned struct_autofs_daemon_done_sz = sizeof(autofs_daemon_done); +unsigned struct_sctp_connectx_addrs_sz = sizeof(sctp_connectx_addrs); +unsigned struct_usb_device_info_old_sz = sizeof(usb_device_info_old); +unsigned struct_usb_device_info_sz = sizeof(usb_device_info); +unsigned struct_usb_device_stats_sz = sizeof(usb_device_stats); +unsigned struct_usb_endpoint_desc_sz = sizeof(usb_endpoint_desc); +unsigned struct_usb_full_desc_sz = sizeof(usb_full_desc); +unsigned struct_usb_interface_desc_sz = sizeof(usb_interface_desc); +unsigned struct_usb_string_desc_sz = sizeof(usb_string_desc); +unsigned struct_utoppy_readfile_sz = sizeof(utoppy_readfile); +unsigned struct_utoppy_rename_sz = sizeof(utoppy_rename); +unsigned struct_utoppy_stats_sz = sizeof(utoppy_stats); +unsigned struct_utoppy_writefile_sz = sizeof(utoppy_writefile); +unsigned struct_v4l2_audio_sz = sizeof(v4l2_audio); +unsigned struct_v4l2_audioout_sz = sizeof(v4l2_audioout); +unsigned struct_v4l2_buffer_sz = sizeof(v4l2_buffer); +unsigned struct_v4l2_capability_sz = sizeof(v4l2_capability); +unsigned struct_v4l2_control_sz = sizeof(v4l2_control); +unsigned struct_v4l2_crop_sz = sizeof(v4l2_crop); +unsigned struct_v4l2_cropcap_sz = sizeof(v4l2_cropcap); +unsigned struct_v4l2_fmtdesc_sz = sizeof(v4l2_fmtdesc); +unsigned struct_v4l2_format_sz = sizeof(v4l2_format); +unsigned struct_v4l2_framebuffer_sz = sizeof(v4l2_framebuffer); +unsigned struct_v4l2_frequency_sz = sizeof(v4l2_frequency); +unsigned struct_v4l2_frmivalenum_sz = sizeof(v4l2_frmivalenum); +unsigned struct_v4l2_frmsizeenum_sz = sizeof(v4l2_frmsizeenum); +unsigned struct_v4l2_input_sz = sizeof(v4l2_input); +unsigned struct_v4l2_jpegcompression_sz = sizeof(v4l2_jpegcompression); +unsigned struct_v4l2_modulator_sz = sizeof(v4l2_modulator); +unsigned struct_v4l2_output_sz = sizeof(v4l2_output); +unsigned struct_v4l2_queryctrl_sz = sizeof(v4l2_queryctrl); +unsigned struct_v4l2_querymenu_sz = sizeof(v4l2_querymenu); +unsigned struct_v4l2_requestbuffers_sz = sizeof(v4l2_requestbuffers); +unsigned struct_v4l2_standard_sz = sizeof(v4l2_standard); +unsigned struct_v4l2_streamparm_sz = sizeof(v4l2_streamparm); +unsigned struct_v4l2_tuner_sz = sizeof(v4l2_tuner); +unsigned struct_vnd_ioctl_sz = sizeof(vnd_ioctl); +unsigned struct_vnd_user_sz = sizeof(vnd_user); +unsigned struct_vt_stat_sz = sizeof(vt_stat); +unsigned struct_wdog_conf_sz = sizeof(wdog_conf); +unsigned struct_wdog_mode_sz = sizeof(wdog_mode); +unsigned struct_ipmi_recv_sz = sizeof(ipmi_recv); +unsigned struct_ipmi_req_sz = sizeof(ipmi_req); +unsigned struct_ipmi_cmdspec_sz = sizeof(ipmi_cmdspec); +unsigned struct_wfq_conf_sz = sizeof(wfq_conf); +unsigned struct_wfq_getqid_sz = sizeof(wfq_getqid); +unsigned struct_wfq_getstats_sz = sizeof(wfq_getstats); +unsigned struct_wfq_interface_sz = sizeof(wfq_interface); +unsigned struct_wfq_setweight_sz = sizeof(wfq_setweight); +unsigned struct_winsize_sz = sizeof(winsize); +unsigned struct_wscons_event_sz = sizeof(wscons_event); +unsigned struct_wsdisplay_addscreendata_sz = sizeof(wsdisplay_addscreendata); +unsigned struct_wsdisplay_char_sz = sizeof(wsdisplay_char); +unsigned struct_wsdisplay_cmap_sz = sizeof(wsdisplay_cmap); +unsigned struct_wsdisplay_curpos_sz = sizeof(wsdisplay_curpos); +unsigned struct_wsdisplay_cursor_sz = sizeof(wsdisplay_cursor); +unsigned struct_wsdisplay_delscreendata_sz = sizeof(wsdisplay_delscreendata); +unsigned struct_wsdisplay_fbinfo_sz = sizeof(wsdisplay_fbinfo); +unsigned struct_wsdisplay_font_sz = sizeof(wsdisplay_font); +unsigned struct_wsdisplay_kbddata_sz = sizeof(wsdisplay_kbddata); +unsigned struct_wsdisplay_msgattrs_sz = sizeof(wsdisplay_msgattrs); +unsigned struct_wsdisplay_param_sz = sizeof(wsdisplay_param); +unsigned struct_wsdisplay_scroll_data_sz = sizeof(wsdisplay_scroll_data); +unsigned struct_wsdisplay_usefontdata_sz = sizeof(wsdisplay_usefontdata); +unsigned struct_wsdisplayio_blit_sz = sizeof(wsdisplayio_blit); +unsigned struct_wsdisplayio_bus_id_sz = sizeof(wsdisplayio_bus_id); +unsigned struct_wsdisplayio_edid_info_sz = sizeof(wsdisplayio_edid_info); +unsigned struct_wsdisplayio_fbinfo_sz = sizeof(wsdisplayio_fbinfo); +unsigned struct_wskbd_bell_data_sz = sizeof(wskbd_bell_data); +unsigned struct_wskbd_keyrepeat_data_sz = sizeof(wskbd_keyrepeat_data); +unsigned struct_wskbd_map_data_sz = sizeof(wskbd_map_data); +unsigned struct_wskbd_scroll_data_sz = sizeof(wskbd_scroll_data); +unsigned struct_wsmouse_calibcoords_sz = sizeof(wsmouse_calibcoords); +unsigned struct_wsmouse_id_sz = sizeof(wsmouse_id); +unsigned struct_wsmouse_repeat_sz = sizeof(wsmouse_repeat); +unsigned struct_wsmux_device_list_sz = sizeof(wsmux_device_list); +unsigned struct_wsmux_device_sz = sizeof(wsmux_device); +unsigned struct_xd_iocmd_sz = sizeof(xd_iocmd); + +unsigned struct_scsireq_sz = sizeof(struct scsireq); +unsigned struct_tone_sz = sizeof(tone_t); +unsigned union_twe_statrequest_sz = sizeof(union twe_statrequest); +unsigned struct_usb_device_descriptor_sz = sizeof(usb_device_descriptor_t); +unsigned struct_vt_mode_sz = sizeof(struct vt_mode); +unsigned struct__old_mixer_info_sz = sizeof(struct _old_mixer_info); +unsigned struct__agp_allocate_sz = sizeof(struct _agp_allocate); +unsigned struct__agp_bind_sz = sizeof(struct _agp_bind); +unsigned struct__agp_info_sz = sizeof(struct _agp_info); +unsigned struct__agp_setup_sz = sizeof(struct _agp_setup); +unsigned struct__agp_unbind_sz = sizeof(struct _agp_unbind); +unsigned struct_atareq_sz = sizeof(struct atareq); +unsigned struct_cpustate_sz = sizeof(struct cpustate); +unsigned struct_dmx_caps_sz = sizeof(struct dmx_caps); +unsigned enum_dmx_source_sz = sizeof(dmx_source_t); +unsigned union_dvd_authinfo_sz = sizeof(dvd_authinfo); +unsigned union_dvd_struct_sz = sizeof(dvd_struct); +unsigned enum_v4l2_priority_sz = sizeof(enum v4l2_priority); +unsigned struct_envsys_basic_info_sz = sizeof(struct envsys_basic_info); +unsigned struct_envsys_tre_data_sz = sizeof(struct envsys_tre_data); +unsigned enum_fe_sec_mini_cmd_sz = sizeof(enum fe_sec_mini_cmd); +unsigned enum_fe_sec_tone_mode_sz = sizeof(enum fe_sec_tone_mode); +unsigned enum_fe_sec_voltage_sz = sizeof(enum fe_sec_voltage); +unsigned enum_fe_status_sz = sizeof(enum fe_status); +unsigned struct_gdt_ctrt_sz = sizeof(struct gdt_ctrt); +unsigned struct_gdt_event_sz = sizeof(struct gdt_event); +unsigned struct_gdt_osv_sz = sizeof(struct gdt_osv); +unsigned struct_gdt_rescan_sz = sizeof(struct gdt_rescan); +unsigned struct_gdt_statist_sz = sizeof(struct gdt_statist); +unsigned struct_gdt_ucmd_sz = sizeof(struct gdt_ucmd); +unsigned struct_iscsi_conn_status_parameters_sz = + sizeof(iscsi_conn_status_parameters_t); +unsigned struct_iscsi_get_version_parameters_sz = + sizeof(iscsi_get_version_parameters_t); +unsigned struct_iscsi_iocommand_parameters_sz = + sizeof(iscsi_iocommand_parameters_t); +unsigned struct_iscsi_login_parameters_sz = sizeof(iscsi_login_parameters_t); +unsigned struct_iscsi_logout_parameters_sz = sizeof(iscsi_logout_parameters_t); +unsigned struct_iscsi_register_event_parameters_sz = + sizeof(iscsi_register_event_parameters_t); +unsigned struct_iscsi_remove_parameters_sz = sizeof(iscsi_remove_parameters_t); +unsigned struct_iscsi_send_targets_parameters_sz = + sizeof(iscsi_send_targets_parameters_t); +unsigned struct_iscsi_set_node_name_parameters_sz = + sizeof(iscsi_set_node_name_parameters_t); +unsigned struct_iscsi_wait_event_parameters_sz = + sizeof(iscsi_wait_event_parameters_t); +unsigned struct_isp_stats_sz = sizeof(isp_stats_t); +unsigned struct_lsenable_sz = sizeof(struct lsenable); +unsigned struct_lsdisable_sz = sizeof(struct lsdisable); +unsigned struct_audio_format_query_sz = sizeof(audio_format_query); +unsigned struct_mixer_ctrl_sz = sizeof(struct mixer_ctrl); +unsigned struct_mixer_devinfo_sz = sizeof(struct mixer_devinfo); +unsigned struct_mpu_command_rec_sz = sizeof(mpu_command_rec); +unsigned struct_rndstat_sz = sizeof(rndstat_t); +unsigned struct_rndstat_name_sz = sizeof(rndstat_name_t); +unsigned struct_rndctl_sz = sizeof(rndctl_t); +unsigned struct_rnddata_sz = sizeof(rnddata_t); +unsigned struct_rndpoolstat_sz = sizeof(rndpoolstat_t); +unsigned struct_rndstat_est_sz = sizeof(rndstat_est_t); +unsigned struct_rndstat_est_name_sz = sizeof(rndstat_est_name_t); +unsigned struct_pps_params_sz = sizeof(pps_params_t); +unsigned struct_pps_info_sz = sizeof(pps_info_t); +unsigned struct_mixer_info_sz = sizeof(struct mixer_info); +unsigned struct_RF_SparetWait_sz = sizeof(RF_SparetWait_t); +unsigned struct_RF_ComponentLabel_sz = sizeof(RF_ComponentLabel_t); +unsigned struct_RF_SingleComponent_sz = sizeof(RF_SingleComponent_t); +unsigned struct_RF_ProgressInfo_sz = sizeof(RF_ProgressInfo_t); +unsigned struct_nvlist_ref_sz = sizeof(struct __sanitizer_nvlist_ref_t); +unsigned struct_StringList_sz = sizeof(StringList); + +const unsigned IOCTL_NOT_PRESENT = 0; + +unsigned IOCTL_AFM_ADDFMAP = AFM_ADDFMAP; +unsigned IOCTL_AFM_DELFMAP = AFM_DELFMAP; +unsigned IOCTL_AFM_CLEANFMAP = AFM_CLEANFMAP; +unsigned IOCTL_AFM_GETFMAP = AFM_GETFMAP; +unsigned IOCTL_ALTQGTYPE = ALTQGTYPE; +unsigned IOCTL_ALTQTBRSET = ALTQTBRSET; +unsigned IOCTL_ALTQTBRGET = ALTQTBRGET; +unsigned IOCTL_BLUE_IF_ATTACH = BLUE_IF_ATTACH; +unsigned IOCTL_BLUE_IF_DETACH = BLUE_IF_DETACH; +unsigned IOCTL_BLUE_ENABLE = BLUE_ENABLE; +unsigned IOCTL_BLUE_DISABLE = BLUE_DISABLE; +unsigned IOCTL_BLUE_CONFIG = BLUE_CONFIG; +unsigned IOCTL_BLUE_GETSTATS = BLUE_GETSTATS; +unsigned IOCTL_CBQ_IF_ATTACH = CBQ_IF_ATTACH; +unsigned IOCTL_CBQ_IF_DETACH = CBQ_IF_DETACH; +unsigned IOCTL_CBQ_ENABLE = CBQ_ENABLE; +unsigned IOCTL_CBQ_DISABLE = CBQ_DISABLE; +unsigned IOCTL_CBQ_CLEAR_HIERARCHY = CBQ_CLEAR_HIERARCHY; +unsigned IOCTL_CBQ_ADD_CLASS = CBQ_ADD_CLASS; +unsigned IOCTL_CBQ_DEL_CLASS = CBQ_DEL_CLASS; +unsigned IOCTL_CBQ_MODIFY_CLASS = CBQ_MODIFY_CLASS; +unsigned IOCTL_CBQ_ADD_FILTER = CBQ_ADD_FILTER; +unsigned IOCTL_CBQ_DEL_FILTER = CBQ_DEL_FILTER; +unsigned IOCTL_CBQ_GETSTATS = CBQ_GETSTATS; +unsigned IOCTL_CDNR_IF_ATTACH = CDNR_IF_ATTACH; +unsigned IOCTL_CDNR_IF_DETACH = CDNR_IF_DETACH; +unsigned IOCTL_CDNR_ENABLE = CDNR_ENABLE; +unsigned IOCTL_CDNR_DISABLE = CDNR_DISABLE; +unsigned IOCTL_CDNR_ADD_FILTER = CDNR_ADD_FILTER; +unsigned IOCTL_CDNR_DEL_FILTER = CDNR_DEL_FILTER; +unsigned IOCTL_CDNR_GETSTATS = CDNR_GETSTATS; +unsigned IOCTL_CDNR_ADD_ELEM = CDNR_ADD_ELEM; +unsigned IOCTL_CDNR_DEL_ELEM = CDNR_DEL_ELEM; +unsigned IOCTL_CDNR_ADD_TBM = CDNR_ADD_TBM; +unsigned IOCTL_CDNR_MOD_TBM = CDNR_MOD_TBM; +unsigned IOCTL_CDNR_TBM_STATS = CDNR_TBM_STATS; +unsigned IOCTL_CDNR_ADD_TCM = CDNR_ADD_TCM; +unsigned IOCTL_CDNR_MOD_TCM = CDNR_MOD_TCM; +unsigned IOCTL_CDNR_TCM_STATS = CDNR_TCM_STATS; +unsigned IOCTL_CDNR_ADD_TSW = CDNR_ADD_TSW; +unsigned IOCTL_CDNR_MOD_TSW = CDNR_MOD_TSW; +unsigned IOCTL_FIFOQ_IF_ATTACH = FIFOQ_IF_ATTACH; +unsigned IOCTL_FIFOQ_IF_DETACH = FIFOQ_IF_DETACH; +unsigned IOCTL_FIFOQ_ENABLE = FIFOQ_ENABLE; +unsigned IOCTL_FIFOQ_DISABLE = FIFOQ_DISABLE; +unsigned IOCTL_FIFOQ_CONFIG = FIFOQ_CONFIG; +unsigned IOCTL_FIFOQ_GETSTATS = FIFOQ_GETSTATS; +unsigned IOCTL_HFSC_IF_ATTACH = HFSC_IF_ATTACH; +unsigned IOCTL_HFSC_IF_DETACH = HFSC_IF_DETACH; +unsigned IOCTL_HFSC_ENABLE = HFSC_ENABLE; +unsigned IOCTL_HFSC_DISABLE = HFSC_DISABLE; +unsigned IOCTL_HFSC_CLEAR_HIERARCHY = HFSC_CLEAR_HIERARCHY; +unsigned IOCTL_HFSC_ADD_CLASS = HFSC_ADD_CLASS; +unsigned IOCTL_HFSC_DEL_CLASS = HFSC_DEL_CLASS; +unsigned IOCTL_HFSC_MOD_CLASS = HFSC_MOD_CLASS; +unsigned IOCTL_HFSC_ADD_FILTER = HFSC_ADD_FILTER; +unsigned IOCTL_HFSC_DEL_FILTER = HFSC_DEL_FILTER; +unsigned IOCTL_HFSC_GETSTATS = HFSC_GETSTATS; +unsigned IOCTL_JOBS_IF_ATTACH = JOBS_IF_ATTACH; +unsigned IOCTL_JOBS_IF_DETACH = JOBS_IF_DETACH; +unsigned IOCTL_JOBS_ENABLE = JOBS_ENABLE; +unsigned IOCTL_JOBS_DISABLE = JOBS_DISABLE; +unsigned IOCTL_JOBS_CLEAR = JOBS_CLEAR; +unsigned IOCTL_JOBS_ADD_CLASS = JOBS_ADD_CLASS; +unsigned IOCTL_JOBS_DEL_CLASS = JOBS_DEL_CLASS; +unsigned IOCTL_JOBS_MOD_CLASS = JOBS_MOD_CLASS; +unsigned IOCTL_JOBS_ADD_FILTER = JOBS_ADD_FILTER; +unsigned IOCTL_JOBS_DEL_FILTER = JOBS_DEL_FILTER; +unsigned IOCTL_JOBS_GETSTATS = JOBS_GETSTATS; +unsigned IOCTL_PRIQ_IF_ATTACH = PRIQ_IF_ATTACH; +unsigned IOCTL_PRIQ_IF_DETACH = PRIQ_IF_DETACH; +unsigned IOCTL_PRIQ_ENABLE = PRIQ_ENABLE; +unsigned IOCTL_PRIQ_DISABLE = PRIQ_DISABLE; +unsigned IOCTL_PRIQ_CLEAR = PRIQ_CLEAR; +unsigned IOCTL_PRIQ_ADD_CLASS = PRIQ_ADD_CLASS; +unsigned IOCTL_PRIQ_DEL_CLASS = PRIQ_DEL_CLASS; +unsigned IOCTL_PRIQ_MOD_CLASS = PRIQ_MOD_CLASS; +unsigned IOCTL_PRIQ_ADD_FILTER = PRIQ_ADD_FILTER; +unsigned IOCTL_PRIQ_DEL_FILTER = PRIQ_DEL_FILTER; +unsigned IOCTL_PRIQ_GETSTATS = PRIQ_GETSTATS; +unsigned IOCTL_RED_IF_ATTACH = RED_IF_ATTACH; +unsigned IOCTL_RED_IF_DETACH = RED_IF_DETACH; +unsigned IOCTL_RED_ENABLE = RED_ENABLE; +unsigned IOCTL_RED_DISABLE = RED_DISABLE; +unsigned IOCTL_RED_CONFIG = RED_CONFIG; +unsigned IOCTL_RED_GETSTATS = RED_GETSTATS; +unsigned IOCTL_RED_SETDEFAULTS = RED_SETDEFAULTS; +unsigned IOCTL_RIO_IF_ATTACH = RIO_IF_ATTACH; +unsigned IOCTL_RIO_IF_DETACH = RIO_IF_DETACH; +unsigned IOCTL_RIO_ENABLE = RIO_ENABLE; +unsigned IOCTL_RIO_DISABLE = RIO_DISABLE; +unsigned IOCTL_RIO_CONFIG = RIO_CONFIG; +unsigned IOCTL_RIO_GETSTATS = RIO_GETSTATS; +unsigned IOCTL_RIO_SETDEFAULTS = RIO_SETDEFAULTS; +unsigned IOCTL_WFQ_IF_ATTACH = WFQ_IF_ATTACH; +unsigned IOCTL_WFQ_IF_DETACH = WFQ_IF_DETACH; +unsigned IOCTL_WFQ_ENABLE = WFQ_ENABLE; +unsigned IOCTL_WFQ_DISABLE = WFQ_DISABLE; +unsigned IOCTL_WFQ_CONFIG = WFQ_CONFIG; +unsigned IOCTL_WFQ_GET_STATS = WFQ_GET_STATS; +unsigned IOCTL_WFQ_GET_QID = WFQ_GET_QID; +unsigned IOCTL_WFQ_SET_WEIGHT = WFQ_SET_WEIGHT; +unsigned IOCTL_CRIOGET = CRIOGET; +unsigned IOCTL_CIOCFSESSION = CIOCFSESSION; +unsigned IOCTL_CIOCKEY = CIOCKEY; +unsigned IOCTL_CIOCNFKEYM = CIOCNFKEYM; +unsigned IOCTL_CIOCNFSESSION = CIOCNFSESSION; +unsigned IOCTL_CIOCNCRYPTRETM = CIOCNCRYPTRETM; +unsigned IOCTL_CIOCNCRYPTRET = CIOCNCRYPTRET; +unsigned IOCTL_CIOCGSESSION = CIOCGSESSION; +unsigned IOCTL_CIOCNGSESSION = CIOCNGSESSION; +unsigned IOCTL_CIOCCRYPT = CIOCCRYPT; +unsigned IOCTL_CIOCNCRYPTM = CIOCNCRYPTM; +unsigned IOCTL_CIOCASYMFEAT = CIOCASYMFEAT; +unsigned IOCTL_APM_IOC_REJECT = APM_IOC_REJECT; +unsigned IOCTL_APM_IOC_STANDBY = APM_IOC_STANDBY; +unsigned IOCTL_APM_IOC_SUSPEND = APM_IOC_SUSPEND; +unsigned IOCTL_OAPM_IOC_GETPOWER = OAPM_IOC_GETPOWER; +unsigned IOCTL_APM_IOC_GETPOWER = APM_IOC_GETPOWER; +unsigned IOCTL_APM_IOC_NEXTEVENT = APM_IOC_NEXTEVENT; +unsigned IOCTL_APM_IOC_DEV_CTL = APM_IOC_DEV_CTL; +unsigned IOCTL_NETBSD_DM_IOCTL = NETBSD_DM_IOCTL; +unsigned IOCTL_DMIO_SETFUNC = DMIO_SETFUNC; +unsigned IOCTL_DMX_START = DMX_START; +unsigned IOCTL_DMX_STOP = DMX_STOP; +unsigned IOCTL_DMX_SET_FILTER = DMX_SET_FILTER; +unsigned IOCTL_DMX_SET_PES_FILTER = DMX_SET_PES_FILTER; +unsigned IOCTL_DMX_SET_BUFFER_SIZE = DMX_SET_BUFFER_SIZE; +unsigned IOCTL_DMX_GET_STC = DMX_GET_STC; +unsigned IOCTL_DMX_ADD_PID = DMX_ADD_PID; +unsigned IOCTL_DMX_REMOVE_PID = DMX_REMOVE_PID; +unsigned IOCTL_DMX_GET_CAPS = DMX_GET_CAPS; +unsigned IOCTL_DMX_SET_SOURCE = DMX_SET_SOURCE; +unsigned IOCTL_FE_READ_STATUS = FE_READ_STATUS; +unsigned IOCTL_FE_READ_BER = FE_READ_BER; +unsigned IOCTL_FE_READ_SNR = FE_READ_SNR; +unsigned IOCTL_FE_READ_SIGNAL_STRENGTH = FE_READ_SIGNAL_STRENGTH; +unsigned IOCTL_FE_READ_UNCORRECTED_BLOCKS = FE_READ_UNCORRECTED_BLOCKS; +unsigned IOCTL_FE_SET_FRONTEND = FE_SET_FRONTEND; +unsigned IOCTL_FE_GET_FRONTEND = FE_GET_FRONTEND; +unsigned IOCTL_FE_GET_EVENT = FE_GET_EVENT; +unsigned IOCTL_FE_GET_INFO = FE_GET_INFO; +unsigned IOCTL_FE_DISEQC_RESET_OVERLOAD = FE_DISEQC_RESET_OVERLOAD; +unsigned IOCTL_FE_DISEQC_SEND_MASTER_CMD = FE_DISEQC_SEND_MASTER_CMD; +unsigned IOCTL_FE_DISEQC_RECV_SLAVE_REPLY = FE_DISEQC_RECV_SLAVE_REPLY; +unsigned IOCTL_FE_DISEQC_SEND_BURST = FE_DISEQC_SEND_BURST; +unsigned IOCTL_FE_SET_TONE = FE_SET_TONE; +unsigned IOCTL_FE_SET_VOLTAGE = FE_SET_VOLTAGE; +unsigned IOCTL_FE_ENABLE_HIGH_LNB_VOLTAGE = FE_ENABLE_HIGH_LNB_VOLTAGE; +unsigned IOCTL_FE_SET_FRONTEND_TUNE_MODE = FE_SET_FRONTEND_TUNE_MODE; +unsigned IOCTL_FE_DISHNETWORK_SEND_LEGACY_CMD = FE_DISHNETWORK_SEND_LEGACY_CMD; +unsigned IOCTL_FILEMON_SET_FD = FILEMON_SET_FD; +unsigned IOCTL_FILEMON_SET_PID = FILEMON_SET_PID; +unsigned IOCTL_HDAUDIO_FGRP_INFO = HDAUDIO_FGRP_INFO; +unsigned IOCTL_HDAUDIO_FGRP_GETCONFIG = HDAUDIO_FGRP_GETCONFIG; +unsigned IOCTL_HDAUDIO_FGRP_SETCONFIG = HDAUDIO_FGRP_SETCONFIG; +unsigned IOCTL_HDAUDIO_FGRP_WIDGET_INFO = HDAUDIO_FGRP_WIDGET_INFO; +unsigned IOCTL_HDAUDIO_FGRP_CODEC_INFO = HDAUDIO_FGRP_CODEC_INFO; +unsigned IOCTL_HDAUDIO_AFG_WIDGET_INFO = HDAUDIO_AFG_WIDGET_INFO; +unsigned IOCTL_HDAUDIO_AFG_CODEC_INFO = HDAUDIO_AFG_CODEC_INFO; +unsigned IOCTL_CEC_GET_PHYS_ADDR = CEC_GET_PHYS_ADDR; +unsigned IOCTL_CEC_GET_LOG_ADDRS = CEC_GET_LOG_ADDRS; +unsigned IOCTL_CEC_SET_LOG_ADDRS = CEC_SET_LOG_ADDRS; +unsigned IOCTL_CEC_GET_VENDOR_ID = CEC_GET_VENDOR_ID; +unsigned IOCTL_HPCFBIO_GCONF = HPCFBIO_GCONF; +unsigned IOCTL_HPCFBIO_SCONF = HPCFBIO_SCONF; +unsigned IOCTL_HPCFBIO_GDSPCONF = HPCFBIO_GDSPCONF; +unsigned IOCTL_HPCFBIO_SDSPCONF = HPCFBIO_SDSPCONF; +unsigned IOCTL_HPCFBIO_GOP = HPCFBIO_GOP; +unsigned IOCTL_HPCFBIO_SOP = HPCFBIO_SOP; +unsigned IOCTL_IOPIOCPT = IOPIOCPT; +unsigned IOCTL_IOPIOCGLCT = IOPIOCGLCT; +unsigned IOCTL_IOPIOCGSTATUS = IOPIOCGSTATUS; +unsigned IOCTL_IOPIOCRECONFIG = IOPIOCRECONFIG; +unsigned IOCTL_IOPIOCGTIDMAP = IOPIOCGTIDMAP; +unsigned IOCTL_SIOCGATHSTATS = SIOCGATHSTATS; +unsigned IOCTL_SIOCGATHDIAG = SIOCGATHDIAG; +unsigned IOCTL_METEORCAPTUR = METEORCAPTUR; +unsigned IOCTL_METEORCAPFRM = METEORCAPFRM; +unsigned IOCTL_METEORSETGEO = METEORSETGEO; +unsigned IOCTL_METEORGETGEO = METEORGETGEO; +unsigned IOCTL_METEORSTATUS = METEORSTATUS; +unsigned IOCTL_METEORSHUE = METEORSHUE; +unsigned IOCTL_METEORGHUE = METEORGHUE; +unsigned IOCTL_METEORSFMT = METEORSFMT; +unsigned IOCTL_METEORGFMT = METEORGFMT; +unsigned IOCTL_METEORSINPUT = METEORSINPUT; +unsigned IOCTL_METEORGINPUT = METEORGINPUT; +unsigned IOCTL_METEORSCHCV = METEORSCHCV; +unsigned IOCTL_METEORGCHCV = METEORGCHCV; +unsigned IOCTL_METEORSCOUNT = METEORSCOUNT; +unsigned IOCTL_METEORGCOUNT = METEORGCOUNT; +unsigned IOCTL_METEORSFPS = METEORSFPS; +unsigned IOCTL_METEORGFPS = METEORGFPS; +unsigned IOCTL_METEORSSIGNAL = METEORSSIGNAL; +unsigned IOCTL_METEORGSIGNAL = METEORGSIGNAL; +unsigned IOCTL_METEORSVIDEO = METEORSVIDEO; +unsigned IOCTL_METEORGVIDEO = METEORGVIDEO; +unsigned IOCTL_METEORSBRIG = METEORSBRIG; +unsigned IOCTL_METEORGBRIG = METEORGBRIG; +unsigned IOCTL_METEORSCSAT = METEORSCSAT; +unsigned IOCTL_METEORGCSAT = METEORGCSAT; +unsigned IOCTL_METEORSCONT = METEORSCONT; +unsigned IOCTL_METEORGCONT = METEORGCONT; +unsigned IOCTL_METEORSHWS = METEORSHWS; +unsigned IOCTL_METEORGHWS = METEORGHWS; +unsigned IOCTL_METEORSVWS = METEORSVWS; +unsigned IOCTL_METEORGVWS = METEORGVWS; +unsigned IOCTL_METEORSTS = METEORSTS; +unsigned IOCTL_METEORGTS = METEORGTS; +unsigned IOCTL_TVTUNER_SETCHNL = TVTUNER_SETCHNL; +unsigned IOCTL_TVTUNER_GETCHNL = TVTUNER_GETCHNL; +unsigned IOCTL_TVTUNER_SETTYPE = TVTUNER_SETTYPE; +unsigned IOCTL_TVTUNER_GETTYPE = TVTUNER_GETTYPE; +unsigned IOCTL_TVTUNER_GETSTATUS = TVTUNER_GETSTATUS; +unsigned IOCTL_TVTUNER_SETFREQ = TVTUNER_SETFREQ; +unsigned IOCTL_TVTUNER_GETFREQ = TVTUNER_GETFREQ; +unsigned IOCTL_TVTUNER_SETAFC = TVTUNER_SETAFC; +unsigned IOCTL_TVTUNER_GETAFC = TVTUNER_GETAFC; +unsigned IOCTL_RADIO_SETMODE = RADIO_SETMODE; +unsigned IOCTL_RADIO_GETMODE = RADIO_GETMODE; +unsigned IOCTL_RADIO_SETFREQ = RADIO_SETFREQ; +unsigned IOCTL_RADIO_GETFREQ = RADIO_GETFREQ; +unsigned IOCTL_METEORSACTPIXFMT = METEORSACTPIXFMT; +unsigned IOCTL_METEORGACTPIXFMT = METEORGACTPIXFMT; +unsigned IOCTL_METEORGSUPPIXFMT = METEORGSUPPIXFMT; +unsigned IOCTL_TVTUNER_GETCHNLSET = TVTUNER_GETCHNLSET; +unsigned IOCTL_REMOTE_GETKEY = REMOTE_GETKEY; +unsigned IOCTL_GDT_IOCTL_GENERAL = GDT_IOCTL_GENERAL; +unsigned IOCTL_GDT_IOCTL_DRVERS = GDT_IOCTL_DRVERS; +unsigned IOCTL_GDT_IOCTL_CTRTYPE = GDT_IOCTL_CTRTYPE; +unsigned IOCTL_GDT_IOCTL_OSVERS = GDT_IOCTL_OSVERS; +unsigned IOCTL_GDT_IOCTL_CTRCNT = GDT_IOCTL_CTRCNT; +unsigned IOCTL_GDT_IOCTL_EVENT = GDT_IOCTL_EVENT; +unsigned IOCTL_GDT_IOCTL_STATIST = GDT_IOCTL_STATIST; +unsigned IOCTL_GDT_IOCTL_RESCAN = GDT_IOCTL_RESCAN; +unsigned IOCTL_ISP_SDBLEV = ISP_SDBLEV; +unsigned IOCTL_ISP_RESETHBA = ISP_RESETHBA; +unsigned IOCTL_ISP_RESCAN = ISP_RESCAN; +unsigned IOCTL_ISP_SETROLE = ISP_SETROLE; +unsigned IOCTL_ISP_GETROLE = ISP_GETROLE; +unsigned IOCTL_ISP_GET_STATS = ISP_GET_STATS; +unsigned IOCTL_ISP_CLR_STATS = ISP_CLR_STATS; +unsigned IOCTL_ISP_FC_LIP = ISP_FC_LIP; +unsigned IOCTL_ISP_FC_GETDINFO = ISP_FC_GETDINFO; +unsigned IOCTL_ISP_GET_FW_CRASH_DUMP = ISP_GET_FW_CRASH_DUMP; +unsigned IOCTL_ISP_FORCE_CRASH_DUMP = ISP_FORCE_CRASH_DUMP; +unsigned IOCTL_ISP_FC_GETHINFO = ISP_FC_GETHINFO; +unsigned IOCTL_ISP_TSK_MGMT = ISP_TSK_MGMT; +unsigned IOCTL_ISP_FC_GETDLIST = ISP_FC_GETDLIST; +unsigned IOCTL_MLXD_STATUS = MLXD_STATUS; +unsigned IOCTL_MLXD_CHECKASYNC = MLXD_CHECKASYNC; +unsigned IOCTL_MLXD_DETACH = MLXD_DETACH; +unsigned IOCTL_MLX_RESCAN_DRIVES = MLX_RESCAN_DRIVES; +unsigned IOCTL_MLX_PAUSE_CHANNEL = MLX_PAUSE_CHANNEL; +unsigned IOCTL_MLX_COMMAND = MLX_COMMAND; +unsigned IOCTL_MLX_REBUILDASYNC = MLX_REBUILDASYNC; +unsigned IOCTL_MLX_REBUILDSTAT = MLX_REBUILDSTAT; +unsigned IOCTL_MLX_GET_SYSDRIVE = MLX_GET_SYSDRIVE; +unsigned IOCTL_MLX_GET_CINFO = MLX_GET_CINFO; +unsigned IOCTL_NVME_PASSTHROUGH_CMD = NVME_PASSTHROUGH_CMD; +unsigned IOCTL_FWCFGIO_SET_INDEX = FWCFGIO_SET_INDEX; +unsigned IOCTL_IRDA_RESET_PARAMS = IRDA_RESET_PARAMS; +unsigned IOCTL_IRDA_SET_PARAMS = IRDA_SET_PARAMS; +unsigned IOCTL_IRDA_GET_SPEEDMASK = IRDA_GET_SPEEDMASK; +unsigned IOCTL_IRDA_GET_TURNAROUNDMASK = IRDA_GET_TURNAROUNDMASK; +unsigned IOCTL_IRFRAMETTY_GET_DEVICE = IRFRAMETTY_GET_DEVICE; +unsigned IOCTL_IRFRAMETTY_GET_DONGLE = IRFRAMETTY_GET_DONGLE; +unsigned IOCTL_IRFRAMETTY_SET_DONGLE = IRFRAMETTY_SET_DONGLE; +unsigned IOCTL_ISV_CMD = ISV_CMD; +unsigned IOCTL_WTQICMD = WTQICMD; +unsigned IOCTL_ISCSI_GET_VERSION = ISCSI_GET_VERSION; +unsigned IOCTL_ISCSI_LOGIN = ISCSI_LOGIN; +unsigned IOCTL_ISCSI_LOGOUT = ISCSI_LOGOUT; +unsigned IOCTL_ISCSI_ADD_CONNECTION = ISCSI_ADD_CONNECTION; +unsigned IOCTL_ISCSI_RESTORE_CONNECTION = ISCSI_RESTORE_CONNECTION; +unsigned IOCTL_ISCSI_REMOVE_CONNECTION = ISCSI_REMOVE_CONNECTION; +unsigned IOCTL_ISCSI_CONNECTION_STATUS = ISCSI_CONNECTION_STATUS; +unsigned IOCTL_ISCSI_SEND_TARGETS = ISCSI_SEND_TARGETS; +unsigned IOCTL_ISCSI_SET_NODE_NAME = ISCSI_SET_NODE_NAME; +unsigned IOCTL_ISCSI_IO_COMMAND = ISCSI_IO_COMMAND; +unsigned IOCTL_ISCSI_REGISTER_EVENT = ISCSI_REGISTER_EVENT; +unsigned IOCTL_ISCSI_DEREGISTER_EVENT = ISCSI_DEREGISTER_EVENT; +unsigned IOCTL_ISCSI_WAIT_EVENT = ISCSI_WAIT_EVENT; +unsigned IOCTL_ISCSI_POLL_EVENT = ISCSI_POLL_EVENT; +unsigned IOCTL_OFIOCGET = OFIOCGET; +unsigned IOCTL_OFIOCSET = OFIOCSET; +unsigned IOCTL_OFIOCNEXTPROP = OFIOCNEXTPROP; +unsigned IOCTL_OFIOCGETOPTNODE = OFIOCGETOPTNODE; +unsigned IOCTL_OFIOCGETNEXT = OFIOCGETNEXT; +unsigned IOCTL_OFIOCGETCHILD = OFIOCGETCHILD; +unsigned IOCTL_OFIOCFINDDEVICE = OFIOCFINDDEVICE; +unsigned IOCTL_AMR_IO_VERSION = AMR_IO_VERSION; +unsigned IOCTL_AMR_IO_COMMAND = AMR_IO_COMMAND; +unsigned IOCTL_MLYIO_COMMAND = MLYIO_COMMAND; +unsigned IOCTL_MLYIO_HEALTH = MLYIO_HEALTH; +unsigned IOCTL_PCI_IOC_CFGREAD = PCI_IOC_CFGREAD; +unsigned IOCTL_PCI_IOC_CFGWRITE = PCI_IOC_CFGWRITE; +unsigned IOCTL_PCI_IOC_BDF_CFGREAD = PCI_IOC_BDF_CFGREAD; +unsigned IOCTL_PCI_IOC_BDF_CFGWRITE = PCI_IOC_BDF_CFGWRITE; +unsigned IOCTL_PCI_IOC_BUSINFO = PCI_IOC_BUSINFO; +unsigned IOCTL_PCI_IOC_DRVNAME = PCI_IOC_DRVNAME; +unsigned IOCTL_PCI_IOC_DRVNAMEONBUS = PCI_IOC_DRVNAMEONBUS; +unsigned IOCTL_TWEIO_COMMAND = TWEIO_COMMAND; +unsigned IOCTL_TWEIO_STATS = TWEIO_STATS; +unsigned IOCTL_TWEIO_AEN_POLL = TWEIO_AEN_POLL; +unsigned IOCTL_TWEIO_AEN_WAIT = TWEIO_AEN_WAIT; +unsigned IOCTL_TWEIO_SET_PARAM = TWEIO_SET_PARAM; +unsigned IOCTL_TWEIO_GET_PARAM = TWEIO_GET_PARAM; +unsigned IOCTL_TWEIO_RESET = TWEIO_RESET; +unsigned IOCTL_TWEIO_ADD_UNIT = TWEIO_ADD_UNIT; +unsigned IOCTL_TWEIO_DEL_UNIT = TWEIO_DEL_UNIT; +unsigned IOCTL_SIOCSCNWDOMAIN = SIOCSCNWDOMAIN; +unsigned IOCTL_SIOCGCNWDOMAIN = SIOCGCNWDOMAIN; +unsigned IOCTL_SIOCSCNWKEY = SIOCSCNWKEY; +unsigned IOCTL_SIOCGCNWSTATUS = SIOCGCNWSTATUS; +unsigned IOCTL_SIOCGCNWSTATS = SIOCGCNWSTATS; +unsigned IOCTL_SIOCGCNWTRAIL = SIOCGCNWTRAIL; +unsigned IOCTL_SIOCGRAYSIGLEV = SIOCGRAYSIGLEV; +unsigned IOCTL_RAIDFRAME_SHUTDOWN = RAIDFRAME_SHUTDOWN; +unsigned IOCTL_RAIDFRAME_TUR = RAIDFRAME_TUR; +unsigned IOCTL_RAIDFRAME_FAIL_DISK = RAIDFRAME_FAIL_DISK; +unsigned IOCTL_RAIDFRAME_CHECK_RECON_STATUS = RAIDFRAME_CHECK_RECON_STATUS; +unsigned IOCTL_RAIDFRAME_REWRITEPARITY = RAIDFRAME_REWRITEPARITY; +unsigned IOCTL_RAIDFRAME_COPYBACK = RAIDFRAME_COPYBACK; +unsigned IOCTL_RAIDFRAME_SPARET_WAIT = RAIDFRAME_SPARET_WAIT; +unsigned IOCTL_RAIDFRAME_SEND_SPARET = RAIDFRAME_SEND_SPARET; +unsigned IOCTL_RAIDFRAME_ABORT_SPARET_WAIT = RAIDFRAME_ABORT_SPARET_WAIT; +unsigned IOCTL_RAIDFRAME_START_ATRACE = RAIDFRAME_START_ATRACE; +unsigned IOCTL_RAIDFRAME_STOP_ATRACE = RAIDFRAME_STOP_ATRACE; +unsigned IOCTL_RAIDFRAME_GET_SIZE = RAIDFRAME_GET_SIZE; +unsigned IOCTL_RAIDFRAME_RESET_ACCTOTALS = RAIDFRAME_RESET_ACCTOTALS; +unsigned IOCTL_RAIDFRAME_KEEP_ACCTOTALS = RAIDFRAME_KEEP_ACCTOTALS; +unsigned IOCTL_RAIDFRAME_GET_COMPONENT_LABEL = RAIDFRAME_GET_COMPONENT_LABEL; +unsigned IOCTL_RAIDFRAME_SET_COMPONENT_LABEL = RAIDFRAME_SET_COMPONENT_LABEL; +unsigned IOCTL_RAIDFRAME_INIT_LABELS = RAIDFRAME_INIT_LABELS; +unsigned IOCTL_RAIDFRAME_ADD_HOT_SPARE = RAIDFRAME_ADD_HOT_SPARE; +unsigned IOCTL_RAIDFRAME_REMOVE_HOT_SPARE = RAIDFRAME_REMOVE_HOT_SPARE; +unsigned IOCTL_RAIDFRAME_REBUILD_IN_PLACE = RAIDFRAME_REBUILD_IN_PLACE; +unsigned IOCTL_RAIDFRAME_CHECK_PARITY = RAIDFRAME_CHECK_PARITY; +unsigned IOCTL_RAIDFRAME_CHECK_PARITYREWRITE_STATUS = + RAIDFRAME_CHECK_PARITYREWRITE_STATUS; +unsigned IOCTL_RAIDFRAME_CHECK_COPYBACK_STATUS = + RAIDFRAME_CHECK_COPYBACK_STATUS; +unsigned IOCTL_RAIDFRAME_SET_AUTOCONFIG = RAIDFRAME_SET_AUTOCONFIG; +unsigned IOCTL_RAIDFRAME_SET_ROOT = RAIDFRAME_SET_ROOT; +unsigned IOCTL_RAIDFRAME_DELETE_COMPONENT = RAIDFRAME_DELETE_COMPONENT; +unsigned IOCTL_RAIDFRAME_INCORPORATE_HOT_SPARE = + RAIDFRAME_INCORPORATE_HOT_SPARE; +unsigned IOCTL_RAIDFRAME_CHECK_RECON_STATUS_EXT = + RAIDFRAME_CHECK_RECON_STATUS_EXT; +unsigned IOCTL_RAIDFRAME_CHECK_PARITYREWRITE_STATUS_EXT = + RAIDFRAME_CHECK_PARITYREWRITE_STATUS_EXT; +unsigned IOCTL_RAIDFRAME_CHECK_COPYBACK_STATUS_EXT = + RAIDFRAME_CHECK_COPYBACK_STATUS_EXT; +unsigned IOCTL_RAIDFRAME_CONFIGURE = RAIDFRAME_CONFIGURE; +unsigned IOCTL_RAIDFRAME_GET_INFO = RAIDFRAME_GET_INFO; +unsigned IOCTL_RAIDFRAME_PARITYMAP_STATUS = RAIDFRAME_PARITYMAP_STATUS; +unsigned IOCTL_RAIDFRAME_PARITYMAP_GET_DISABLE = + RAIDFRAME_PARITYMAP_GET_DISABLE; +unsigned IOCTL_RAIDFRAME_PARITYMAP_SET_DISABLE = + RAIDFRAME_PARITYMAP_SET_DISABLE; +unsigned IOCTL_RAIDFRAME_PARITYMAP_SET_PARAMS = RAIDFRAME_PARITYMAP_SET_PARAMS; +unsigned IOCTL_RAIDFRAME_SET_LAST_UNIT = RAIDFRAME_SET_LAST_UNIT; +unsigned IOCTL_MBPPIOCSPARAM = MBPPIOCSPARAM; +unsigned IOCTL_MBPPIOCGPARAM = MBPPIOCGPARAM; +unsigned IOCTL_MBPPIOCGSTAT = MBPPIOCGSTAT; +unsigned IOCTL_SESIOC_GETNOBJ = SESIOC_GETNOBJ; +unsigned IOCTL_SESIOC_GETOBJMAP = SESIOC_GETOBJMAP; +unsigned IOCTL_SESIOC_GETENCSTAT = SESIOC_GETENCSTAT; +unsigned IOCTL_SESIOC_SETENCSTAT = SESIOC_SETENCSTAT; +unsigned IOCTL_SESIOC_GETOBJSTAT = SESIOC_GETOBJSTAT; +unsigned IOCTL_SESIOC_SETOBJSTAT = SESIOC_SETOBJSTAT; +unsigned IOCTL_SESIOC_GETTEXT = SESIOC_GETTEXT; +unsigned IOCTL_SESIOC_INIT = SESIOC_INIT; +unsigned IOCTL_SUN_DKIOCGGEOM = SUN_DKIOCGGEOM; +unsigned IOCTL_SUN_DKIOCINFO = SUN_DKIOCINFO; +unsigned IOCTL_SUN_DKIOCGPART = SUN_DKIOCGPART; +unsigned IOCTL_FBIOGTYPE = FBIOGTYPE; +unsigned IOCTL_FBIOPUTCMAP = FBIOPUTCMAP; +unsigned IOCTL_FBIOGETCMAP = FBIOGETCMAP; +unsigned IOCTL_FBIOGATTR = FBIOGATTR; +unsigned IOCTL_FBIOSVIDEO = FBIOSVIDEO; +unsigned IOCTL_FBIOGVIDEO = FBIOGVIDEO; +unsigned IOCTL_FBIOSCURSOR = FBIOSCURSOR; +unsigned IOCTL_FBIOGCURSOR = FBIOGCURSOR; +unsigned IOCTL_FBIOSCURPOS = FBIOSCURPOS; +unsigned IOCTL_FBIOGCURPOS = FBIOGCURPOS; +unsigned IOCTL_FBIOGCURMAX = FBIOGCURMAX; +unsigned IOCTL_KIOCTRANS = KIOCTRANS; +unsigned IOCTL_KIOCSETKEY = KIOCSETKEY; +unsigned IOCTL_KIOCGETKEY = KIOCGETKEY; +unsigned IOCTL_KIOCGTRANS = KIOCGTRANS; +unsigned IOCTL_KIOCCMD = KIOCCMD; +unsigned IOCTL_KIOCTYPE = KIOCTYPE; +unsigned IOCTL_KIOCSDIRECT = KIOCSDIRECT; +unsigned IOCTL_KIOCSKEY = KIOCSKEY; +unsigned IOCTL_KIOCGKEY = KIOCGKEY; +unsigned IOCTL_KIOCSLED = KIOCSLED; +unsigned IOCTL_KIOCGLED = KIOCGLED; +unsigned IOCTL_KIOCLAYOUT = KIOCLAYOUT; +unsigned IOCTL_VUIDSFORMAT = VUIDSFORMAT; +unsigned IOCTL_VUIDGFORMAT = VUIDGFORMAT; +unsigned IOCTL_STICIO_GXINFO = STICIO_GXINFO; +unsigned IOCTL_STICIO_RESET = STICIO_RESET; +unsigned IOCTL_STICIO_STARTQ = STICIO_STARTQ; +unsigned IOCTL_STICIO_STOPQ = STICIO_STOPQ; +unsigned IOCTL_UKYOPON_IDENTIFY = UKYOPON_IDENTIFY; +unsigned IOCTL_URIO_SEND_COMMAND = URIO_SEND_COMMAND; +unsigned IOCTL_URIO_RECV_COMMAND = URIO_RECV_COMMAND; +unsigned IOCTL_USB_REQUEST = USB_REQUEST; +unsigned IOCTL_USB_SETDEBUG = USB_SETDEBUG; +unsigned IOCTL_USB_DISCOVER = USB_DISCOVER; +unsigned IOCTL_USB_DEVICEINFO = USB_DEVICEINFO; +unsigned IOCTL_USB_DEVICEINFO_OLD = USB_DEVICEINFO_OLD; +unsigned IOCTL_USB_DEVICESTATS = USB_DEVICESTATS; +unsigned IOCTL_USB_GET_REPORT_DESC = USB_GET_REPORT_DESC; +unsigned IOCTL_USB_SET_IMMED = USB_SET_IMMED; +unsigned IOCTL_USB_GET_REPORT = USB_GET_REPORT; +unsigned IOCTL_USB_SET_REPORT = USB_SET_REPORT; +unsigned IOCTL_USB_GET_REPORT_ID = USB_GET_REPORT_ID; +unsigned IOCTL_USB_GET_CONFIG = USB_GET_CONFIG; +unsigned IOCTL_USB_SET_CONFIG = USB_SET_CONFIG; +unsigned IOCTL_USB_GET_ALTINTERFACE = USB_GET_ALTINTERFACE; +unsigned IOCTL_USB_SET_ALTINTERFACE = USB_SET_ALTINTERFACE; +unsigned IOCTL_USB_GET_NO_ALT = USB_GET_NO_ALT; +unsigned IOCTL_USB_GET_DEVICE_DESC = USB_GET_DEVICE_DESC; +unsigned IOCTL_USB_GET_CONFIG_DESC = USB_GET_CONFIG_DESC; +unsigned IOCTL_USB_GET_INTERFACE_DESC = USB_GET_INTERFACE_DESC; +unsigned IOCTL_USB_GET_ENDPOINT_DESC = USB_GET_ENDPOINT_DESC; +unsigned IOCTL_USB_GET_FULL_DESC = USB_GET_FULL_DESC; +unsigned IOCTL_USB_GET_STRING_DESC = USB_GET_STRING_DESC; +unsigned IOCTL_USB_DO_REQUEST = USB_DO_REQUEST; +unsigned IOCTL_USB_GET_DEVICEINFO = USB_GET_DEVICEINFO; +unsigned IOCTL_USB_GET_DEVICEINFO_OLD = USB_GET_DEVICEINFO_OLD; +unsigned IOCTL_USB_SET_SHORT_XFER = USB_SET_SHORT_XFER; +unsigned IOCTL_USB_SET_TIMEOUT = USB_SET_TIMEOUT; +unsigned IOCTL_USB_SET_BULK_RA = USB_SET_BULK_RA; +unsigned IOCTL_USB_SET_BULK_WB = USB_SET_BULK_WB; +unsigned IOCTL_USB_SET_BULK_RA_OPT = USB_SET_BULK_RA_OPT; +unsigned IOCTL_USB_SET_BULK_WB_OPT = USB_SET_BULK_WB_OPT; +unsigned IOCTL_USB_GET_CM_OVER_DATA = USB_GET_CM_OVER_DATA; +unsigned IOCTL_USB_SET_CM_OVER_DATA = USB_SET_CM_OVER_DATA; +unsigned IOCTL_UTOPPYIOTURBO = UTOPPYIOTURBO; +unsigned IOCTL_UTOPPYIOCANCEL = UTOPPYIOCANCEL; +unsigned IOCTL_UTOPPYIOREBOOT = UTOPPYIOREBOOT; +unsigned IOCTL_UTOPPYIOSTATS = UTOPPYIOSTATS; +unsigned IOCTL_UTOPPYIORENAME = UTOPPYIORENAME; +unsigned IOCTL_UTOPPYIOMKDIR = UTOPPYIOMKDIR; +unsigned IOCTL_UTOPPYIODELETE = UTOPPYIODELETE; +unsigned IOCTL_UTOPPYIOREADDIR = UTOPPYIOREADDIR; +unsigned IOCTL_UTOPPYIOREADFILE = UTOPPYIOREADFILE; +unsigned IOCTL_UTOPPYIOWRITEFILE = UTOPPYIOWRITEFILE; +unsigned IOCTL_DIOSXDCMD = DIOSXDCMD; +unsigned IOCTL_VT_OPENQRY = VT_OPENQRY; +unsigned IOCTL_VT_SETMODE = VT_SETMODE; +unsigned IOCTL_VT_GETMODE = VT_GETMODE; +unsigned IOCTL_VT_RELDISP = VT_RELDISP; +unsigned IOCTL_VT_ACTIVATE = VT_ACTIVATE; +unsigned IOCTL_VT_WAITACTIVE = VT_WAITACTIVE; +unsigned IOCTL_VT_GETACTIVE = VT_GETACTIVE; +unsigned IOCTL_VT_GETSTATE = VT_GETSTATE; +unsigned IOCTL_KDGETKBENT = KDGETKBENT; +unsigned IOCTL_KDGKBMODE = KDGKBMODE; +unsigned IOCTL_KDSKBMODE = KDSKBMODE; +unsigned IOCTL_KDMKTONE = KDMKTONE; +unsigned IOCTL_KDSETMODE = KDSETMODE; +unsigned IOCTL_KDENABIO = KDENABIO; +unsigned IOCTL_KDDISABIO = KDDISABIO; +unsigned IOCTL_KDGKBTYPE = KDGKBTYPE; +unsigned IOCTL_KDGETLED = KDGETLED; +unsigned IOCTL_KDSETLED = KDSETLED; +unsigned IOCTL_KDSETRAD = KDSETRAD; +unsigned IOCTL_VGAPCVTID = VGAPCVTID; +unsigned IOCTL_CONS_GETVERS = CONS_GETVERS; +unsigned IOCTL_WSKBDIO_GTYPE = WSKBDIO_GTYPE; +unsigned IOCTL_WSKBDIO_BELL = WSKBDIO_BELL; +unsigned IOCTL_WSKBDIO_COMPLEXBELL = WSKBDIO_COMPLEXBELL; +unsigned IOCTL_WSKBDIO_SETBELL = WSKBDIO_SETBELL; +unsigned IOCTL_WSKBDIO_GETBELL = WSKBDIO_GETBELL; +unsigned IOCTL_WSKBDIO_SETDEFAULTBELL = WSKBDIO_SETDEFAULTBELL; +unsigned IOCTL_WSKBDIO_GETDEFAULTBELL = WSKBDIO_GETDEFAULTBELL; +unsigned IOCTL_WSKBDIO_SETKEYREPEAT = WSKBDIO_SETKEYREPEAT; +unsigned IOCTL_WSKBDIO_GETKEYREPEAT = WSKBDIO_GETKEYREPEAT; +unsigned IOCTL_WSKBDIO_SETDEFAULTKEYREPEAT = WSKBDIO_SETDEFAULTKEYREPEAT; +unsigned IOCTL_WSKBDIO_GETDEFAULTKEYREPEAT = WSKBDIO_GETDEFAULTKEYREPEAT; +unsigned IOCTL_WSKBDIO_SETLEDS = WSKBDIO_SETLEDS; +unsigned IOCTL_WSKBDIO_GETLEDS = WSKBDIO_GETLEDS; +unsigned IOCTL_WSKBDIO_GETMAP = WSKBDIO_GETMAP; +unsigned IOCTL_WSKBDIO_SETMAP = WSKBDIO_SETMAP; +unsigned IOCTL_WSKBDIO_GETENCODING = WSKBDIO_GETENCODING; +unsigned IOCTL_WSKBDIO_SETENCODING = WSKBDIO_SETENCODING; +unsigned IOCTL_WSKBDIO_SETMODE = WSKBDIO_SETMODE; +unsigned IOCTL_WSKBDIO_GETMODE = WSKBDIO_GETMODE; +unsigned IOCTL_WSKBDIO_SETKEYCLICK = WSKBDIO_SETKEYCLICK; +unsigned IOCTL_WSKBDIO_GETKEYCLICK = WSKBDIO_GETKEYCLICK; +unsigned IOCTL_WSKBDIO_GETSCROLL = WSKBDIO_GETSCROLL; +unsigned IOCTL_WSKBDIO_SETSCROLL = WSKBDIO_SETSCROLL; +unsigned IOCTL_WSKBDIO_SETVERSION = WSKBDIO_SETVERSION; +unsigned IOCTL_WSMOUSEIO_GTYPE = WSMOUSEIO_GTYPE; +unsigned IOCTL_WSMOUSEIO_SRES = WSMOUSEIO_SRES; +unsigned IOCTL_WSMOUSEIO_SSCALE = WSMOUSEIO_SSCALE; +unsigned IOCTL_WSMOUSEIO_SRATE = WSMOUSEIO_SRATE; +unsigned IOCTL_WSMOUSEIO_SCALIBCOORDS = WSMOUSEIO_SCALIBCOORDS; +unsigned IOCTL_WSMOUSEIO_GCALIBCOORDS = WSMOUSEIO_GCALIBCOORDS; +unsigned IOCTL_WSMOUSEIO_GETID = WSMOUSEIO_GETID; +unsigned IOCTL_WSMOUSEIO_GETREPEAT = WSMOUSEIO_GETREPEAT; +unsigned IOCTL_WSMOUSEIO_SETREPEAT = WSMOUSEIO_SETREPEAT; +unsigned IOCTL_WSMOUSEIO_SETVERSION = WSMOUSEIO_SETVERSION; +unsigned IOCTL_WSDISPLAYIO_GTYPE = WSDISPLAYIO_GTYPE; +unsigned IOCTL_WSDISPLAYIO_GINFO = WSDISPLAYIO_GINFO; +unsigned IOCTL_WSDISPLAYIO_GETCMAP = WSDISPLAYIO_GETCMAP; +unsigned IOCTL_WSDISPLAYIO_PUTCMAP = WSDISPLAYIO_PUTCMAP; +unsigned IOCTL_WSDISPLAYIO_GVIDEO = WSDISPLAYIO_GVIDEO; +unsigned IOCTL_WSDISPLAYIO_SVIDEO = WSDISPLAYIO_SVIDEO; +unsigned IOCTL_WSDISPLAYIO_GCURPOS = WSDISPLAYIO_GCURPOS; +unsigned IOCTL_WSDISPLAYIO_SCURPOS = WSDISPLAYIO_SCURPOS; +unsigned IOCTL_WSDISPLAYIO_GCURMAX = WSDISPLAYIO_GCURMAX; +unsigned IOCTL_WSDISPLAYIO_GCURSOR = WSDISPLAYIO_GCURSOR; +unsigned IOCTL_WSDISPLAYIO_SCURSOR = WSDISPLAYIO_SCURSOR; +unsigned IOCTL_WSDISPLAYIO_GMODE = WSDISPLAYIO_GMODE; +unsigned IOCTL_WSDISPLAYIO_SMODE = WSDISPLAYIO_SMODE; +unsigned IOCTL_WSDISPLAYIO_LDFONT = WSDISPLAYIO_LDFONT; +unsigned IOCTL_WSDISPLAYIO_ADDSCREEN = WSDISPLAYIO_ADDSCREEN; +unsigned IOCTL_WSDISPLAYIO_DELSCREEN = WSDISPLAYIO_DELSCREEN; +unsigned IOCTL_WSDISPLAYIO_SFONT = WSDISPLAYIO_SFONT; +unsigned IOCTL__O_WSDISPLAYIO_SETKEYBOARD = _O_WSDISPLAYIO_SETKEYBOARD; +unsigned IOCTL_WSDISPLAYIO_GETPARAM = WSDISPLAYIO_GETPARAM; +unsigned IOCTL_WSDISPLAYIO_SETPARAM = WSDISPLAYIO_SETPARAM; +unsigned IOCTL_WSDISPLAYIO_GETACTIVESCREEN = WSDISPLAYIO_GETACTIVESCREEN; +unsigned IOCTL_WSDISPLAYIO_GETWSCHAR = WSDISPLAYIO_GETWSCHAR; +unsigned IOCTL_WSDISPLAYIO_PUTWSCHAR = WSDISPLAYIO_PUTWSCHAR; +unsigned IOCTL_WSDISPLAYIO_DGSCROLL = WSDISPLAYIO_DGSCROLL; +unsigned IOCTL_WSDISPLAYIO_DSSCROLL = WSDISPLAYIO_DSSCROLL; +unsigned IOCTL_WSDISPLAYIO_GMSGATTRS = WSDISPLAYIO_GMSGATTRS; +unsigned IOCTL_WSDISPLAYIO_SMSGATTRS = WSDISPLAYIO_SMSGATTRS; +unsigned IOCTL_WSDISPLAYIO_GBORDER = WSDISPLAYIO_GBORDER; +unsigned IOCTL_WSDISPLAYIO_SBORDER = WSDISPLAYIO_SBORDER; +unsigned IOCTL_WSDISPLAYIO_SSPLASH = WSDISPLAYIO_SSPLASH; +unsigned IOCTL_WSDISPLAYIO_SPROGRESS = WSDISPLAYIO_SPROGRESS; +unsigned IOCTL_WSDISPLAYIO_LINEBYTES = WSDISPLAYIO_LINEBYTES; +unsigned IOCTL_WSDISPLAYIO_SETVERSION = WSDISPLAYIO_SETVERSION; +unsigned IOCTL_WSMUXIO_ADD_DEVICE = WSMUXIO_ADD_DEVICE; +unsigned IOCTL_WSMUXIO_REMOVE_DEVICE = WSMUXIO_REMOVE_DEVICE; +unsigned IOCTL_WSMUXIO_LIST_DEVICES = WSMUXIO_LIST_DEVICES; +unsigned IOCTL_WSMUXIO_INJECTEVENT = WSMUXIO_INJECTEVENT; +unsigned IOCTL_WSDISPLAYIO_GET_BUSID = WSDISPLAYIO_GET_BUSID; +unsigned IOCTL_WSDISPLAYIO_GET_EDID = WSDISPLAYIO_GET_EDID; +unsigned IOCTL_WSDISPLAYIO_SET_POLLING = WSDISPLAYIO_SET_POLLING; +unsigned IOCTL_WSDISPLAYIO_GET_FBINFO = WSDISPLAYIO_GET_FBINFO; +unsigned IOCTL_WSDISPLAYIO_DOBLIT = WSDISPLAYIO_DOBLIT; +unsigned IOCTL_WSDISPLAYIO_WAITBLIT = WSDISPLAYIO_WAITBLIT; +unsigned IOCTL_BIOCLOCATE = BIOCLOCATE; +unsigned IOCTL_BIOCINQ = BIOCINQ; +unsigned IOCTL_BIOCDISK_NOVOL = BIOCDISK_NOVOL; +unsigned IOCTL_BIOCDISK = BIOCDISK; +unsigned IOCTL_BIOCVOL = BIOCVOL; +unsigned IOCTL_BIOCALARM = BIOCALARM; +unsigned IOCTL_BIOCBLINK = BIOCBLINK; +unsigned IOCTL_BIOCSETSTATE = BIOCSETSTATE; +unsigned IOCTL_BIOCVOLOPS = BIOCVOLOPS; +unsigned IOCTL_MD_GETCONF = MD_GETCONF; +unsigned IOCTL_MD_SETCONF = MD_SETCONF; +unsigned IOCTL_CCDIOCSET = CCDIOCSET; +unsigned IOCTL_CCDIOCCLR = CCDIOCCLR; +unsigned IOCTL_CGDIOCSET = CGDIOCSET; +unsigned IOCTL_CGDIOCCLR = CGDIOCCLR; +unsigned IOCTL_CGDIOCGET = CGDIOCGET; +unsigned IOCTL_FSSIOCSET = FSSIOCSET; +unsigned IOCTL_FSSIOCGET = FSSIOCGET; +unsigned IOCTL_FSSIOCCLR = FSSIOCCLR; +unsigned IOCTL_FSSIOFSET = FSSIOFSET; +unsigned IOCTL_FSSIOFGET = FSSIOFGET; +unsigned IOCTL_BTDEV_ATTACH = BTDEV_ATTACH; +unsigned IOCTL_BTDEV_DETACH = BTDEV_DETACH; +unsigned IOCTL_BTSCO_GETINFO = BTSCO_GETINFO; +unsigned IOCTL_KTTCP_IO_SEND = KTTCP_IO_SEND; +unsigned IOCTL_KTTCP_IO_RECV = KTTCP_IO_RECV; +unsigned IOCTL_IOC_LOCKSTAT_GVERSION = IOC_LOCKSTAT_GVERSION; +unsigned IOCTL_IOC_LOCKSTAT_ENABLE = IOC_LOCKSTAT_ENABLE; +unsigned IOCTL_IOC_LOCKSTAT_DISABLE = IOC_LOCKSTAT_DISABLE; +unsigned IOCTL_VNDIOCSET = VNDIOCSET; +unsigned IOCTL_VNDIOCCLR = VNDIOCCLR; +unsigned IOCTL_VNDIOCGET = VNDIOCGET; +unsigned IOCTL_SPKRTONE = SPKRTONE; +unsigned IOCTL_SPKRTUNE = SPKRTUNE; +unsigned IOCTL_SPKRGETVOL = SPKRGETVOL; +unsigned IOCTL_SPKRSETVOL = SPKRSETVOL; +#if defined(__x86_64__) +unsigned IOCTL_NVMM_IOC_CAPABILITY = NVMM_IOC_CAPABILITY; +unsigned IOCTL_NVMM_IOC_MACHINE_CREATE = NVMM_IOC_MACHINE_CREATE; +unsigned IOCTL_NVMM_IOC_MACHINE_DESTROY = NVMM_IOC_MACHINE_DESTROY; +unsigned IOCTL_NVMM_IOC_MACHINE_CONFIGURE = NVMM_IOC_MACHINE_CONFIGURE; +unsigned IOCTL_NVMM_IOC_VCPU_CREATE = NVMM_IOC_VCPU_CREATE; +unsigned IOCTL_NVMM_IOC_VCPU_DESTROY = NVMM_IOC_VCPU_DESTROY; +unsigned IOCTL_NVMM_IOC_VCPU_CONFIGURE = NVMM_IOC_VCPU_CONFIGURE; +unsigned IOCTL_NVMM_IOC_VCPU_SETSTATE = NVMM_IOC_VCPU_SETSTATE; +unsigned IOCTL_NVMM_IOC_VCPU_GETSTATE = NVMM_IOC_VCPU_GETSTATE; +unsigned IOCTL_NVMM_IOC_VCPU_INJECT = NVMM_IOC_VCPU_INJECT; +unsigned IOCTL_NVMM_IOC_VCPU_RUN = NVMM_IOC_VCPU_RUN; +unsigned IOCTL_NVMM_IOC_GPA_MAP = NVMM_IOC_GPA_MAP; +unsigned IOCTL_NVMM_IOC_GPA_UNMAP = NVMM_IOC_GPA_UNMAP; +unsigned IOCTL_NVMM_IOC_HVA_MAP = NVMM_IOC_HVA_MAP; +unsigned IOCTL_NVMM_IOC_HVA_UNMAP = NVMM_IOC_HVA_UNMAP; +unsigned IOCTL_NVMM_IOC_CTL = NVMM_IOC_CTL; +#endif +unsigned IOCTL_SPI_IOCTL_CONFIGURE = SPI_IOCTL_CONFIGURE; +unsigned IOCTL_SPI_IOCTL_TRANSFER = SPI_IOCTL_TRANSFER; +unsigned IOCTL_AUTOFSREQUEST = AUTOFSREQUEST; +unsigned IOCTL_AUTOFSDONE = AUTOFSDONE; +unsigned IOCTL_BIOCGBLEN = BIOCGBLEN; +unsigned IOCTL_BIOCSBLEN = BIOCSBLEN; +unsigned IOCTL_BIOCSETF = BIOCSETF; +unsigned IOCTL_BIOCFLUSH = BIOCFLUSH; +unsigned IOCTL_BIOCPROMISC = BIOCPROMISC; +unsigned IOCTL_BIOCGDLT = BIOCGDLT; +unsigned IOCTL_BIOCGETIF = BIOCGETIF; +unsigned IOCTL_BIOCSETIF = BIOCSETIF; +unsigned IOCTL_BIOCGSTATS = BIOCGSTATS; +unsigned IOCTL_BIOCGSTATSOLD = BIOCGSTATSOLD; +unsigned IOCTL_BIOCIMMEDIATE = BIOCIMMEDIATE; +unsigned IOCTL_BIOCVERSION = BIOCVERSION; +unsigned IOCTL_BIOCSTCPF = BIOCSTCPF; +unsigned IOCTL_BIOCSUDPF = BIOCSUDPF; +unsigned IOCTL_BIOCGHDRCMPLT = BIOCGHDRCMPLT; +unsigned IOCTL_BIOCSHDRCMPLT = BIOCSHDRCMPLT; +unsigned IOCTL_BIOCSDLT = BIOCSDLT; +unsigned IOCTL_BIOCGDLTLIST = BIOCGDLTLIST; +unsigned IOCTL_BIOCGDIRECTION = BIOCGDIRECTION; +unsigned IOCTL_BIOCSDIRECTION = BIOCSDIRECTION; +unsigned IOCTL_BIOCSRTIMEOUT = BIOCSRTIMEOUT; +unsigned IOCTL_BIOCGRTIMEOUT = BIOCGRTIMEOUT; +unsigned IOCTL_BIOCGFEEDBACK = BIOCGFEEDBACK; +unsigned IOCTL_BIOCSFEEDBACK = BIOCSFEEDBACK; +unsigned IOCTL_GRESADDRS = GRESADDRS; +unsigned IOCTL_GRESADDRD = GRESADDRD; +unsigned IOCTL_GREGADDRS = GREGADDRS; +unsigned IOCTL_GREGADDRD = GREGADDRD; +unsigned IOCTL_GRESPROTO = GRESPROTO; +unsigned IOCTL_GREGPROTO = GREGPROTO; +unsigned IOCTL_GRESSOCK = GRESSOCK; +unsigned IOCTL_GREDSOCK = GREDSOCK; +unsigned IOCTL_PPPIOCGRAWIN = PPPIOCGRAWIN; +unsigned IOCTL_PPPIOCGFLAGS = PPPIOCGFLAGS; +unsigned IOCTL_PPPIOCSFLAGS = PPPIOCSFLAGS; +unsigned IOCTL_PPPIOCGASYNCMAP = PPPIOCGASYNCMAP; +unsigned IOCTL_PPPIOCSASYNCMAP = PPPIOCSASYNCMAP; +unsigned IOCTL_PPPIOCGUNIT = PPPIOCGUNIT; +unsigned IOCTL_PPPIOCGRASYNCMAP = PPPIOCGRASYNCMAP; +unsigned IOCTL_PPPIOCSRASYNCMAP = PPPIOCSRASYNCMAP; +unsigned IOCTL_PPPIOCGMRU = PPPIOCGMRU; +unsigned IOCTL_PPPIOCSMRU = PPPIOCSMRU; +unsigned IOCTL_PPPIOCSMAXCID = PPPIOCSMAXCID; +unsigned IOCTL_PPPIOCGXASYNCMAP = PPPIOCGXASYNCMAP; +unsigned IOCTL_PPPIOCSXASYNCMAP = PPPIOCSXASYNCMAP; +unsigned IOCTL_PPPIOCXFERUNIT = PPPIOCXFERUNIT; +unsigned IOCTL_PPPIOCSCOMPRESS = PPPIOCSCOMPRESS; +unsigned IOCTL_PPPIOCGNPMODE = PPPIOCGNPMODE; +unsigned IOCTL_PPPIOCSNPMODE = PPPIOCSNPMODE; +unsigned IOCTL_PPPIOCGIDLE = PPPIOCGIDLE; +unsigned IOCTL_PPPIOCGMTU = PPPIOCGMTU; +unsigned IOCTL_PPPIOCSMTU = PPPIOCSMTU; +unsigned IOCTL_SIOCGPPPSTATS = SIOCGPPPSTATS; +unsigned IOCTL_SIOCGPPPCSTATS = SIOCGPPPCSTATS; +unsigned IOCTL_IOC_NPF_VERSION = IOC_NPF_VERSION; +unsigned IOCTL_IOC_NPF_SWITCH = IOC_NPF_SWITCH; +unsigned IOCTL_IOC_NPF_LOAD = IOC_NPF_LOAD; +unsigned IOCTL_IOC_NPF_TABLE = IOC_NPF_TABLE; +unsigned IOCTL_IOC_NPF_STATS = IOC_NPF_STATS; +unsigned IOCTL_IOC_NPF_SAVE = IOC_NPF_SAVE; +unsigned IOCTL_IOC_NPF_RULE = IOC_NPF_RULE; +unsigned IOCTL_IOC_NPF_CONN_LOOKUP = IOC_NPF_CONN_LOOKUP; +unsigned IOCTL_IOC_NPF_TABLE_REPLACE = IOC_NPF_TABLE_REPLACE; +unsigned IOCTL_PPPOESETPARMS = PPPOESETPARMS; +unsigned IOCTL_PPPOEGETPARMS = PPPOEGETPARMS; +unsigned IOCTL_PPPOEGETSESSION = PPPOEGETSESSION; +unsigned IOCTL_SPPPGETAUTHCFG = SPPPGETAUTHCFG; +unsigned IOCTL_SPPPSETAUTHCFG = SPPPSETAUTHCFG; +unsigned IOCTL_SPPPGETLCPCFG = SPPPGETLCPCFG; +unsigned IOCTL_SPPPSETLCPCFG = SPPPSETLCPCFG; +unsigned IOCTL_SPPPGETSTATUS = SPPPGETSTATUS; +unsigned IOCTL_SPPPGETSTATUSNCP = SPPPGETSTATUSNCP; +unsigned IOCTL_SPPPGETIDLETO = SPPPGETIDLETO; +unsigned IOCTL_SPPPSETIDLETO = SPPPSETIDLETO; +unsigned IOCTL_SPPPGETAUTHFAILURES = SPPPGETAUTHFAILURES; +unsigned IOCTL_SPPPSETAUTHFAILURE = SPPPSETAUTHFAILURE; +unsigned IOCTL_SPPPSETDNSOPTS = SPPPSETDNSOPTS; +unsigned IOCTL_SPPPGETDNSOPTS = SPPPGETDNSOPTS; +unsigned IOCTL_SPPPGETDNSADDRS = SPPPGETDNSADDRS; +unsigned IOCTL_SPPPSETKEEPALIVE = SPPPSETKEEPALIVE; +unsigned IOCTL_SPPPGETKEEPALIVE = SPPPGETKEEPALIVE; +unsigned IOCTL_SRT_GETNRT = SRT_GETNRT; +unsigned IOCTL_SRT_GETRT = SRT_GETRT; +unsigned IOCTL_SRT_SETRT = SRT_SETRT; +unsigned IOCTL_SRT_DELRT = SRT_DELRT; +unsigned IOCTL_SRT_SFLAGS = SRT_SFLAGS; +unsigned IOCTL_SRT_GFLAGS = SRT_GFLAGS; +unsigned IOCTL_SRT_SGFLAGS = SRT_SGFLAGS; +unsigned IOCTL_SRT_DEBUG = SRT_DEBUG; +unsigned IOCTL_TAPGIFNAME = TAPGIFNAME; +unsigned IOCTL_TUNSDEBUG = TUNSDEBUG; +unsigned IOCTL_TUNGDEBUG = TUNGDEBUG; +unsigned IOCTL_TUNSIFMODE = TUNSIFMODE; +unsigned IOCTL_TUNSLMODE = TUNSLMODE; +unsigned IOCTL_TUNSIFHEAD = TUNSIFHEAD; +unsigned IOCTL_TUNGIFHEAD = TUNGIFHEAD; +unsigned IOCTL_DIOCSTART = DIOCSTART; +unsigned IOCTL_DIOCSTOP = DIOCSTOP; +unsigned IOCTL_DIOCADDRULE = DIOCADDRULE; +unsigned IOCTL_DIOCGETRULES = DIOCGETRULES; +unsigned IOCTL_DIOCGETRULE = DIOCGETRULE; +unsigned IOCTL_DIOCSETLCK = DIOCSETLCK; +unsigned IOCTL_DIOCCLRSTATES = DIOCCLRSTATES; +unsigned IOCTL_DIOCGETSTATE = DIOCGETSTATE; +unsigned IOCTL_DIOCSETSTATUSIF = DIOCSETSTATUSIF; +unsigned IOCTL_DIOCGETSTATUS = DIOCGETSTATUS; +unsigned IOCTL_DIOCCLRSTATUS = DIOCCLRSTATUS; +unsigned IOCTL_DIOCNATLOOK = DIOCNATLOOK; +unsigned IOCTL_DIOCSETDEBUG = DIOCSETDEBUG; +unsigned IOCTL_DIOCGETSTATES = DIOCGETSTATES; +unsigned IOCTL_DIOCCHANGERULE = DIOCCHANGERULE; +unsigned IOCTL_DIOCSETTIMEOUT = DIOCSETTIMEOUT; +unsigned IOCTL_DIOCGETTIMEOUT = DIOCGETTIMEOUT; +unsigned IOCTL_DIOCADDSTATE = DIOCADDSTATE; +unsigned IOCTL_DIOCCLRRULECTRS = DIOCCLRRULECTRS; +unsigned IOCTL_DIOCGETLIMIT = DIOCGETLIMIT; +unsigned IOCTL_DIOCSETLIMIT = DIOCSETLIMIT; +unsigned IOCTL_DIOCKILLSTATES = DIOCKILLSTATES; +unsigned IOCTL_DIOCSTARTALTQ = DIOCSTARTALTQ; +unsigned IOCTL_DIOCSTOPALTQ = DIOCSTOPALTQ; +unsigned IOCTL_DIOCADDALTQ = DIOCADDALTQ; +unsigned IOCTL_DIOCGETALTQS = DIOCGETALTQS; +unsigned IOCTL_DIOCGETALTQ = DIOCGETALTQ; +unsigned IOCTL_DIOCCHANGEALTQ = DIOCCHANGEALTQ; +unsigned IOCTL_DIOCGETQSTATS = DIOCGETQSTATS; +unsigned IOCTL_DIOCBEGINADDRS = DIOCBEGINADDRS; +unsigned IOCTL_DIOCADDADDR = DIOCADDADDR; +unsigned IOCTL_DIOCGETADDRS = DIOCGETADDRS; +unsigned IOCTL_DIOCGETADDR = DIOCGETADDR; +unsigned IOCTL_DIOCCHANGEADDR = DIOCCHANGEADDR; +unsigned IOCTL_DIOCADDSTATES = DIOCADDSTATES; +unsigned IOCTL_DIOCGETRULESETS = DIOCGETRULESETS; +unsigned IOCTL_DIOCGETRULESET = DIOCGETRULESET; +unsigned IOCTL_DIOCRCLRTABLES = DIOCRCLRTABLES; +unsigned IOCTL_DIOCRADDTABLES = DIOCRADDTABLES; +unsigned IOCTL_DIOCRDELTABLES = DIOCRDELTABLES; +unsigned IOCTL_DIOCRGETTABLES = DIOCRGETTABLES; +unsigned IOCTL_DIOCRGETTSTATS = DIOCRGETTSTATS; +unsigned IOCTL_DIOCRCLRTSTATS = DIOCRCLRTSTATS; +unsigned IOCTL_DIOCRCLRADDRS = DIOCRCLRADDRS; +unsigned IOCTL_DIOCRADDADDRS = DIOCRADDADDRS; +unsigned IOCTL_DIOCRDELADDRS = DIOCRDELADDRS; +unsigned IOCTL_DIOCRSETADDRS = DIOCRSETADDRS; +unsigned IOCTL_DIOCRGETADDRS = DIOCRGETADDRS; +unsigned IOCTL_DIOCRGETASTATS = DIOCRGETASTATS; +unsigned IOCTL_DIOCRCLRASTATS = DIOCRCLRASTATS; +unsigned IOCTL_DIOCRTSTADDRS = DIOCRTSTADDRS; +unsigned IOCTL_DIOCRSETTFLAGS = DIOCRSETTFLAGS; +unsigned IOCTL_DIOCRINADEFINE = DIOCRINADEFINE; +unsigned IOCTL_DIOCOSFPFLUSH = DIOCOSFPFLUSH; +unsigned IOCTL_DIOCOSFPADD = DIOCOSFPADD; +unsigned IOCTL_DIOCOSFPGET = DIOCOSFPGET; +unsigned IOCTL_DIOCXBEGIN = DIOCXBEGIN; +unsigned IOCTL_DIOCXCOMMIT = DIOCXCOMMIT; +unsigned IOCTL_DIOCXROLLBACK = DIOCXROLLBACK; +unsigned IOCTL_DIOCGETSRCNODES = DIOCGETSRCNODES; +unsigned IOCTL_DIOCCLRSRCNODES = DIOCCLRSRCNODES; +unsigned IOCTL_DIOCSETHOSTID = DIOCSETHOSTID; +unsigned IOCTL_DIOCIGETIFACES = DIOCIGETIFACES; +unsigned IOCTL_DIOCSETIFFLAG = DIOCSETIFFLAG; +unsigned IOCTL_DIOCCLRIFFLAG = DIOCCLRIFFLAG; +unsigned IOCTL_DIOCKILLSRCNODES = DIOCKILLSRCNODES; +unsigned IOCTL_SLIOCGUNIT = SLIOCGUNIT; +unsigned IOCTL_SIOCGBTINFO = SIOCGBTINFO; +unsigned IOCTL_SIOCGBTINFOA = SIOCGBTINFOA; +unsigned IOCTL_SIOCNBTINFO = SIOCNBTINFO; +unsigned IOCTL_SIOCSBTFLAGS = SIOCSBTFLAGS; +unsigned IOCTL_SIOCSBTPOLICY = SIOCSBTPOLICY; +unsigned IOCTL_SIOCSBTPTYPE = SIOCSBTPTYPE; +unsigned IOCTL_SIOCGBTSTATS = SIOCGBTSTATS; +unsigned IOCTL_SIOCZBTSTATS = SIOCZBTSTATS; +unsigned IOCTL_SIOCBTDUMP = SIOCBTDUMP; +unsigned IOCTL_SIOCSBTSCOMTU = SIOCSBTSCOMTU; +unsigned IOCTL_SIOCGBTFEAT = SIOCGBTFEAT; +unsigned IOCTL_SIOCADNAT = SIOCADNAT; +unsigned IOCTL_SIOCRMNAT = SIOCRMNAT; +unsigned IOCTL_SIOCGNATS = SIOCGNATS; +unsigned IOCTL_SIOCGNATL = SIOCGNATL; +unsigned IOCTL_SIOCPURGENAT = SIOCPURGENAT; +unsigned IOCTL_SIOCCONNECTX = SIOCCONNECTX; +unsigned IOCTL_SIOCCONNECTXDEL = SIOCCONNECTXDEL; +unsigned IOCTL_SIOCSIFINFO_FLAGS = SIOCSIFINFO_FLAGS; +unsigned IOCTL_SIOCAADDRCTL_POLICY = SIOCAADDRCTL_POLICY; +unsigned IOCTL_SIOCDADDRCTL_POLICY = SIOCDADDRCTL_POLICY; +unsigned IOCTL_SMBIOC_OPENSESSION = SMBIOC_OPENSESSION; +unsigned IOCTL_SMBIOC_OPENSHARE = SMBIOC_OPENSHARE; +unsigned IOCTL_SMBIOC_REQUEST = SMBIOC_REQUEST; +unsigned IOCTL_SMBIOC_SETFLAGS = SMBIOC_SETFLAGS; +unsigned IOCTL_SMBIOC_LOOKUP = SMBIOC_LOOKUP; +unsigned IOCTL_SMBIOC_READ = SMBIOC_READ; +unsigned IOCTL_SMBIOC_WRITE = SMBIOC_WRITE; +unsigned IOCTL_AGPIOC_INFO = AGPIOC_INFO; +unsigned IOCTL_AGPIOC_ACQUIRE = AGPIOC_ACQUIRE; +unsigned IOCTL_AGPIOC_RELEASE = AGPIOC_RELEASE; +unsigned IOCTL_AGPIOC_SETUP = AGPIOC_SETUP; +unsigned IOCTL_AGPIOC_ALLOCATE = AGPIOC_ALLOCATE; +unsigned IOCTL_AGPIOC_DEALLOCATE = AGPIOC_DEALLOCATE; +unsigned IOCTL_AGPIOC_BIND = AGPIOC_BIND; +unsigned IOCTL_AGPIOC_UNBIND = AGPIOC_UNBIND; +unsigned IOCTL_AUDIO_GETINFO = AUDIO_GETINFO; +unsigned IOCTL_AUDIO_SETINFO = AUDIO_SETINFO; +unsigned IOCTL_AUDIO_DRAIN = AUDIO_DRAIN; +unsigned IOCTL_AUDIO_FLUSH = AUDIO_FLUSH; +unsigned IOCTL_AUDIO_WSEEK = AUDIO_WSEEK; +unsigned IOCTL_AUDIO_RERROR = AUDIO_RERROR; +unsigned IOCTL_AUDIO_GETDEV = AUDIO_GETDEV; +unsigned IOCTL_AUDIO_GETENC = AUDIO_GETENC; +unsigned IOCTL_AUDIO_GETFD = AUDIO_GETFD; +unsigned IOCTL_AUDIO_SETFD = AUDIO_SETFD; +unsigned IOCTL_AUDIO_PERROR = AUDIO_PERROR; +unsigned IOCTL_AUDIO_GETIOFFS = AUDIO_GETIOFFS; +unsigned IOCTL_AUDIO_GETOOFFS = AUDIO_GETOOFFS; +unsigned IOCTL_AUDIO_GETPROPS = AUDIO_GETPROPS; +unsigned IOCTL_AUDIO_GETBUFINFO = AUDIO_GETBUFINFO; +unsigned IOCTL_AUDIO_SETCHAN = AUDIO_SETCHAN; +unsigned IOCTL_AUDIO_GETCHAN = AUDIO_GETCHAN; +unsigned IOCTL_AUDIO_QUERYFORMAT = AUDIO_QUERYFORMAT; +unsigned IOCTL_AUDIO_GETFORMAT = AUDIO_GETFORMAT; +unsigned IOCTL_AUDIO_SETFORMAT = AUDIO_SETFORMAT; +unsigned IOCTL_AUDIO_MIXER_READ = AUDIO_MIXER_READ; +unsigned IOCTL_AUDIO_MIXER_WRITE = AUDIO_MIXER_WRITE; +unsigned IOCTL_AUDIO_MIXER_DEVINFO = AUDIO_MIXER_DEVINFO; +unsigned IOCTL_ATAIOCCOMMAND = ATAIOCCOMMAND; +unsigned IOCTL_ATABUSIOSCAN = ATABUSIOSCAN; +unsigned IOCTL_ATABUSIORESET = ATABUSIORESET; +unsigned IOCTL_ATABUSIODETACH = ATABUSIODETACH; +unsigned IOCTL_CDIOCPLAYTRACKS = CDIOCPLAYTRACKS; +unsigned IOCTL_CDIOCPLAYBLOCKS = CDIOCPLAYBLOCKS; +unsigned IOCTL_CDIOCREADSUBCHANNEL = CDIOCREADSUBCHANNEL; +unsigned IOCTL_CDIOREADTOCHEADER = CDIOREADTOCHEADER; +unsigned IOCTL_CDIOREADTOCENTRIES = CDIOREADTOCENTRIES; +unsigned IOCTL_CDIOREADMSADDR = CDIOREADMSADDR; +unsigned IOCTL_CDIOCSETPATCH = CDIOCSETPATCH; +unsigned IOCTL_CDIOCGETVOL = CDIOCGETVOL; +unsigned IOCTL_CDIOCSETVOL = CDIOCSETVOL; +unsigned IOCTL_CDIOCSETMONO = CDIOCSETMONO; +unsigned IOCTL_CDIOCSETSTEREO = CDIOCSETSTEREO; +unsigned IOCTL_CDIOCSETMUTE = CDIOCSETMUTE; +unsigned IOCTL_CDIOCSETLEFT = CDIOCSETLEFT; +unsigned IOCTL_CDIOCSETRIGHT = CDIOCSETRIGHT; +unsigned IOCTL_CDIOCSETDEBUG = CDIOCSETDEBUG; +unsigned IOCTL_CDIOCCLRDEBUG = CDIOCCLRDEBUG; +unsigned IOCTL_CDIOCPAUSE = CDIOCPAUSE; +unsigned IOCTL_CDIOCRESUME = CDIOCRESUME; +unsigned IOCTL_CDIOCRESET = CDIOCRESET; +unsigned IOCTL_CDIOCSTART = CDIOCSTART; +unsigned IOCTL_CDIOCSTOP = CDIOCSTOP; +unsigned IOCTL_CDIOCEJECT = CDIOCEJECT; +unsigned IOCTL_CDIOCALLOW = CDIOCALLOW; +unsigned IOCTL_CDIOCPREVENT = CDIOCPREVENT; +unsigned IOCTL_CDIOCCLOSE = CDIOCCLOSE; +unsigned IOCTL_CDIOCPLAYMSF = CDIOCPLAYMSF; +unsigned IOCTL_CDIOCLOADUNLOAD = CDIOCLOADUNLOAD; +unsigned IOCTL_CHIOMOVE = CHIOMOVE; +unsigned IOCTL_CHIOEXCHANGE = CHIOEXCHANGE; +unsigned IOCTL_CHIOPOSITION = CHIOPOSITION; +unsigned IOCTL_CHIOGPICKER = CHIOGPICKER; +unsigned IOCTL_CHIOSPICKER = CHIOSPICKER; +unsigned IOCTL_CHIOGPARAMS = CHIOGPARAMS; +unsigned IOCTL_CHIOIELEM = CHIOIELEM; +unsigned IOCTL_OCHIOGSTATUS = OCHIOGSTATUS; +unsigned IOCTL_CHIOGSTATUS = CHIOGSTATUS; +unsigned IOCTL_CHIOSVOLTAG = CHIOSVOLTAG; +unsigned IOCTL_CLOCKCTL_SETTIMEOFDAY = CLOCKCTL_SETTIMEOFDAY; +unsigned IOCTL_CLOCKCTL_ADJTIME = CLOCKCTL_ADJTIME; +unsigned IOCTL_CLOCKCTL_CLOCK_SETTIME = CLOCKCTL_CLOCK_SETTIME; +unsigned IOCTL_CLOCKCTL_NTP_ADJTIME = CLOCKCTL_NTP_ADJTIME; +unsigned IOCTL_IOC_CPU_SETSTATE = IOC_CPU_SETSTATE; +unsigned IOCTL_IOC_CPU_GETSTATE = IOC_CPU_GETSTATE; +unsigned IOCTL_IOC_CPU_GETCOUNT = IOC_CPU_GETCOUNT; +unsigned IOCTL_IOC_CPU_MAPID = IOC_CPU_MAPID; +unsigned IOCTL_IOC_CPU_UCODE_GET_VERSION = IOC_CPU_UCODE_GET_VERSION; +unsigned IOCTL_IOC_CPU_UCODE_APPLY = IOC_CPU_UCODE_APPLY; +unsigned IOCTL_DIOCGDINFO = DIOCGDINFO; +unsigned IOCTL_DIOCSDINFO = DIOCSDINFO; +unsigned IOCTL_DIOCWDINFO = DIOCWDINFO; +unsigned IOCTL_DIOCRFORMAT = DIOCRFORMAT; +unsigned IOCTL_DIOCWFORMAT = DIOCWFORMAT; +unsigned IOCTL_DIOCSSTEP = DIOCSSTEP; +unsigned IOCTL_DIOCSRETRIES = DIOCSRETRIES; +unsigned IOCTL_DIOCKLABEL = DIOCKLABEL; +unsigned IOCTL_DIOCWLABEL = DIOCWLABEL; +unsigned IOCTL_DIOCSBAD = DIOCSBAD; +unsigned IOCTL_DIOCEJECT = DIOCEJECT; +unsigned IOCTL_ODIOCEJECT = ODIOCEJECT; +unsigned IOCTL_DIOCLOCK = DIOCLOCK; +unsigned IOCTL_DIOCGDEFLABEL = DIOCGDEFLABEL; +unsigned IOCTL_DIOCCLRLABEL = DIOCCLRLABEL; +unsigned IOCTL_DIOCGCACHE = DIOCGCACHE; +unsigned IOCTL_DIOCSCACHE = DIOCSCACHE; +unsigned IOCTL_DIOCCACHESYNC = DIOCCACHESYNC; +unsigned IOCTL_DIOCBSLIST = DIOCBSLIST; +unsigned IOCTL_DIOCBSFLUSH = DIOCBSFLUSH; +unsigned IOCTL_DIOCAWEDGE = DIOCAWEDGE; +unsigned IOCTL_DIOCGWEDGEINFO = DIOCGWEDGEINFO; +unsigned IOCTL_DIOCDWEDGE = DIOCDWEDGE; +unsigned IOCTL_DIOCLWEDGES = DIOCLWEDGES; +unsigned IOCTL_DIOCGSTRATEGY = DIOCGSTRATEGY; +unsigned IOCTL_DIOCSSTRATEGY = DIOCSSTRATEGY; +unsigned IOCTL_DIOCGDISKINFO = DIOCGDISKINFO; +unsigned IOCTL_DIOCTUR = DIOCTUR; +unsigned IOCTL_DIOCMWEDGES = DIOCMWEDGES; +unsigned IOCTL_DIOCGSECTORSIZE = DIOCGSECTORSIZE; +unsigned IOCTL_DIOCGMEDIASIZE = DIOCGMEDIASIZE; +unsigned IOCTL_DIOCRMWEDGES = DIOCRMWEDGES; +unsigned IOCTL_DRVDETACHDEV = DRVDETACHDEV; +unsigned IOCTL_DRVRESCANBUS = DRVRESCANBUS; +unsigned IOCTL_DRVCTLCOMMAND = DRVCTLCOMMAND; +unsigned IOCTL_DRVRESUMEDEV = DRVRESUMEDEV; +unsigned IOCTL_DRVLISTDEV = DRVLISTDEV; +unsigned IOCTL_DRVGETEVENT = DRVGETEVENT; +unsigned IOCTL_DRVSUSPENDDEV = DRVSUSPENDDEV; +unsigned IOCTL_DVD_READ_STRUCT = DVD_READ_STRUCT; +unsigned IOCTL_DVD_WRITE_STRUCT = DVD_WRITE_STRUCT; +unsigned IOCTL_DVD_AUTH = DVD_AUTH; +unsigned IOCTL_ENVSYS_GETDICTIONARY = ENVSYS_GETDICTIONARY; +unsigned IOCTL_ENVSYS_SETDICTIONARY = ENVSYS_SETDICTIONARY; +unsigned IOCTL_ENVSYS_REMOVEPROPS = ENVSYS_REMOVEPROPS; +unsigned IOCTL_ENVSYS_GTREDATA = ENVSYS_GTREDATA; +unsigned IOCTL_ENVSYS_GTREINFO = ENVSYS_GTREINFO; +unsigned IOCTL_KFILTER_BYFILTER = KFILTER_BYFILTER; +unsigned IOCTL_KFILTER_BYNAME = KFILTER_BYNAME; +unsigned IOCTL_FDIOCGETOPTS = FDIOCGETOPTS; +unsigned IOCTL_FDIOCSETOPTS = FDIOCSETOPTS; +unsigned IOCTL_FDIOCSETFORMAT = FDIOCSETFORMAT; +unsigned IOCTL_FDIOCGETFORMAT = FDIOCGETFORMAT; +unsigned IOCTL_FDIOCFORMAT_TRACK = FDIOCFORMAT_TRACK; +unsigned IOCTL_FIOCLEX = FIOCLEX; +unsigned IOCTL_FIONCLEX = FIONCLEX; +unsigned IOCTL_FIOSEEKDATA = FIOSEEKDATA; +unsigned IOCTL_FIOSEEKHOLE = FIOSEEKHOLE; +unsigned IOCTL_FIONREAD = FIONREAD; +unsigned IOCTL_FIONBIO = FIONBIO; +unsigned IOCTL_FIOASYNC = FIOASYNC; +unsigned IOCTL_FIOSETOWN = FIOSETOWN; +unsigned IOCTL_FIOGETOWN = FIOGETOWN; +unsigned IOCTL_OFIOGETBMAP = OFIOGETBMAP; +unsigned IOCTL_FIOGETBMAP = FIOGETBMAP; +unsigned IOCTL_FIONWRITE = FIONWRITE; +unsigned IOCTL_FIONSPACE = FIONSPACE; +unsigned IOCTL_GPIOINFO = GPIOINFO; +unsigned IOCTL_GPIOSET = GPIOSET; +unsigned IOCTL_GPIOUNSET = GPIOUNSET; +unsigned IOCTL_GPIOREAD = GPIOREAD; +unsigned IOCTL_GPIOWRITE = GPIOWRITE; +unsigned IOCTL_GPIOTOGGLE = GPIOTOGGLE; +unsigned IOCTL_GPIOATTACH = GPIOATTACH; +unsigned IOCTL_PTIOCNETBSD = PTIOCNETBSD; +unsigned IOCTL_PTIOCSUNOS = PTIOCSUNOS; +unsigned IOCTL_PTIOCLINUX = PTIOCLINUX; +unsigned IOCTL_PTIOCFREEBSD = PTIOCFREEBSD; +unsigned IOCTL_PTIOCULTRIX = PTIOCULTRIX; +unsigned IOCTL_TIOCHPCL = TIOCHPCL; +unsigned IOCTL_TIOCGETP = TIOCGETP; +unsigned IOCTL_TIOCSETP = TIOCSETP; +unsigned IOCTL_TIOCSETN = TIOCSETN; +unsigned IOCTL_TIOCSETC = TIOCSETC; +unsigned IOCTL_TIOCGETC = TIOCGETC; +unsigned IOCTL_TIOCLBIS = TIOCLBIS; +unsigned IOCTL_TIOCLBIC = TIOCLBIC; +unsigned IOCTL_TIOCLSET = TIOCLSET; +unsigned IOCTL_TIOCLGET = TIOCLGET; +unsigned IOCTL_TIOCSLTC = TIOCSLTC; +unsigned IOCTL_TIOCGLTC = TIOCGLTC; +unsigned IOCTL_OTIOCCONS = OTIOCCONS; +unsigned IOCTL_JOY_SETTIMEOUT = JOY_SETTIMEOUT; +unsigned IOCTL_JOY_GETTIMEOUT = JOY_GETTIMEOUT; +unsigned IOCTL_JOY_SET_X_OFFSET = JOY_SET_X_OFFSET; +unsigned IOCTL_JOY_SET_Y_OFFSET = JOY_SET_Y_OFFSET; +unsigned IOCTL_JOY_GET_X_OFFSET = JOY_GET_X_OFFSET; +unsigned IOCTL_JOY_GET_Y_OFFSET = JOY_GET_Y_OFFSET; +unsigned IOCTL_OKIOCGSYMBOL = OKIOCGSYMBOL; +unsigned IOCTL_OKIOCGVALUE = OKIOCGVALUE; +unsigned IOCTL_KIOCGSIZE = KIOCGSIZE; +unsigned IOCTL_KIOCGVALUE = KIOCGVALUE; +unsigned IOCTL_KIOCGSYMBOL = KIOCGSYMBOL; +unsigned IOCTL_LUAINFO = LUAINFO; +unsigned IOCTL_LUACREATE = LUACREATE; +unsigned IOCTL_LUADESTROY = LUADESTROY; +unsigned IOCTL_LUAREQUIRE = LUAREQUIRE; +unsigned IOCTL_LUALOAD = LUALOAD; +unsigned IOCTL_MIDI_PRETIME = MIDI_PRETIME; +unsigned IOCTL_MIDI_MPUMODE = MIDI_MPUMODE; +unsigned IOCTL_MIDI_MPUCMD = MIDI_MPUCMD; +unsigned IOCTL_SEQUENCER_RESET = SEQUENCER_RESET; +unsigned IOCTL_SEQUENCER_SYNC = SEQUENCER_SYNC; +unsigned IOCTL_SEQUENCER_INFO = SEQUENCER_INFO; +unsigned IOCTL_SEQUENCER_CTRLRATE = SEQUENCER_CTRLRATE; +unsigned IOCTL_SEQUENCER_GETOUTCOUNT = SEQUENCER_GETOUTCOUNT; +unsigned IOCTL_SEQUENCER_GETINCOUNT = SEQUENCER_GETINCOUNT; +unsigned IOCTL_SEQUENCER_RESETSAMPLES = SEQUENCER_RESETSAMPLES; +unsigned IOCTL_SEQUENCER_NRSYNTHS = SEQUENCER_NRSYNTHS; +unsigned IOCTL_SEQUENCER_NRMIDIS = SEQUENCER_NRMIDIS; +unsigned IOCTL_SEQUENCER_THRESHOLD = SEQUENCER_THRESHOLD; +unsigned IOCTL_SEQUENCER_MEMAVL = SEQUENCER_MEMAVL; +unsigned IOCTL_SEQUENCER_PANIC = SEQUENCER_PANIC; +unsigned IOCTL_SEQUENCER_OUTOFBAND = SEQUENCER_OUTOFBAND; +unsigned IOCTL_SEQUENCER_GETTIME = SEQUENCER_GETTIME; +unsigned IOCTL_SEQUENCER_TMR_TIMEBASE = SEQUENCER_TMR_TIMEBASE; +unsigned IOCTL_SEQUENCER_TMR_START = SEQUENCER_TMR_START; +unsigned IOCTL_SEQUENCER_TMR_STOP = SEQUENCER_TMR_STOP; +unsigned IOCTL_SEQUENCER_TMR_CONTINUE = SEQUENCER_TMR_CONTINUE; +unsigned IOCTL_SEQUENCER_TMR_TEMPO = SEQUENCER_TMR_TEMPO; +unsigned IOCTL_SEQUENCER_TMR_SOURCE = SEQUENCER_TMR_SOURCE; +unsigned IOCTL_SEQUENCER_TMR_METRONOME = SEQUENCER_TMR_METRONOME; +unsigned IOCTL_SEQUENCER_TMR_SELECT = SEQUENCER_TMR_SELECT; +unsigned IOCTL_MTIOCTOP = MTIOCTOP; +unsigned IOCTL_MTIOCGET = MTIOCGET; +unsigned IOCTL_MTIOCIEOT = MTIOCIEOT; +unsigned IOCTL_MTIOCEEOT = MTIOCEEOT; +unsigned IOCTL_MTIOCRDSPOS = MTIOCRDSPOS; +unsigned IOCTL_MTIOCRDHPOS = MTIOCRDHPOS; +unsigned IOCTL_MTIOCSLOCATE = MTIOCSLOCATE; +unsigned IOCTL_MTIOCHLOCATE = MTIOCHLOCATE; +unsigned IOCTL_POWER_EVENT_RECVDICT = POWER_EVENT_RECVDICT; +unsigned IOCTL_POWER_IOC_GET_TYPE = POWER_IOC_GET_TYPE; +unsigned IOCTL_RIOCGINFO = RIOCGINFO; +unsigned IOCTL_RIOCSINFO = RIOCSINFO; +unsigned IOCTL_RIOCSSRCH = RIOCSSRCH; +unsigned IOCTL_RNDGETENTCNT = RNDGETENTCNT; +unsigned IOCTL_RNDGETSRCNUM = RNDGETSRCNUM; +unsigned IOCTL_RNDGETSRCNAME = RNDGETSRCNAME; +unsigned IOCTL_RNDCTL = RNDCTL; +unsigned IOCTL_RNDADDDATA = RNDADDDATA; +unsigned IOCTL_RNDGETPOOLSTAT = RNDGETPOOLSTAT; +unsigned IOCTL_RNDGETESTNUM = RNDGETESTNUM; +unsigned IOCTL_RNDGETESTNAME = RNDGETESTNAME; +unsigned IOCTL_SCIOCGET = SCIOCGET; +unsigned IOCTL_SCIOCSET = SCIOCSET; +unsigned IOCTL_SCIOCRESTART = SCIOCRESTART; +unsigned IOCTL_SCIOC_USE_ADF = SCIOC_USE_ADF; +unsigned IOCTL_SCIOCCOMMAND = SCIOCCOMMAND; +unsigned IOCTL_SCIOCDEBUG = SCIOCDEBUG; +unsigned IOCTL_SCIOCIDENTIFY = SCIOCIDENTIFY; +unsigned IOCTL_OSCIOCIDENTIFY = OSCIOCIDENTIFY; +unsigned IOCTL_SCIOCDECONFIG = SCIOCDECONFIG; +unsigned IOCTL_SCIOCRECONFIG = SCIOCRECONFIG; +unsigned IOCTL_SCIOCRESET = SCIOCRESET; +unsigned IOCTL_SCBUSIOSCAN = SCBUSIOSCAN; +unsigned IOCTL_SCBUSIORESET = SCBUSIORESET; +unsigned IOCTL_SCBUSIODETACH = SCBUSIODETACH; +unsigned IOCTL_SCBUSACCEL = SCBUSACCEL; +unsigned IOCTL_SCBUSIOLLSCAN = SCBUSIOLLSCAN; +unsigned IOCTL_SIOCSHIWAT = SIOCSHIWAT; +unsigned IOCTL_SIOCGHIWAT = SIOCGHIWAT; +unsigned IOCTL_SIOCSLOWAT = SIOCSLOWAT; +unsigned IOCTL_SIOCGLOWAT = SIOCGLOWAT; +unsigned IOCTL_SIOCATMARK = SIOCATMARK; +unsigned IOCTL_SIOCSPGRP = SIOCSPGRP; +unsigned IOCTL_SIOCGPGRP = SIOCGPGRP; +unsigned IOCTL_SIOCPEELOFF = SIOCPEELOFF; +unsigned IOCTL_SIOCADDRT = SIOCADDRT; +unsigned IOCTL_SIOCDELRT = SIOCDELRT; +unsigned IOCTL_SIOCSIFADDR = SIOCSIFADDR; +unsigned IOCTL_SIOCGIFADDR = SIOCGIFADDR; +unsigned IOCTL_SIOCSIFDSTADDR = SIOCSIFDSTADDR; +unsigned IOCTL_SIOCGIFDSTADDR = SIOCGIFDSTADDR; +unsigned IOCTL_SIOCSIFFLAGS = SIOCSIFFLAGS; +unsigned IOCTL_SIOCGIFFLAGS = SIOCGIFFLAGS; +unsigned IOCTL_SIOCGIFBRDADDR = SIOCGIFBRDADDR; +unsigned IOCTL_SIOCSIFBRDADDR = SIOCSIFBRDADDR; +unsigned IOCTL_SIOCGIFCONF = SIOCGIFCONF; +unsigned IOCTL_SIOCGIFNETMASK = SIOCGIFNETMASK; +unsigned IOCTL_SIOCSIFNETMASK = SIOCSIFNETMASK; +unsigned IOCTL_SIOCGIFMETRIC = SIOCGIFMETRIC; +unsigned IOCTL_SIOCSIFMETRIC = SIOCSIFMETRIC; +unsigned IOCTL_SIOCDIFADDR = SIOCDIFADDR; +unsigned IOCTL_SIOCAIFADDR = SIOCAIFADDR; +unsigned IOCTL_SIOCGIFALIAS = SIOCGIFALIAS; +unsigned IOCTL_SIOCGIFAFLAG_IN = SIOCGIFAFLAG_IN; +unsigned IOCTL_SIOCALIFADDR = SIOCALIFADDR; +unsigned IOCTL_SIOCGLIFADDR = SIOCGLIFADDR; +unsigned IOCTL_SIOCDLIFADDR = SIOCDLIFADDR; +unsigned IOCTL_SIOCSIFADDRPREF = SIOCSIFADDRPREF; +unsigned IOCTL_SIOCGIFADDRPREF = SIOCGIFADDRPREF; +unsigned IOCTL_SIOCADDMULTI = SIOCADDMULTI; +unsigned IOCTL_SIOCDELMULTI = SIOCDELMULTI; +unsigned IOCTL_SIOCGETVIFCNT = SIOCGETVIFCNT; +unsigned IOCTL_SIOCGETSGCNT = SIOCGETSGCNT; +unsigned IOCTL_SIOCSIFMEDIA = SIOCSIFMEDIA; +unsigned IOCTL_SIOCGIFMEDIA = SIOCGIFMEDIA; +unsigned IOCTL_SIOCSIFGENERIC = SIOCSIFGENERIC; +unsigned IOCTL_SIOCGIFGENERIC = SIOCGIFGENERIC; +unsigned IOCTL_SIOCSIFPHYADDR = SIOCSIFPHYADDR; +unsigned IOCTL_SIOCGIFPSRCADDR = SIOCGIFPSRCADDR; +unsigned IOCTL_SIOCGIFPDSTADDR = SIOCGIFPDSTADDR; +unsigned IOCTL_SIOCDIFPHYADDR = SIOCDIFPHYADDR; +unsigned IOCTL_SIOCSLIFPHYADDR = SIOCSLIFPHYADDR; +unsigned IOCTL_SIOCGLIFPHYADDR = SIOCGLIFPHYADDR; +unsigned IOCTL_SIOCSIFMTU = SIOCSIFMTU; +unsigned IOCTL_SIOCGIFMTU = SIOCGIFMTU; +unsigned IOCTL_SIOCSDRVSPEC = SIOCSDRVSPEC; +unsigned IOCTL_SIOCGDRVSPEC = SIOCGDRVSPEC; +unsigned IOCTL_SIOCIFCREATE = SIOCIFCREATE; +unsigned IOCTL_SIOCIFDESTROY = SIOCIFDESTROY; +unsigned IOCTL_SIOCIFGCLONERS = SIOCIFGCLONERS; +unsigned IOCTL_SIOCGIFDLT = SIOCGIFDLT; +unsigned IOCTL_SIOCGIFCAP = SIOCGIFCAP; +unsigned IOCTL_SIOCSIFCAP = SIOCSIFCAP; +unsigned IOCTL_SIOCSVH = SIOCSVH; +unsigned IOCTL_SIOCGVH = SIOCGVH; +unsigned IOCTL_SIOCINITIFADDR = SIOCINITIFADDR; +unsigned IOCTL_SIOCGIFDATA = SIOCGIFDATA; +unsigned IOCTL_SIOCZIFDATA = SIOCZIFDATA; +unsigned IOCTL_SIOCGLINKSTR = SIOCGLINKSTR; +unsigned IOCTL_SIOCSLINKSTR = SIOCSLINKSTR; +unsigned IOCTL_SIOCGETHERCAP = SIOCGETHERCAP; +unsigned IOCTL_SIOCGIFINDEX = SIOCGIFINDEX; +unsigned IOCTL_SIOCSETHERCAP = SIOCSETHERCAP; +unsigned IOCTL_SIOCSIFDESCR = SIOCSIFDESCR; +unsigned IOCTL_SIOCGIFDESCR = SIOCGIFDESCR; +unsigned IOCTL_SIOCGUMBINFO = SIOCGUMBINFO; +unsigned IOCTL_SIOCSUMBPARAM = SIOCSUMBPARAM; +unsigned IOCTL_SIOCGUMBPARAM = SIOCGUMBPARAM; +unsigned IOCTL_SIOCSETPFSYNC = SIOCSETPFSYNC; +unsigned IOCTL_SIOCGETPFSYNC = SIOCGETPFSYNC; +unsigned IOCTL_PPS_IOC_CREATE = PPS_IOC_CREATE; +unsigned IOCTL_PPS_IOC_DESTROY = PPS_IOC_DESTROY; +unsigned IOCTL_PPS_IOC_SETPARAMS = PPS_IOC_SETPARAMS; +unsigned IOCTL_PPS_IOC_GETPARAMS = PPS_IOC_GETPARAMS; +unsigned IOCTL_PPS_IOC_GETCAP = PPS_IOC_GETCAP; +unsigned IOCTL_PPS_IOC_FETCH = PPS_IOC_FETCH; +unsigned IOCTL_PPS_IOC_KCBIND = PPS_IOC_KCBIND; +unsigned IOCTL_TIOCEXCL = TIOCEXCL; +unsigned IOCTL_TIOCNXCL = TIOCNXCL; +unsigned IOCTL_TIOCFLUSH = TIOCFLUSH; +unsigned IOCTL_TIOCGETA = TIOCGETA; +unsigned IOCTL_TIOCSETA = TIOCSETA; +unsigned IOCTL_TIOCSETAW = TIOCSETAW; +unsigned IOCTL_TIOCSETAF = TIOCSETAF; +unsigned IOCTL_TIOCGETD = TIOCGETD; +unsigned IOCTL_TIOCSETD = TIOCSETD; +unsigned IOCTL_TIOCGLINED = TIOCGLINED; +unsigned IOCTL_TIOCSLINED = TIOCSLINED; +unsigned IOCTL_TIOCSBRK = TIOCSBRK; +unsigned IOCTL_TIOCCBRK = TIOCCBRK; +unsigned IOCTL_TIOCSDTR = TIOCSDTR; +unsigned IOCTL_TIOCCDTR = TIOCCDTR; +unsigned IOCTL_TIOCGPGRP = TIOCGPGRP; +unsigned IOCTL_TIOCSPGRP = TIOCSPGRP; +unsigned IOCTL_TIOCOUTQ = TIOCOUTQ; +unsigned IOCTL_TIOCSTI = TIOCSTI; +unsigned IOCTL_TIOCNOTTY = TIOCNOTTY; +unsigned IOCTL_TIOCPKT = TIOCPKT; +unsigned IOCTL_TIOCSTOP = TIOCSTOP; +unsigned IOCTL_TIOCSTART = TIOCSTART; +unsigned IOCTL_TIOCMSET = TIOCMSET; +unsigned IOCTL_TIOCMBIS = TIOCMBIS; +unsigned IOCTL_TIOCMBIC = TIOCMBIC; +unsigned IOCTL_TIOCMGET = TIOCMGET; +unsigned IOCTL_TIOCREMOTE = TIOCREMOTE; +unsigned IOCTL_TIOCGWINSZ = TIOCGWINSZ; +unsigned IOCTL_TIOCSWINSZ = TIOCSWINSZ; +unsigned IOCTL_TIOCUCNTL = TIOCUCNTL; +unsigned IOCTL_TIOCSTAT = TIOCSTAT; +unsigned IOCTL_TIOCGSID = TIOCGSID; +unsigned IOCTL_TIOCCONS = TIOCCONS; +unsigned IOCTL_TIOCSCTTY = TIOCSCTTY; +unsigned IOCTL_TIOCEXT = TIOCEXT; +unsigned IOCTL_TIOCSIG = TIOCSIG; +unsigned IOCTL_TIOCDRAIN = TIOCDRAIN; +unsigned IOCTL_TIOCGFLAGS = TIOCGFLAGS; +unsigned IOCTL_TIOCSFLAGS = TIOCSFLAGS; +unsigned IOCTL_TIOCDCDTIMESTAMP = TIOCDCDTIMESTAMP; +unsigned IOCTL_TIOCRCVFRAME = TIOCRCVFRAME; +unsigned IOCTL_TIOCXMTFRAME = TIOCXMTFRAME; +unsigned IOCTL_TIOCPTMGET = TIOCPTMGET; +unsigned IOCTL_TIOCGRANTPT = TIOCGRANTPT; +unsigned IOCTL_TIOCPTSNAME = TIOCPTSNAME; +unsigned IOCTL_TIOCSQSIZE = TIOCSQSIZE; +unsigned IOCTL_TIOCGQSIZE = TIOCGQSIZE; +unsigned IOCTL_VERIEXEC_LOAD = VERIEXEC_LOAD; +unsigned IOCTL_VERIEXEC_TABLESIZE = VERIEXEC_TABLESIZE; +unsigned IOCTL_VERIEXEC_DELETE = VERIEXEC_DELETE; +unsigned IOCTL_VERIEXEC_QUERY = VERIEXEC_QUERY; +unsigned IOCTL_VERIEXEC_DUMP = VERIEXEC_DUMP; +unsigned IOCTL_VERIEXEC_FLUSH = VERIEXEC_FLUSH; +unsigned IOCTL_VIDIOC_QUERYCAP = VIDIOC_QUERYCAP; +unsigned IOCTL_VIDIOC_RESERVED = VIDIOC_RESERVED; +unsigned IOCTL_VIDIOC_ENUM_FMT = VIDIOC_ENUM_FMT; +unsigned IOCTL_VIDIOC_G_FMT = VIDIOC_G_FMT; +unsigned IOCTL_VIDIOC_S_FMT = VIDIOC_S_FMT; +unsigned IOCTL_VIDIOC_REQBUFS = VIDIOC_REQBUFS; +unsigned IOCTL_VIDIOC_QUERYBUF = VIDIOC_QUERYBUF; +unsigned IOCTL_VIDIOC_G_FBUF = VIDIOC_G_FBUF; +unsigned IOCTL_VIDIOC_S_FBUF = VIDIOC_S_FBUF; +unsigned IOCTL_VIDIOC_OVERLAY = VIDIOC_OVERLAY; +unsigned IOCTL_VIDIOC_QBUF = VIDIOC_QBUF; +unsigned IOCTL_VIDIOC_DQBUF = VIDIOC_DQBUF; +unsigned IOCTL_VIDIOC_STREAMON = VIDIOC_STREAMON; +unsigned IOCTL_VIDIOC_STREAMOFF = VIDIOC_STREAMOFF; +unsigned IOCTL_VIDIOC_G_PARM = VIDIOC_G_PARM; +unsigned IOCTL_VIDIOC_S_PARM = VIDIOC_S_PARM; +unsigned IOCTL_VIDIOC_G_STD = VIDIOC_G_STD; +unsigned IOCTL_VIDIOC_S_STD = VIDIOC_S_STD; +unsigned IOCTL_VIDIOC_ENUMSTD = VIDIOC_ENUMSTD; +unsigned IOCTL_VIDIOC_ENUMINPUT = VIDIOC_ENUMINPUT; +unsigned IOCTL_VIDIOC_G_CTRL = VIDIOC_G_CTRL; +unsigned IOCTL_VIDIOC_S_CTRL = VIDIOC_S_CTRL; +unsigned IOCTL_VIDIOC_G_TUNER = VIDIOC_G_TUNER; +unsigned IOCTL_VIDIOC_S_TUNER = VIDIOC_S_TUNER; +unsigned IOCTL_VIDIOC_G_AUDIO = VIDIOC_G_AUDIO; +unsigned IOCTL_VIDIOC_S_AUDIO = VIDIOC_S_AUDIO; +unsigned IOCTL_VIDIOC_QUERYCTRL = VIDIOC_QUERYCTRL; +unsigned IOCTL_VIDIOC_QUERYMENU = VIDIOC_QUERYMENU; +unsigned IOCTL_VIDIOC_G_INPUT = VIDIOC_G_INPUT; +unsigned IOCTL_VIDIOC_S_INPUT = VIDIOC_S_INPUT; +unsigned IOCTL_VIDIOC_G_OUTPUT = VIDIOC_G_OUTPUT; +unsigned IOCTL_VIDIOC_S_OUTPUT = VIDIOC_S_OUTPUT; +unsigned IOCTL_VIDIOC_ENUMOUTPUT = VIDIOC_ENUMOUTPUT; +unsigned IOCTL_VIDIOC_G_AUDOUT = VIDIOC_G_AUDOUT; +unsigned IOCTL_VIDIOC_S_AUDOUT = VIDIOC_S_AUDOUT; +unsigned IOCTL_VIDIOC_G_MODULATOR = VIDIOC_G_MODULATOR; +unsigned IOCTL_VIDIOC_S_MODULATOR = VIDIOC_S_MODULATOR; +unsigned IOCTL_VIDIOC_G_FREQUENCY = VIDIOC_G_FREQUENCY; +unsigned IOCTL_VIDIOC_S_FREQUENCY = VIDIOC_S_FREQUENCY; +unsigned IOCTL_VIDIOC_CROPCAP = VIDIOC_CROPCAP; +unsigned IOCTL_VIDIOC_G_CROP = VIDIOC_G_CROP; +unsigned IOCTL_VIDIOC_S_CROP = VIDIOC_S_CROP; +unsigned IOCTL_VIDIOC_G_JPEGCOMP = VIDIOC_G_JPEGCOMP; +unsigned IOCTL_VIDIOC_S_JPEGCOMP = VIDIOC_S_JPEGCOMP; +unsigned IOCTL_VIDIOC_QUERYSTD = VIDIOC_QUERYSTD; +unsigned IOCTL_VIDIOC_TRY_FMT = VIDIOC_TRY_FMT; +unsigned IOCTL_VIDIOC_ENUMAUDIO = VIDIOC_ENUMAUDIO; +unsigned IOCTL_VIDIOC_ENUMAUDOUT = VIDIOC_ENUMAUDOUT; +unsigned IOCTL_VIDIOC_G_PRIORITY = VIDIOC_G_PRIORITY; +unsigned IOCTL_VIDIOC_S_PRIORITY = VIDIOC_S_PRIORITY; +unsigned IOCTL_VIDIOC_ENUM_FRAMESIZES = VIDIOC_ENUM_FRAMESIZES; +unsigned IOCTL_VIDIOC_ENUM_FRAMEINTERVALS = VIDIOC_ENUM_FRAMEINTERVALS; +unsigned IOCTL_WDOGIOC_GMODE = WDOGIOC_GMODE; +unsigned IOCTL_WDOGIOC_SMODE = WDOGIOC_SMODE; +unsigned IOCTL_WDOGIOC_WHICH = WDOGIOC_WHICH; +unsigned IOCTL_WDOGIOC_TICKLE = WDOGIOC_TICKLE; +unsigned IOCTL_WDOGIOC_GTICKLER = WDOGIOC_GTICKLER; +unsigned IOCTL_WDOGIOC_GWDOGS = WDOGIOC_GWDOGS; +unsigned IOCTL_KCOV_IOC_SETBUFSIZE = KCOV_IOC_SETBUFSIZE; +unsigned IOCTL_KCOV_IOC_ENABLE = KCOV_IOC_ENABLE; +unsigned IOCTL_KCOV_IOC_DISABLE = KCOV_IOC_DISABLE; +unsigned IOCTL_IPMICTL_RECEIVE_MSG_TRUNC = IPMICTL_RECEIVE_MSG_TRUNC; +unsigned IOCTL_IPMICTL_RECEIVE_MSG = IPMICTL_RECEIVE_MSG; +unsigned IOCTL_IPMICTL_SEND_COMMAND = IPMICTL_SEND_COMMAND; +unsigned IOCTL_IPMICTL_REGISTER_FOR_CMD = IPMICTL_REGISTER_FOR_CMD; +unsigned IOCTL_IPMICTL_UNREGISTER_FOR_CMD = IPMICTL_UNREGISTER_FOR_CMD; +unsigned IOCTL_IPMICTL_SET_GETS_EVENTS_CMD = IPMICTL_SET_GETS_EVENTS_CMD; +unsigned IOCTL_IPMICTL_SET_MY_ADDRESS_CMD = IPMICTL_SET_MY_ADDRESS_CMD; +unsigned IOCTL_IPMICTL_GET_MY_ADDRESS_CMD = IPMICTL_GET_MY_ADDRESS_CMD; +unsigned IOCTL_IPMICTL_SET_MY_LUN_CMD = IPMICTL_SET_MY_LUN_CMD; +unsigned IOCTL_IPMICTL_GET_MY_LUN_CMD = IPMICTL_GET_MY_LUN_CMD; +unsigned IOCTL_SNDCTL_DSP_RESET = SNDCTL_DSP_RESET; +unsigned IOCTL_SNDCTL_DSP_SYNC = SNDCTL_DSP_SYNC; +unsigned IOCTL_SNDCTL_DSP_SPEED = SNDCTL_DSP_SPEED; +unsigned IOCTL_SOUND_PCM_READ_RATE = SOUND_PCM_READ_RATE; +unsigned IOCTL_SNDCTL_DSP_STEREO = SNDCTL_DSP_STEREO; +unsigned IOCTL_SNDCTL_DSP_GETBLKSIZE = SNDCTL_DSP_GETBLKSIZE; +unsigned IOCTL_SNDCTL_DSP_SETFMT = SNDCTL_DSP_SETFMT; +unsigned IOCTL_SOUND_PCM_READ_BITS = SOUND_PCM_READ_BITS; +unsigned IOCTL_SNDCTL_DSP_CHANNELS = SNDCTL_DSP_CHANNELS; +unsigned IOCTL_SOUND_PCM_READ_CHANNELS = SOUND_PCM_READ_CHANNELS; +unsigned IOCTL_SOUND_PCM_WRITE_FILTER = SOUND_PCM_WRITE_FILTER; +unsigned IOCTL_SOUND_PCM_READ_FILTER = SOUND_PCM_READ_FILTER; +unsigned IOCTL_SNDCTL_DSP_POST = SNDCTL_DSP_POST; +unsigned IOCTL_SNDCTL_DSP_SUBDIVIDE = SNDCTL_DSP_SUBDIVIDE; +unsigned IOCTL_SNDCTL_DSP_SETFRAGMENT = SNDCTL_DSP_SETFRAGMENT; +unsigned IOCTL_SNDCTL_DSP_GETFMTS = SNDCTL_DSP_GETFMTS; +unsigned IOCTL_SNDCTL_DSP_GETOSPACE = SNDCTL_DSP_GETOSPACE; +unsigned IOCTL_SNDCTL_DSP_GETISPACE = SNDCTL_DSP_GETISPACE; +unsigned IOCTL_SNDCTL_DSP_NONBLOCK = SNDCTL_DSP_NONBLOCK; +unsigned IOCTL_SNDCTL_DSP_GETCAPS = SNDCTL_DSP_GETCAPS; +unsigned IOCTL_SNDCTL_DSP_GETTRIGGER = SNDCTL_DSP_GETTRIGGER; +unsigned IOCTL_SNDCTL_DSP_SETTRIGGER = SNDCTL_DSP_SETTRIGGER; +unsigned IOCTL_SNDCTL_DSP_GETIPTR = SNDCTL_DSP_GETIPTR; +unsigned IOCTL_SNDCTL_DSP_GETOPTR = SNDCTL_DSP_GETOPTR; +unsigned IOCTL_SNDCTL_DSP_MAPINBUF = SNDCTL_DSP_MAPINBUF; +unsigned IOCTL_SNDCTL_DSP_MAPOUTBUF = SNDCTL_DSP_MAPOUTBUF; +unsigned IOCTL_SNDCTL_DSP_SETSYNCRO = SNDCTL_DSP_SETSYNCRO; +unsigned IOCTL_SNDCTL_DSP_SETDUPLEX = SNDCTL_DSP_SETDUPLEX; +unsigned IOCTL_SNDCTL_DSP_PROFILE = SNDCTL_DSP_PROFILE; +unsigned IOCTL_SNDCTL_DSP_GETODELAY = SNDCTL_DSP_GETODELAY; +unsigned IOCTL_SOUND_MIXER_INFO = SOUND_MIXER_INFO; +unsigned IOCTL_SOUND_OLD_MIXER_INFO = SOUND_OLD_MIXER_INFO; +unsigned IOCTL_OSS_GETVERSION = OSS_GETVERSION; +unsigned IOCTL_SNDCTL_SYSINFO = SNDCTL_SYSINFO; +unsigned IOCTL_SNDCTL_AUDIOINFO = SNDCTL_AUDIOINFO; +unsigned IOCTL_SNDCTL_ENGINEINFO = SNDCTL_ENGINEINFO; +unsigned IOCTL_SNDCTL_DSP_GETPLAYVOL = SNDCTL_DSP_GETPLAYVOL; +unsigned IOCTL_SNDCTL_DSP_SETPLAYVOL = SNDCTL_DSP_SETPLAYVOL; +unsigned IOCTL_SNDCTL_DSP_GETRECVOL = SNDCTL_DSP_GETRECVOL; +unsigned IOCTL_SNDCTL_DSP_SETRECVOL = SNDCTL_DSP_SETRECVOL; +unsigned IOCTL_SNDCTL_DSP_SKIP = SNDCTL_DSP_SKIP; +unsigned IOCTL_SNDCTL_DSP_SILENCE = SNDCTL_DSP_SILENCE; + +const int si_SEGV_MAPERR = SEGV_MAPERR; +const int si_SEGV_ACCERR = SEGV_ACCERR; + +const int modctl_load = MODCTL_LOAD; +const int modctl_unload = MODCTL_UNLOAD; +const int modctl_stat = MODCTL_STAT; +const int modctl_exists = MODCTL_EXISTS; + +const unsigned SHA1_CTX_sz = sizeof(SHA1_CTX); +const unsigned SHA1_return_length = SHA1_DIGEST_STRING_LENGTH; + +const unsigned MD4_CTX_sz = sizeof(MD4_CTX); +const unsigned MD4_return_length = MD4_DIGEST_STRING_LENGTH; + +const unsigned RMD160_CTX_sz = sizeof(RMD160_CTX); +const unsigned RMD160_return_length = RMD160_DIGEST_STRING_LENGTH; + +const unsigned MD5_CTX_sz = sizeof(MD5_CTX); +const unsigned MD5_return_length = MD5_DIGEST_STRING_LENGTH; + +const unsigned fpos_t_sz = sizeof(fpos_t); + +const unsigned MD2_CTX_sz = sizeof(MD2_CTX); +const unsigned MD2_return_length = MD2_DIGEST_STRING_LENGTH; + +#define SHA2_CONST(LEN) \ + const unsigned SHA##LEN##_CTX_sz = sizeof(SHA##LEN##_CTX); \ + const unsigned SHA##LEN##_return_length = SHA##LEN##_DIGEST_STRING_LENGTH; \ + const unsigned SHA##LEN##_block_length = SHA##LEN##_BLOCK_LENGTH; \ + const unsigned SHA##LEN##_digest_length = SHA##LEN##_DIGEST_LENGTH + +SHA2_CONST(224); +SHA2_CONST(256); +SHA2_CONST(384); +SHA2_CONST(512); + +#undef SHA2_CONST + +const int unvis_valid = UNVIS_VALID; +const int unvis_validpush = UNVIS_VALIDPUSH; +} // namespace __sanitizer + +using namespace __sanitizer; + +COMPILER_CHECK(sizeof(__sanitizer_pthread_attr_t) >= sizeof(pthread_attr_t)); + +COMPILER_CHECK(sizeof(socklen_t) == sizeof(unsigned)); +CHECK_TYPE_SIZE(pthread_key_t); + +// There are more undocumented fields in dl_phdr_info that we are not interested +// in. +COMPILER_CHECK(sizeof(__sanitizer_dl_phdr_info) <= sizeof(dl_phdr_info)); +CHECK_SIZE_AND_OFFSET(dl_phdr_info, dlpi_addr); +CHECK_SIZE_AND_OFFSET(dl_phdr_info, dlpi_name); +CHECK_SIZE_AND_OFFSET(dl_phdr_info, dlpi_phdr); +CHECK_SIZE_AND_OFFSET(dl_phdr_info, dlpi_phnum); + +CHECK_TYPE_SIZE(glob_t); +CHECK_SIZE_AND_OFFSET(glob_t, gl_pathc); +CHECK_SIZE_AND_OFFSET(glob_t, gl_pathv); +CHECK_SIZE_AND_OFFSET(glob_t, gl_offs); +CHECK_SIZE_AND_OFFSET(glob_t, gl_flags); +CHECK_SIZE_AND_OFFSET(glob_t, gl_closedir); +CHECK_SIZE_AND_OFFSET(glob_t, gl_readdir); +CHECK_SIZE_AND_OFFSET(glob_t, gl_opendir); +CHECK_SIZE_AND_OFFSET(glob_t, gl_lstat); +CHECK_SIZE_AND_OFFSET(glob_t, gl_stat); + +CHECK_TYPE_SIZE(addrinfo); +CHECK_SIZE_AND_OFFSET(addrinfo, ai_flags); +CHECK_SIZE_AND_OFFSET(addrinfo, ai_family); +CHECK_SIZE_AND_OFFSET(addrinfo, ai_socktype); +CHECK_SIZE_AND_OFFSET(addrinfo, ai_protocol); +CHECK_SIZE_AND_OFFSET(addrinfo, ai_protocol); +CHECK_SIZE_AND_OFFSET(addrinfo, ai_addrlen); +CHECK_SIZE_AND_OFFSET(addrinfo, ai_canonname); +CHECK_SIZE_AND_OFFSET(addrinfo, ai_addr); + +CHECK_TYPE_SIZE(hostent); +CHECK_SIZE_AND_OFFSET(hostent, h_name); +CHECK_SIZE_AND_OFFSET(hostent, h_aliases); +CHECK_SIZE_AND_OFFSET(hostent, h_addrtype); +CHECK_SIZE_AND_OFFSET(hostent, h_length); +CHECK_SIZE_AND_OFFSET(hostent, h_addr_list); + +CHECK_TYPE_SIZE(iovec); +CHECK_SIZE_AND_OFFSET(iovec, iov_base); +CHECK_SIZE_AND_OFFSET(iovec, iov_len); + +CHECK_TYPE_SIZE(msghdr); +CHECK_SIZE_AND_OFFSET(msghdr, msg_name); +CHECK_SIZE_AND_OFFSET(msghdr, msg_namelen); +CHECK_SIZE_AND_OFFSET(msghdr, msg_iov); +CHECK_SIZE_AND_OFFSET(msghdr, msg_iovlen); +CHECK_SIZE_AND_OFFSET(msghdr, msg_control); +CHECK_SIZE_AND_OFFSET(msghdr, msg_controllen); +CHECK_SIZE_AND_OFFSET(msghdr, msg_flags); + +CHECK_TYPE_SIZE(cmsghdr); +CHECK_SIZE_AND_OFFSET(cmsghdr, cmsg_len); +CHECK_SIZE_AND_OFFSET(cmsghdr, cmsg_level); +CHECK_SIZE_AND_OFFSET(cmsghdr, cmsg_type); + +COMPILER_CHECK(sizeof(__sanitizer_dirent) <= sizeof(dirent)); +CHECK_SIZE_AND_OFFSET(dirent, d_fileno); +CHECK_SIZE_AND_OFFSET(dirent, d_reclen); + +CHECK_TYPE_SIZE(ifconf); +CHECK_SIZE_AND_OFFSET(ifconf, ifc_len); +CHECK_SIZE_AND_OFFSET(ifconf, ifc_ifcu); + +CHECK_TYPE_SIZE(pollfd); +CHECK_SIZE_AND_OFFSET(pollfd, fd); +CHECK_SIZE_AND_OFFSET(pollfd, events); +CHECK_SIZE_AND_OFFSET(pollfd, revents); + +CHECK_TYPE_SIZE(nfds_t); + +CHECK_TYPE_SIZE(sigset_t); + +COMPILER_CHECK(sizeof(__sanitizer_sigaction) == sizeof(struct sigaction)); +// Can't write checks for sa_handler and sa_sigaction due to them being +// preprocessor macros. +CHECK_STRUCT_SIZE_AND_OFFSET(sigaction, sa_mask); + +CHECK_TYPE_SIZE(wordexp_t); +CHECK_SIZE_AND_OFFSET(wordexp_t, we_wordc); +CHECK_SIZE_AND_OFFSET(wordexp_t, we_wordv); +CHECK_SIZE_AND_OFFSET(wordexp_t, we_offs); + +COMPILER_CHECK(sizeof(__sanitizer_FILE) <= sizeof(FILE)); +CHECK_SIZE_AND_OFFSET(FILE, _p); +CHECK_SIZE_AND_OFFSET(FILE, _r); +CHECK_SIZE_AND_OFFSET(FILE, _w); +CHECK_SIZE_AND_OFFSET(FILE, _flags); +CHECK_SIZE_AND_OFFSET(FILE, _file); +CHECK_SIZE_AND_OFFSET(FILE, _bf); +CHECK_SIZE_AND_OFFSET(FILE, _lbfsize); +CHECK_SIZE_AND_OFFSET(FILE, _cookie); +CHECK_SIZE_AND_OFFSET(FILE, _close); +CHECK_SIZE_AND_OFFSET(FILE, _read); +CHECK_SIZE_AND_OFFSET(FILE, _seek); +CHECK_SIZE_AND_OFFSET(FILE, _write); +CHECK_SIZE_AND_OFFSET(FILE, _ext); +CHECK_SIZE_AND_OFFSET(FILE, _up); +CHECK_SIZE_AND_OFFSET(FILE, _ur); +CHECK_SIZE_AND_OFFSET(FILE, _ubuf); +CHECK_SIZE_AND_OFFSET(FILE, _nbuf); +CHECK_SIZE_AND_OFFSET(FILE, _flush); +CHECK_SIZE_AND_OFFSET(FILE, _lb_unused); +CHECK_SIZE_AND_OFFSET(FILE, _blksize); +CHECK_SIZE_AND_OFFSET(FILE, _offset); + +CHECK_TYPE_SIZE(tm); +CHECK_SIZE_AND_OFFSET(tm, tm_sec); +CHECK_SIZE_AND_OFFSET(tm, tm_min); +CHECK_SIZE_AND_OFFSET(tm, tm_hour); +CHECK_SIZE_AND_OFFSET(tm, tm_mday); +CHECK_SIZE_AND_OFFSET(tm, tm_mon); +CHECK_SIZE_AND_OFFSET(tm, tm_year); +CHECK_SIZE_AND_OFFSET(tm, tm_wday); +CHECK_SIZE_AND_OFFSET(tm, tm_yday); +CHECK_SIZE_AND_OFFSET(tm, tm_isdst); +CHECK_SIZE_AND_OFFSET(tm, tm_gmtoff); +CHECK_SIZE_AND_OFFSET(tm, tm_zone); + +CHECK_TYPE_SIZE(ether_addr); + +CHECK_TYPE_SIZE(ipc_perm); +CHECK_SIZE_AND_OFFSET(ipc_perm, _key); +CHECK_SIZE_AND_OFFSET(ipc_perm, _seq); +CHECK_SIZE_AND_OFFSET(ipc_perm, uid); +CHECK_SIZE_AND_OFFSET(ipc_perm, gid); +CHECK_SIZE_AND_OFFSET(ipc_perm, cuid); +CHECK_SIZE_AND_OFFSET(ipc_perm, cgid); +CHECK_SIZE_AND_OFFSET(ipc_perm, mode); + +CHECK_TYPE_SIZE(shmid_ds); +CHECK_SIZE_AND_OFFSET(shmid_ds, shm_perm); +CHECK_SIZE_AND_OFFSET(shmid_ds, shm_segsz); +CHECK_SIZE_AND_OFFSET(shmid_ds, shm_atime); +CHECK_SIZE_AND_OFFSET(shmid_ds, shm_dtime); +CHECK_SIZE_AND_OFFSET(shmid_ds, shm_ctime); +CHECK_SIZE_AND_OFFSET(shmid_ds, shm_cpid); +CHECK_SIZE_AND_OFFSET(shmid_ds, shm_lpid); +CHECK_SIZE_AND_OFFSET(shmid_ds, shm_nattch); + +CHECK_TYPE_SIZE(clock_t); + +CHECK_TYPE_SIZE(ifaddrs); +CHECK_SIZE_AND_OFFSET(ifaddrs, ifa_next); +CHECK_SIZE_AND_OFFSET(ifaddrs, ifa_name); +CHECK_SIZE_AND_OFFSET(ifaddrs, ifa_addr); +CHECK_SIZE_AND_OFFSET(ifaddrs, ifa_netmask); +// Compare against the union, because we can't reach into the union in a +// compliant way. +#ifdef ifa_dstaddr +#undef ifa_dstaddr +#endif +CHECK_SIZE_AND_OFFSET(ifaddrs, ifa_dstaddr); +CHECK_SIZE_AND_OFFSET(ifaddrs, ifa_data); + +CHECK_TYPE_SIZE(timeb); +CHECK_SIZE_AND_OFFSET(timeb, time); +CHECK_SIZE_AND_OFFSET(timeb, millitm); +CHECK_SIZE_AND_OFFSET(timeb, timezone); +CHECK_SIZE_AND_OFFSET(timeb, dstflag); + +CHECK_TYPE_SIZE(passwd); +CHECK_SIZE_AND_OFFSET(passwd, pw_name); +CHECK_SIZE_AND_OFFSET(passwd, pw_passwd); +CHECK_SIZE_AND_OFFSET(passwd, pw_uid); +CHECK_SIZE_AND_OFFSET(passwd, pw_gid); +CHECK_SIZE_AND_OFFSET(passwd, pw_dir); +CHECK_SIZE_AND_OFFSET(passwd, pw_shell); + +CHECK_SIZE_AND_OFFSET(passwd, pw_gecos); + +CHECK_TYPE_SIZE(group); +CHECK_SIZE_AND_OFFSET(group, gr_name); +CHECK_SIZE_AND_OFFSET(group, gr_passwd); +CHECK_SIZE_AND_OFFSET(group, gr_gid); +CHECK_SIZE_AND_OFFSET(group, gr_mem); + +CHECK_TYPE_SIZE(modctl_load_t); +CHECK_SIZE_AND_OFFSET(modctl_load_t, ml_filename); +CHECK_SIZE_AND_OFFSET(modctl_load_t, ml_flags); +CHECK_SIZE_AND_OFFSET(modctl_load_t, ml_props); +CHECK_SIZE_AND_OFFSET(modctl_load_t, ml_propslen); + +// Compat with 9.0 +struct statvfs90 { + unsigned long f_flag; + unsigned long f_bsize; + unsigned long f_frsize; + unsigned long f_iosize; + + u64 f_blocks; + u64 f_bfree; + u64 f_bavail; + u64 f_bresvd; + + u64 f_files; + u64 f_ffree; + u64 f_favail; + u64 f_fresvd; + + u64 f_syncreads; + u64 f_syncwrites; + + u64 f_asyncreads; + u64 f_asyncwrites; + + struct { + s32 __fsid_val[2]; + } f_fsidx; + unsigned long f_fsid; + unsigned long f_namemax; + u32 f_owner; + + u32 f_spare[4]; + + char f_fstypename[32]; + char f_mntonname[32]; + char f_mntfromname[32]; +}; +unsigned struct_statvfs90_sz = sizeof(struct statvfs90); + +#endif // SANITIZER_NETBSD diff --git a/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_platform_limits_netbsd.h b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_platform_limits_netbsd.h new file mode 100644 index 0000000000..dc6eb59b28 --- /dev/null +++ b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_platform_limits_netbsd.h @@ -0,0 +1,2421 @@ +//===-- sanitizer_platform_limits_netbsd.h --------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file is a part of Sanitizer common code. +// +// Sizes and layouts of platform-specific NetBSD data structures. +//===----------------------------------------------------------------------===// + +#ifndef SANITIZER_PLATFORM_LIMITS_NETBSD_H +#define SANITIZER_PLATFORM_LIMITS_NETBSD_H + +#if SANITIZER_NETBSD + +#include "sanitizer_internal_defs.h" +#include "sanitizer_platform.h" + +namespace __sanitizer { +void *__sanitizer_get_link_map_by_dlopen_handle(void *handle); +#define GET_LINK_MAP_BY_DLOPEN_HANDLE(handle) \ + (link_map *)__sanitizer_get_link_map_by_dlopen_handle(handle) + +extern unsigned struct_utsname_sz; +extern unsigned struct_stat_sz; +extern unsigned struct_rusage_sz; +extern unsigned siginfo_t_sz; +extern unsigned struct_itimerval_sz; +extern unsigned pthread_t_sz; +extern unsigned pthread_mutex_t_sz; +extern unsigned pthread_cond_t_sz; +extern unsigned pid_t_sz; +extern unsigned timeval_sz; +extern unsigned uid_t_sz; +extern unsigned gid_t_sz; +extern unsigned mbstate_t_sz; +extern unsigned struct_timezone_sz; +extern unsigned struct_tms_sz; +extern unsigned struct_itimerspec_sz; +extern unsigned struct_sigevent_sz; +extern unsigned struct_stack_t_sz; +extern unsigned struct_sched_param_sz; +extern unsigned struct_statfs_sz; +extern unsigned struct_sockaddr_sz; +unsigned ucontext_t_sz(void *ctx); + +extern unsigned struct_rlimit_sz; +extern unsigned struct_utimbuf_sz; +extern unsigned struct_timespec_sz; +extern unsigned struct_sembuf_sz; + +extern unsigned struct_kevent_sz; +extern unsigned struct_FTS_sz; +extern unsigned struct_FTSENT_sz; + +extern unsigned struct_regex_sz; +extern unsigned struct_regmatch_sz; + +extern unsigned struct_fstab_sz; + +struct __sanitizer_regmatch { + OFF_T rm_so; + OFF_T rm_eo; +}; + +typedef struct __sanitizer_modctl_load { + const char *ml_filename; + int ml_flags; + const char *ml_props; + uptr ml_propslen; +} __sanitizer_modctl_load_t; +extern const int modctl_load; +extern const int modctl_unload; +extern const int modctl_stat; +extern const int modctl_exists; + +union __sanitizer_sigval { + int sival_int; + uptr sival_ptr; +}; + +struct __sanitizer_sigevent { + int sigev_notify; + int sigev_signo; + union __sanitizer_sigval sigev_value; + uptr sigev_notify_function; + uptr sigev_notify_attributes; +}; + +struct __sanitizer_aiocb { + u64 aio_offset; + uptr aio_buf; + uptr aio_nbytes; + int aio_fildes; + int aio_lio_opcode; + int aio_reqprio; + struct __sanitizer_sigevent aio_sigevent; + int _state; + int _errno; + long _retval; +}; + +struct __sanitizer_sem_t { + uptr data[5]; +}; + +struct __sanitizer_ipc_perm { + u32 uid; + u32 gid; + u32 cuid; + u32 cgid; + u32 mode; + unsigned short _seq; + long _key; +}; + +struct __sanitizer_shmid_ds { + __sanitizer_ipc_perm shm_perm; + unsigned long shm_segsz; + u32 shm_lpid; + u32 shm_cpid; + unsigned int shm_nattch; + u64 shm_atime; + u64 shm_dtime; + u64 shm_ctime; + void *_shm_internal; +}; + +struct __sanitizer_protoent { + char *p_name; + char **p_aliases; + int p_proto; +}; + +struct __sanitizer_netent { + char *n_name; + char **n_aliases; + int n_addrtype; + u32 n_net; +}; + +extern unsigned struct_msqid_ds_sz; +extern unsigned struct_mq_attr_sz; +extern unsigned struct_timex_sz; +extern unsigned struct_statvfs_sz; + +struct __sanitizer_iovec { + void *iov_base; + uptr iov_len; +}; + +struct __sanitizer_ifaddrs { + struct __sanitizer_ifaddrs *ifa_next; + char *ifa_name; + unsigned int ifa_flags; + void *ifa_addr; // (struct sockaddr *) + void *ifa_netmask; // (struct sockaddr *) + void *ifa_dstaddr; // (struct sockaddr *) + void *ifa_data; + unsigned int ifa_addrflags; +}; + +typedef unsigned int __sanitizer_socklen_t; + +typedef unsigned __sanitizer_pthread_key_t; + +typedef long long __sanitizer_time_t; +typedef int __sanitizer_suseconds_t; + +struct __sanitizer_timeval { + __sanitizer_time_t tv_sec; + __sanitizer_suseconds_t tv_usec; +}; + +struct __sanitizer_itimerval { + struct __sanitizer_timeval it_interval; + struct __sanitizer_timeval it_value; +}; + +struct __sanitizer_timespec { + __sanitizer_time_t tv_sec; + long tv_nsec; +}; + +struct __sanitizer_passwd { + char *pw_name; + char *pw_passwd; + int pw_uid; + int pw_gid; + __sanitizer_time_t pw_change; + char *pw_class; + char *pw_gecos; + char *pw_dir; + char *pw_shell; + __sanitizer_time_t pw_expire; +}; + +struct __sanitizer_group { + char *gr_name; + char *gr_passwd; + int gr_gid; + char **gr_mem; +}; + +struct __sanitizer_timeb { + __sanitizer_time_t time; + unsigned short millitm; + short timezone; + short dstflag; +}; + +struct __sanitizer_ether_addr { + u8 octet[6]; +}; + +struct __sanitizer_tm { + int tm_sec; + int tm_min; + int tm_hour; + int tm_mday; + int tm_mon; + int tm_year; + int tm_wday; + int tm_yday; + int tm_isdst; + long int tm_gmtoff; + const char *tm_zone; +}; + +struct __sanitizer_msghdr { + void *msg_name; + unsigned msg_namelen; + struct __sanitizer_iovec *msg_iov; + unsigned msg_iovlen; + void *msg_control; + unsigned msg_controllen; + int msg_flags; +}; + +struct __sanitizer_mmsghdr { + struct __sanitizer_msghdr msg_hdr; + unsigned int msg_len; +}; + +struct __sanitizer_cmsghdr { + unsigned cmsg_len; + int cmsg_level; + int cmsg_type; +}; + +struct __sanitizer_dirent { + u64 d_fileno; + u16 d_reclen; + // more fields that we don't care about +}; + +typedef int __sanitizer_clock_t; +typedef int __sanitizer_clockid_t; + +typedef u32 __sanitizer___kernel_uid_t; +typedef u32 __sanitizer___kernel_gid_t; +typedef u64 __sanitizer___kernel_off_t; +typedef struct { + u32 fds_bits[8]; +} __sanitizer___kernel_fd_set; + +typedef struct { + unsigned int pta_magic; + int pta_flags; + void *pta_private; +} __sanitizer_pthread_attr_t; + +struct __sanitizer_sigset_t { + // uint32_t * 4 + unsigned int __bits[4]; +}; + +struct __sanitizer_siginfo { + // The size is determined by looking at sizeof of real siginfo_t on linux. + u64 opaque[128 / sizeof(u64)]; +}; + +using __sanitizer_sighandler_ptr = void (*)(int sig); +using __sanitizer_sigactionhandler_ptr = void (*)(int sig, + __sanitizer_siginfo *siginfo, + void *uctx); + +struct __sanitizer_sigaction { + union { + __sanitizer_sighandler_ptr handler; + __sanitizer_sigactionhandler_ptr sigaction; + }; + __sanitizer_sigset_t sa_mask; + int sa_flags; +}; + +extern unsigned struct_sigaltstack_sz; + +typedef unsigned int __sanitizer_sigset13_t; + +struct __sanitizer_sigaction13 { + __sanitizer_sighandler_ptr osa_handler; + __sanitizer_sigset13_t osa_mask; + int osa_flags; +}; + +struct __sanitizer_sigaltstack { + void *ss_sp; + uptr ss_size; + int ss_flags; +}; + +typedef __sanitizer_sigset_t __sanitizer_kernel_sigset_t; + +struct __sanitizer_kernel_sigaction_t { + union { + void (*handler)(int signo); + void (*sigaction)(int signo, void *info, void *ctx); + }; + unsigned long sa_flags; + void (*sa_restorer)(void); + __sanitizer_kernel_sigset_t sa_mask; +}; + +extern const uptr sig_ign; +extern const uptr sig_dfl; +extern const uptr sig_err; +extern const uptr sa_siginfo; + +extern int af_inet; +extern int af_inet6; +uptr __sanitizer_in_addr_sz(int af); + +struct __sanitizer_dl_phdr_info { + uptr dlpi_addr; + const char *dlpi_name; + const void *dlpi_phdr; + short dlpi_phnum; +}; + +extern unsigned struct_ElfW_Phdr_sz; + +struct __sanitizer_addrinfo { + int ai_flags; + int ai_family; + int ai_socktype; + int ai_protocol; +#if defined(__sparc__) && defined(_LP64) + int __ai_pad0; +#endif + unsigned ai_addrlen; +#if defined(__alpha__) || (defined(__i386__) && defined(_LP64)) + int __ai_pad0; +#endif + char *ai_canonname; + void *ai_addr; + struct __sanitizer_addrinfo *ai_next; +}; + +struct __sanitizer_hostent { + char *h_name; + char **h_aliases; + int h_addrtype; + int h_length; + char **h_addr_list; +}; + +struct __sanitizer_pollfd { + int fd; + short events; + short revents; +}; + +typedef unsigned __sanitizer_nfds_t; + +typedef int __sanitizer_lwpid_t; + +struct __sanitizer_glob_t { + uptr gl_pathc; + uptr gl_matchc; + uptr gl_offs; + int gl_flags; + char **gl_pathv; + int (*gl_errfunc)(const char *, int); + void (*gl_closedir)(void *dirp); + struct dirent *(*gl_readdir)(void *dirp); + void *(*gl_opendir)(const char *); + int (*gl_lstat)(const char *, void * /* struct stat* */); + int (*gl_stat)(const char *, void * /* struct stat* */); +}; + +extern int glob_nomatch; +extern int glob_altdirfunc; +extern const int wordexp_wrde_dooffs; + +extern unsigned path_max; + +extern int struct_ttyent_sz; + +extern int ptrace_pt_io; +extern int ptrace_pt_lwpinfo; +extern int ptrace_pt_set_event_mask; +extern int ptrace_pt_get_event_mask; +extern int ptrace_pt_get_process_state; +extern int ptrace_pt_set_siginfo; +extern int ptrace_pt_get_siginfo; +extern int ptrace_pt_lwpstatus; +extern int ptrace_pt_lwpnext; +extern int ptrace_piod_read_d; +extern int ptrace_piod_write_d; +extern int ptrace_piod_read_i; +extern int ptrace_piod_write_i; +extern int ptrace_piod_read_auxv; +extern int ptrace_pt_setregs; +extern int ptrace_pt_getregs; +extern int ptrace_pt_setfpregs; +extern int ptrace_pt_getfpregs; +extern int ptrace_pt_setdbregs; +extern int ptrace_pt_getdbregs; + +struct __sanitizer_ptrace_io_desc { + int piod_op; + void *piod_offs; + void *piod_addr; + uptr piod_len; +}; + +struct __sanitizer_ptrace_lwpinfo { + __sanitizer_lwpid_t pl_lwpid; + int pl_event; +}; + +struct __sanitizer_ptrace_lwpstatus { + __sanitizer_lwpid_t pl_lwpid; + __sanitizer_sigset_t pl_sigpend; + __sanitizer_sigset_t pl_sigmask; + char pl_name[20]; + void *pl_private; +}; + +extern unsigned struct_ptrace_ptrace_io_desc_struct_sz; +extern unsigned struct_ptrace_ptrace_lwpinfo_struct_sz; +extern unsigned struct_ptrace_ptrace_lwpstatus_struct_sz; +extern unsigned struct_ptrace_ptrace_event_struct_sz; +extern unsigned struct_ptrace_ptrace_siginfo_struct_sz; + +extern unsigned struct_ptrace_reg_struct_sz; +extern unsigned struct_ptrace_fpreg_struct_sz; +extern unsigned struct_ptrace_dbreg_struct_sz; + +struct __sanitizer_wordexp_t { + uptr we_wordc; + char **we_wordv; + uptr we_offs; + char *we_strings; + uptr we_nbytes; +}; + +struct __sanitizer_FILE { + unsigned char *_p; + int _r; + int _w; + unsigned short _flags; + short _file; + struct { + unsigned char *_base; + int _size; + } _bf; + int _lbfsize; + void *_cookie; + int (*_close)(void *ptr); + u64 (*_read)(void *, void *, uptr); + u64 (*_seek)(void *, u64, int); + uptr (*_write)(void *, const void *, uptr); + struct { + unsigned char *_base; + int _size; + } _ext; + unsigned char *_up; + int _ur; + unsigned char _ubuf[3]; + unsigned char _nbuf[1]; + int (*_flush)(void *ptr); + char _lb_unused[sizeof(uptr)]; + int _blksize; + u64 _offset; +}; +#define SANITIZER_HAS_STRUCT_FILE 1 + +extern int shmctl_ipc_stat; + +// This simplifies generic code +#define struct_shminfo_sz -1 +#define struct_shm_info_sz -1 +#define shmctl_shm_stat -1 +#define shmctl_ipc_info -1 +#define shmctl_shm_info -1 + +extern unsigned struct_utmp_sz; +extern unsigned struct_utmpx_sz; + +extern int map_fixed; + +// ioctl arguments +struct __sanitizer_ifconf { + int ifc_len; + union { + void *ifcu_req; + } ifc_ifcu; +}; + +struct __sanitizer_ttyent { + char *ty_name; + char *ty_getty; + char *ty_type; + int ty_status; + char *ty_window; + char *ty_comment; + char *ty_class; +}; + +extern const unsigned long __sanitizer_bufsiz; + +#define IOC_NRBITS 8 +#define IOC_TYPEBITS 8 +#define IOC_SIZEBITS 14 +#define IOC_DIRBITS 2 +#define IOC_NONE 0U +#define IOC_WRITE 1U +#define IOC_READ 2U +#define IOC_NRMASK ((1 << IOC_NRBITS) - 1) +#define IOC_TYPEMASK ((1 << IOC_TYPEBITS) - 1) +#define IOC_SIZEMASK ((1 << IOC_SIZEBITS) - 1) +#undef IOC_DIRMASK +#define IOC_DIRMASK ((1 << IOC_DIRBITS) - 1) +#define IOC_NRSHIFT 0 +#define IOC_TYPESHIFT (IOC_NRSHIFT + IOC_NRBITS) +#define IOC_SIZESHIFT (IOC_TYPESHIFT + IOC_TYPEBITS) +#define IOC_DIRSHIFT (IOC_SIZESHIFT + IOC_SIZEBITS) +#define EVIOC_EV_MAX 0x1f +#define EVIOC_ABS_MAX 0x3f + +#define IOC_DIR(nr) (((nr) >> IOC_DIRSHIFT) & IOC_DIRMASK) +#define IOC_TYPE(nr) (((nr) >> IOC_TYPESHIFT) & IOC_TYPEMASK) +#define IOC_NR(nr) (((nr) >> IOC_NRSHIFT) & IOC_NRMASK) +#define IOC_SIZE(nr) (((nr) >> IOC_SIZESHIFT) & IOC_SIZEMASK) + +// ioctl request identifiers + +extern unsigned struct_altqreq_sz; +extern unsigned struct_amr_user_ioctl_sz; +extern unsigned struct_ap_control_sz; +extern unsigned struct_apm_ctl_sz; +extern unsigned struct_apm_event_info_sz; +extern unsigned struct_apm_power_info_sz; +extern unsigned struct_atabusiodetach_args_sz; +extern unsigned struct_atabusioscan_args_sz; +extern unsigned struct_ath_diag_sz; +extern unsigned struct_atm_flowmap_sz; +extern unsigned struct_audio_buf_info_sz; +extern unsigned struct_audio_device_sz; +extern unsigned struct_audio_encoding_sz; +extern unsigned struct_audio_info_sz; +extern unsigned struct_audio_offset_sz; +extern unsigned struct_bio_locate_sz; +extern unsigned struct_bioc_alarm_sz; +extern unsigned struct_bioc_blink_sz; +extern unsigned struct_bioc_disk_sz; +extern unsigned struct_bioc_inq_sz; +extern unsigned struct_bioc_setstate_sz; +extern unsigned struct_bioc_vol_sz; +extern unsigned struct_bioc_volops_sz; +extern unsigned struct_bktr_chnlset_sz; +extern unsigned struct_bktr_remote_sz; +extern unsigned struct_blue_conf_sz; +extern unsigned struct_blue_interface_sz; +extern unsigned struct_blue_stats_sz; +extern unsigned struct_bpf_dltlist_sz; +extern unsigned struct_bpf_program_sz; +extern unsigned struct_bpf_stat_old_sz; +extern unsigned struct_bpf_stat_sz; +extern unsigned struct_bpf_version_sz; +extern unsigned struct_btreq_sz; +extern unsigned struct_btsco_info_sz; +extern unsigned struct_buffmem_desc_sz; +extern unsigned struct_cbq_add_class_sz; +extern unsigned struct_cbq_add_filter_sz; +extern unsigned struct_cbq_delete_class_sz; +extern unsigned struct_cbq_delete_filter_sz; +extern unsigned struct_cbq_getstats_sz; +extern unsigned struct_cbq_interface_sz; +extern unsigned struct_cbq_modify_class_sz; +extern unsigned struct_ccd_ioctl_sz; +extern unsigned struct_cdnr_add_element_sz; +extern unsigned struct_cdnr_add_filter_sz; +extern unsigned struct_cdnr_add_tbmeter_sz; +extern unsigned struct_cdnr_add_trtcm_sz; +extern unsigned struct_cdnr_add_tswtcm_sz; +extern unsigned struct_cdnr_delete_element_sz; +extern unsigned struct_cdnr_delete_filter_sz; +extern unsigned struct_cdnr_get_stats_sz; +extern unsigned struct_cdnr_interface_sz; +extern unsigned struct_cdnr_modify_tbmeter_sz; +extern unsigned struct_cdnr_modify_trtcm_sz; +extern unsigned struct_cdnr_modify_tswtcm_sz; +extern unsigned struct_cdnr_tbmeter_stats_sz; +extern unsigned struct_cdnr_tcm_stats_sz; +extern unsigned struct_cgd_ioctl_sz; +extern unsigned struct_cgd_user_sz; +extern unsigned struct_changer_element_status_request_sz; +extern unsigned struct_changer_exchange_request_sz; +extern unsigned struct_changer_move_request_sz; +extern unsigned struct_changer_params_sz; +extern unsigned struct_changer_position_request_sz; +extern unsigned struct_changer_set_voltag_request_sz; +extern unsigned struct_clockctl_adjtime_sz; +extern unsigned struct_clockctl_clock_settime_sz; +extern unsigned struct_clockctl_ntp_adjtime_sz; +extern unsigned struct_clockctl_settimeofday_sz; +extern unsigned struct_cnwistats_sz; +extern unsigned struct_cnwitrail_sz; +extern unsigned struct_cnwstatus_sz; +extern unsigned struct_count_info_sz; +extern unsigned struct_cpu_ucode_sz; +extern unsigned struct_cpu_ucode_version_sz; +extern unsigned struct_crypt_kop_sz; +extern unsigned struct_crypt_mkop_sz; +extern unsigned struct_crypt_mop_sz; +extern unsigned struct_crypt_op_sz; +extern unsigned struct_crypt_result_sz; +extern unsigned struct_crypt_sfop_sz; +extern unsigned struct_crypt_sgop_sz; +extern unsigned struct_cryptret_sz; +extern unsigned struct_devdetachargs_sz; +extern unsigned struct_devlistargs_sz; +extern unsigned struct_devpmargs_sz; +extern unsigned struct_devrescanargs_sz; +extern unsigned struct_disk_badsecinfo_sz; +extern unsigned struct_disk_strategy_sz; +extern unsigned struct_disklabel_sz; +extern unsigned struct_dkbad_sz; +extern unsigned struct_dkwedge_info_sz; +extern unsigned struct_dkwedge_list_sz; +extern unsigned struct_dmio_setfunc_sz; +extern unsigned struct_dmx_pes_filter_params_sz; +extern unsigned struct_dmx_sct_filter_params_sz; +extern unsigned struct_dmx_stc_sz; +extern unsigned struct_dvb_diseqc_master_cmd_sz; +extern unsigned struct_dvb_diseqc_slave_reply_sz; +extern unsigned struct_dvb_frontend_event_sz; +extern unsigned struct_dvb_frontend_info_sz; +extern unsigned struct_dvb_frontend_parameters_sz; +extern unsigned struct_eccapreq_sz; +extern unsigned struct_fbcmap_sz; +extern unsigned struct_fbcurpos_sz; +extern unsigned struct_fbcursor_sz; +extern unsigned struct_fbgattr_sz; +extern unsigned struct_fbsattr_sz; +extern unsigned struct_fbtype_sz; +extern unsigned struct_fdformat_cmd_sz; +extern unsigned struct_fdformat_parms_sz; +extern unsigned struct_fifoq_conf_sz; +extern unsigned struct_fifoq_getstats_sz; +extern unsigned struct_fifoq_interface_sz; +extern unsigned struct_format_op_sz; +extern unsigned struct_fss_get_sz; +extern unsigned struct_fss_set_sz; +extern unsigned struct_gpio_attach_sz; +extern unsigned struct_gpio_info_sz; +extern unsigned struct_gpio_req_sz; +extern unsigned struct_gpio_set_sz; +extern unsigned struct_hfsc_add_class_sz; +extern unsigned struct_hfsc_add_filter_sz; +extern unsigned struct_hfsc_attach_sz; +extern unsigned struct_hfsc_class_stats_sz; +extern unsigned struct_hfsc_delete_class_sz; +extern unsigned struct_hfsc_delete_filter_sz; +extern unsigned struct_hfsc_interface_sz; +extern unsigned struct_hfsc_modify_class_sz; +extern unsigned struct_hpcfb_dsp_op_sz; +extern unsigned struct_hpcfb_dspconf_sz; +extern unsigned struct_hpcfb_fbconf_sz; +extern unsigned struct_if_addrprefreq_sz; +extern unsigned struct_if_clonereq_sz; +extern unsigned struct_if_laddrreq_sz; +extern unsigned struct_ifaddr_sz; +extern unsigned struct_ifaliasreq_sz; +extern unsigned struct_ifcapreq_sz; +extern unsigned struct_ifconf_sz; +extern unsigned struct_ifdatareq_sz; +extern unsigned struct_ifdrv_sz; +extern unsigned struct_ifmediareq_sz; +extern unsigned struct_ifpppcstatsreq_sz; +extern unsigned struct_ifpppstatsreq_sz; +extern unsigned struct_ifreq_sz; +extern unsigned struct_in6_addrpolicy_sz; +extern unsigned struct_in6_ndireq_sz; +extern unsigned struct_ioc_load_unload_sz; +extern unsigned struct_ioc_patch_sz; +extern unsigned struct_ioc_play_blocks_sz; +extern unsigned struct_ioc_play_msf_sz; +extern unsigned struct_ioc_play_track_sz; +extern unsigned struct_ioc_read_subchannel_sz; +extern unsigned struct_ioc_read_toc_entry_sz; +extern unsigned struct_ioc_toc_header_sz; +extern unsigned struct_ioc_vol_sz; +extern unsigned struct_ioctl_pt_sz; +extern unsigned struct_ioppt_sz; +extern unsigned struct_iovec_sz; +extern unsigned struct_ipfobj_sz; +extern unsigned struct_irda_params_sz; +extern unsigned struct_isp_fc_device_sz; +extern unsigned struct_isp_fc_tsk_mgmt_sz; +extern unsigned struct_isp_hba_device_sz; +extern unsigned struct_isv_cmd_sz; +extern unsigned struct_jobs_add_class_sz; +extern unsigned struct_jobs_add_filter_sz; +extern unsigned struct_jobs_attach_sz; +extern unsigned struct_jobs_class_stats_sz; +extern unsigned struct_jobs_delete_class_sz; +extern unsigned struct_jobs_delete_filter_sz; +extern unsigned struct_jobs_interface_sz; +extern unsigned struct_jobs_modify_class_sz; +extern unsigned struct_kbentry_sz; +extern unsigned struct_kfilter_mapping_sz; +extern unsigned struct_kiockeymap_sz; +extern unsigned struct_ksyms_gsymbol_sz; +extern unsigned struct_ksyms_gvalue_sz; +extern unsigned struct_ksyms_ogsymbol_sz; +extern unsigned struct_kttcp_io_args_sz; +extern unsigned struct_ltchars_sz; +extern unsigned struct_lua_create_sz; +extern unsigned struct_lua_info_sz; +extern unsigned struct_lua_load_sz; +extern unsigned struct_lua_require_sz; +extern unsigned struct_mbpp_param_sz; +extern unsigned struct_md_conf_sz; +extern unsigned struct_meteor_capframe_sz; +extern unsigned struct_meteor_counts_sz; +extern unsigned struct_meteor_geomet_sz; +extern unsigned struct_meteor_pixfmt_sz; +extern unsigned struct_meteor_video_sz; +extern unsigned struct_mlx_cinfo_sz; +extern unsigned struct_mlx_pause_sz; +extern unsigned struct_mlx_rebuild_request_sz; +extern unsigned struct_mlx_rebuild_status_sz; +extern unsigned struct_mlx_usercommand_sz; +extern unsigned struct_mly_user_command_sz; +extern unsigned struct_mly_user_health_sz; +extern unsigned struct_mtget_sz; +extern unsigned struct_mtop_sz; +extern unsigned struct_npf_ioctl_table_sz; +extern unsigned struct_npioctl_sz; +extern unsigned struct_nvme_pt_command_sz; +extern unsigned struct_ochanger_element_status_request_sz; +extern unsigned struct_ofiocdesc_sz; +extern unsigned struct_okiockey_sz; +extern unsigned struct_ortentry_sz; +extern unsigned struct_oscsi_addr_sz; +extern unsigned struct_oss_audioinfo_sz; +extern unsigned struct_oss_sysinfo_sz; +extern unsigned struct_pciio_bdf_cfgreg_sz; +extern unsigned struct_pciio_businfo_sz; +extern unsigned struct_pciio_cfgreg_sz; +extern unsigned struct_pciio_drvname_sz; +extern unsigned struct_pciio_drvnameonbus_sz; +extern unsigned struct_pcvtid_sz; +extern unsigned struct_pf_osfp_ioctl_sz; +extern unsigned struct_pf_status_sz; +extern unsigned struct_pfioc_altq_sz; +extern unsigned struct_pfioc_if_sz; +extern unsigned struct_pfioc_iface_sz; +extern unsigned struct_pfioc_limit_sz; +extern unsigned struct_pfioc_natlook_sz; +extern unsigned struct_pfioc_pooladdr_sz; +extern unsigned struct_pfioc_qstats_sz; +extern unsigned struct_pfioc_rule_sz; +extern unsigned struct_pfioc_ruleset_sz; +extern unsigned struct_pfioc_src_node_kill_sz; +extern unsigned struct_pfioc_src_nodes_sz; +extern unsigned struct_pfioc_state_kill_sz; +extern unsigned struct_pfioc_state_sz; +extern unsigned struct_pfioc_states_sz; +extern unsigned struct_pfioc_table_sz; +extern unsigned struct_pfioc_tm_sz; +extern unsigned struct_pfioc_trans_sz; +extern unsigned struct_plistref_sz; +extern unsigned struct_power_type_sz; +extern unsigned struct_ppp_idle_sz; +extern unsigned struct_ppp_option_data_sz; +extern unsigned struct_ppp_rawin_sz; +extern unsigned struct_pppoeconnectionstate_sz; +extern unsigned struct_pppoediscparms_sz; +extern unsigned struct_priq_add_class_sz; +extern unsigned struct_priq_add_filter_sz; +extern unsigned struct_priq_class_stats_sz; +extern unsigned struct_priq_delete_class_sz; +extern unsigned struct_priq_delete_filter_sz; +extern unsigned struct_priq_interface_sz; +extern unsigned struct_priq_modify_class_sz; +extern unsigned struct_ptmget_sz; +extern unsigned struct_pvctxreq_sz; +extern unsigned struct_radio_info_sz; +extern unsigned struct_red_conf_sz; +extern unsigned struct_red_interface_sz; +extern unsigned struct_red_stats_sz; +extern unsigned struct_redparams_sz; +extern unsigned struct_rf_pmparams_sz; +extern unsigned struct_rf_pmstat_sz; +extern unsigned struct_rf_recon_req_sz; +extern unsigned struct_rio_conf_sz; +extern unsigned struct_rio_interface_sz; +extern unsigned struct_rio_stats_sz; +extern unsigned struct_scan_io_sz; +extern unsigned struct_scbusaccel_args_sz; +extern unsigned struct_scbusiodetach_args_sz; +extern unsigned struct_scbusioscan_args_sz; +extern unsigned struct_scsi_addr_sz; +extern unsigned struct_seq_event_rec_sz; +extern unsigned struct_session_op_sz; +extern unsigned struct_sgttyb_sz; +extern unsigned struct_sioc_sg_req_sz; +extern unsigned struct_sioc_vif_req_sz; +extern unsigned struct_smbioc_flags_sz; +extern unsigned struct_smbioc_lookup_sz; +extern unsigned struct_smbioc_oshare_sz; +extern unsigned struct_smbioc_ossn_sz; +extern unsigned struct_smbioc_rq_sz; +extern unsigned struct_smbioc_rw_sz; +extern unsigned struct_spppauthcfg_sz; +extern unsigned struct_spppauthfailuresettings_sz; +extern unsigned struct_spppauthfailurestats_sz; +extern unsigned struct_spppdnsaddrs_sz; +extern unsigned struct_spppdnssettings_sz; +extern unsigned struct_spppidletimeout_sz; +extern unsigned struct_spppkeepalivesettings_sz; +extern unsigned struct_sppplcpcfg_sz; +extern unsigned struct_spppstatus_sz; +extern unsigned struct_spppstatusncp_sz; +extern unsigned struct_srt_rt_sz; +extern unsigned struct_stic_xinfo_sz; +extern unsigned struct_sun_dkctlr_sz; +extern unsigned struct_sun_dkgeom_sz; +extern unsigned struct_sun_dkpart_sz; +extern unsigned struct_synth_info_sz; +extern unsigned struct_tbrreq_sz; +extern unsigned struct_tchars_sz; +extern unsigned struct_termios_sz; +extern unsigned struct_timeval_sz; +extern unsigned struct_twe_drivecommand_sz; +extern unsigned struct_twe_paramcommand_sz; +extern unsigned struct_twe_usercommand_sz; +extern unsigned struct_ukyopon_identify_sz; +extern unsigned struct_urio_command_sz; +extern unsigned struct_usb_alt_interface_sz; +extern unsigned struct_usb_bulk_ra_wb_opt_sz; +extern unsigned struct_usb_config_desc_sz; +extern unsigned struct_usb_ctl_report_desc_sz; +extern unsigned struct_usb_ctl_report_sz; +extern unsigned struct_usb_ctl_request_sz; +#if defined(__x86_64__) +extern unsigned struct_nvmm_ioc_capability_sz; +extern unsigned struct_nvmm_ioc_machine_create_sz; +extern unsigned struct_nvmm_ioc_machine_destroy_sz; +extern unsigned struct_nvmm_ioc_machine_configure_sz; +extern unsigned struct_nvmm_ioc_vcpu_create_sz; +extern unsigned struct_nvmm_ioc_vcpu_destroy_sz; +extern unsigned struct_nvmm_ioc_vcpu_configure_sz; +extern unsigned struct_nvmm_ioc_vcpu_setstate_sz; +extern unsigned struct_nvmm_ioc_vcpu_getstate_sz; +extern unsigned struct_nvmm_ioc_vcpu_inject_sz; +extern unsigned struct_nvmm_ioc_vcpu_run_sz; +extern unsigned struct_nvmm_ioc_gpa_map_sz; +extern unsigned struct_nvmm_ioc_gpa_unmap_sz; +extern unsigned struct_nvmm_ioc_hva_map_sz; +extern unsigned struct_nvmm_ioc_hva_unmap_sz; +extern unsigned struct_nvmm_ioc_ctl_sz; +#endif +extern unsigned struct_spi_ioctl_configure_sz; +extern unsigned struct_spi_ioctl_transfer_sz; +extern unsigned struct_autofs_daemon_request_sz; +extern unsigned struct_autofs_daemon_done_sz; +extern unsigned struct_sctp_connectx_addrs_sz; +extern unsigned struct_usb_device_info_old_sz; +extern unsigned struct_usb_device_info_sz; +extern unsigned struct_usb_device_stats_sz; +extern unsigned struct_usb_endpoint_desc_sz; +extern unsigned struct_usb_full_desc_sz; +extern unsigned struct_usb_interface_desc_sz; +extern unsigned struct_usb_string_desc_sz; +extern unsigned struct_utoppy_readfile_sz; +extern unsigned struct_utoppy_rename_sz; +extern unsigned struct_utoppy_stats_sz; +extern unsigned struct_utoppy_writefile_sz; +extern unsigned struct_v4l2_audio_sz; +extern unsigned struct_v4l2_audioout_sz; +extern unsigned struct_v4l2_buffer_sz; +extern unsigned struct_v4l2_capability_sz; +extern unsigned struct_v4l2_control_sz; +extern unsigned struct_v4l2_crop_sz; +extern unsigned struct_v4l2_cropcap_sz; +extern unsigned struct_v4l2_fmtdesc_sz; +extern unsigned struct_v4l2_format_sz; +extern unsigned struct_v4l2_framebuffer_sz; +extern unsigned struct_v4l2_frequency_sz; +extern unsigned struct_v4l2_frmivalenum_sz; +extern unsigned struct_v4l2_frmsizeenum_sz; +extern unsigned struct_v4l2_input_sz; +extern unsigned struct_v4l2_jpegcompression_sz; +extern unsigned struct_v4l2_modulator_sz; +extern unsigned struct_v4l2_output_sz; +extern unsigned struct_v4l2_queryctrl_sz; +extern unsigned struct_v4l2_querymenu_sz; +extern unsigned struct_v4l2_requestbuffers_sz; +extern unsigned struct_v4l2_standard_sz; +extern unsigned struct_v4l2_streamparm_sz; +extern unsigned struct_v4l2_tuner_sz; +extern unsigned struct_vnd_ioctl_sz; +extern unsigned struct_vnd_user_sz; +extern unsigned struct_vt_stat_sz; +extern unsigned struct_wdog_conf_sz; +extern unsigned struct_wdog_mode_sz; +extern unsigned struct_ipmi_recv_sz; +extern unsigned struct_ipmi_req_sz; +extern unsigned struct_ipmi_cmdspec_sz; +extern unsigned struct_wfq_conf_sz; +extern unsigned struct_wfq_getqid_sz; +extern unsigned struct_wfq_getstats_sz; +extern unsigned struct_wfq_interface_sz; +extern unsigned struct_wfq_setweight_sz; +extern unsigned struct_winsize_sz; +extern unsigned struct_wscons_event_sz; +extern unsigned struct_wsdisplay_addscreendata_sz; +extern unsigned struct_wsdisplay_char_sz; +extern unsigned struct_wsdisplay_cmap_sz; +extern unsigned struct_wsdisplay_curpos_sz; +extern unsigned struct_wsdisplay_cursor_sz; +extern unsigned struct_wsdisplay_delscreendata_sz; +extern unsigned struct_wsdisplay_fbinfo_sz; +extern unsigned struct_wsdisplay_font_sz; +extern unsigned struct_wsdisplay_kbddata_sz; +extern unsigned struct_wsdisplay_msgattrs_sz; +extern unsigned struct_wsdisplay_param_sz; +extern unsigned struct_wsdisplay_scroll_data_sz; +extern unsigned struct_wsdisplay_usefontdata_sz; +extern unsigned struct_wsdisplayio_blit_sz; +extern unsigned struct_wsdisplayio_bus_id_sz; +extern unsigned struct_wsdisplayio_edid_info_sz; +extern unsigned struct_wsdisplayio_fbinfo_sz; +extern unsigned struct_wskbd_bell_data_sz; +extern unsigned struct_wskbd_keyrepeat_data_sz; +extern unsigned struct_wskbd_map_data_sz; +extern unsigned struct_wskbd_scroll_data_sz; +extern unsigned struct_wsmouse_calibcoords_sz; +extern unsigned struct_wsmouse_id_sz; +extern unsigned struct_wsmouse_repeat_sz; +extern unsigned struct_wsmux_device_list_sz; +extern unsigned struct_wsmux_device_sz; +extern unsigned struct_xd_iocmd_sz; + +extern unsigned struct_scsireq_sz; +extern unsigned struct_tone_sz; +extern unsigned union_twe_statrequest_sz; +extern unsigned struct_usb_device_descriptor_sz; +extern unsigned struct_vt_mode_sz; +extern unsigned struct__old_mixer_info_sz; +extern unsigned struct__agp_allocate_sz; +extern unsigned struct__agp_bind_sz; +extern unsigned struct__agp_info_sz; +extern unsigned struct__agp_setup_sz; +extern unsigned struct__agp_unbind_sz; +extern unsigned struct_atareq_sz; +extern unsigned struct_cpustate_sz; +extern unsigned struct_dmx_caps_sz; +extern unsigned enum_dmx_source_sz; +extern unsigned union_dvd_authinfo_sz; +extern unsigned union_dvd_struct_sz; +extern unsigned enum_v4l2_priority_sz; +extern unsigned struct_envsys_basic_info_sz; +extern unsigned struct_envsys_tre_data_sz; +extern unsigned enum_fe_sec_mini_cmd_sz; +extern unsigned enum_fe_sec_tone_mode_sz; +extern unsigned enum_fe_sec_voltage_sz; +extern unsigned enum_fe_status_sz; +extern unsigned struct_gdt_ctrt_sz; +extern unsigned struct_gdt_event_sz; +extern unsigned struct_gdt_osv_sz; +extern unsigned struct_gdt_rescan_sz; +extern unsigned struct_gdt_statist_sz; +extern unsigned struct_gdt_ucmd_sz; +extern unsigned struct_iscsi_conn_status_parameters_sz; +extern unsigned struct_iscsi_get_version_parameters_sz; +extern unsigned struct_iscsi_iocommand_parameters_sz; +extern unsigned struct_iscsi_login_parameters_sz; +extern unsigned struct_iscsi_logout_parameters_sz; +extern unsigned struct_iscsi_register_event_parameters_sz; +extern unsigned struct_iscsi_remove_parameters_sz; +extern unsigned struct_iscsi_send_targets_parameters_sz; +extern unsigned struct_iscsi_set_node_name_parameters_sz; +extern unsigned struct_iscsi_wait_event_parameters_sz; +extern unsigned struct_isp_stats_sz; +extern unsigned struct_lsenable_sz; +extern unsigned struct_lsdisable_sz; +extern unsigned struct_audio_format_query_sz; +extern unsigned struct_mixer_ctrl_sz; +extern unsigned struct_mixer_devinfo_sz; +extern unsigned struct_mpu_command_rec_sz; +extern unsigned struct_rndstat_sz; +extern unsigned struct_rndstat_name_sz; +extern unsigned struct_rndctl_sz; +extern unsigned struct_rnddata_sz; +extern unsigned struct_rndpoolstat_sz; +extern unsigned struct_rndstat_est_sz; +extern unsigned struct_rndstat_est_name_sz; +extern unsigned struct_pps_params_sz; +extern unsigned struct_pps_info_sz; +extern unsigned struct_mixer_info_sz; +extern unsigned struct_RF_SparetWait_sz; +extern unsigned struct_RF_ComponentLabel_sz; +extern unsigned struct_RF_SingleComponent_sz; +extern unsigned struct_RF_ProgressInfo_sz; +extern unsigned struct_nvlist_ref_sz; +extern unsigned struct_StringList_sz; + +// A special value to mark ioctls that are not present on the target platform, +// when it can not be determined without including any system headers. +extern const unsigned IOCTL_NOT_PRESENT; + +extern unsigned IOCTL_AFM_ADDFMAP; +extern unsigned IOCTL_AFM_DELFMAP; +extern unsigned IOCTL_AFM_CLEANFMAP; +extern unsigned IOCTL_AFM_GETFMAP; +extern unsigned IOCTL_ALTQGTYPE; +extern unsigned IOCTL_ALTQTBRSET; +extern unsigned IOCTL_ALTQTBRGET; +extern unsigned IOCTL_BLUE_IF_ATTACH; +extern unsigned IOCTL_BLUE_IF_DETACH; +extern unsigned IOCTL_BLUE_ENABLE; +extern unsigned IOCTL_BLUE_DISABLE; +extern unsigned IOCTL_BLUE_CONFIG; +extern unsigned IOCTL_BLUE_GETSTATS; +extern unsigned IOCTL_CBQ_IF_ATTACH; +extern unsigned IOCTL_CBQ_IF_DETACH; +extern unsigned IOCTL_CBQ_ENABLE; +extern unsigned IOCTL_CBQ_DISABLE; +extern unsigned IOCTL_CBQ_CLEAR_HIERARCHY; +extern unsigned IOCTL_CBQ_ADD_CLASS; +extern unsigned IOCTL_CBQ_DEL_CLASS; +extern unsigned IOCTL_CBQ_MODIFY_CLASS; +extern unsigned IOCTL_CBQ_ADD_FILTER; +extern unsigned IOCTL_CBQ_DEL_FILTER; +extern unsigned IOCTL_CBQ_GETSTATS; +extern unsigned IOCTL_CDNR_IF_ATTACH; +extern unsigned IOCTL_CDNR_IF_DETACH; +extern unsigned IOCTL_CDNR_ENABLE; +extern unsigned IOCTL_CDNR_DISABLE; +extern unsigned IOCTL_CDNR_ADD_FILTER; +extern unsigned IOCTL_CDNR_DEL_FILTER; +extern unsigned IOCTL_CDNR_GETSTATS; +extern unsigned IOCTL_CDNR_ADD_ELEM; +extern unsigned IOCTL_CDNR_DEL_ELEM; +extern unsigned IOCTL_CDNR_ADD_TBM; +extern unsigned IOCTL_CDNR_MOD_TBM; +extern unsigned IOCTL_CDNR_TBM_STATS; +extern unsigned IOCTL_CDNR_ADD_TCM; +extern unsigned IOCTL_CDNR_MOD_TCM; +extern unsigned IOCTL_CDNR_TCM_STATS; +extern unsigned IOCTL_CDNR_ADD_TSW; +extern unsigned IOCTL_CDNR_MOD_TSW; +extern unsigned IOCTL_FIFOQ_IF_ATTACH; +extern unsigned IOCTL_FIFOQ_IF_DETACH; +extern unsigned IOCTL_FIFOQ_ENABLE; +extern unsigned IOCTL_FIFOQ_DISABLE; +extern unsigned IOCTL_FIFOQ_CONFIG; +extern unsigned IOCTL_FIFOQ_GETSTATS; +extern unsigned IOCTL_HFSC_IF_ATTACH; +extern unsigned IOCTL_HFSC_IF_DETACH; +extern unsigned IOCTL_HFSC_ENABLE; +extern unsigned IOCTL_HFSC_DISABLE; +extern unsigned IOCTL_HFSC_CLEAR_HIERARCHY; +extern unsigned IOCTL_HFSC_ADD_CLASS; +extern unsigned IOCTL_HFSC_DEL_CLASS; +extern unsigned IOCTL_HFSC_MOD_CLASS; +extern unsigned IOCTL_HFSC_ADD_FILTER; +extern unsigned IOCTL_HFSC_DEL_FILTER; +extern unsigned IOCTL_HFSC_GETSTATS; +extern unsigned IOCTL_JOBS_IF_ATTACH; +extern unsigned IOCTL_JOBS_IF_DETACH; +extern unsigned IOCTL_JOBS_ENABLE; +extern unsigned IOCTL_JOBS_DISABLE; +extern unsigned IOCTL_JOBS_CLEAR; +extern unsigned IOCTL_JOBS_ADD_CLASS; +extern unsigned IOCTL_JOBS_DEL_CLASS; +extern unsigned IOCTL_JOBS_MOD_CLASS; +extern unsigned IOCTL_JOBS_ADD_FILTER; +extern unsigned IOCTL_JOBS_DEL_FILTER; +extern unsigned IOCTL_JOBS_GETSTATS; +extern unsigned IOCTL_PRIQ_IF_ATTACH; +extern unsigned IOCTL_PRIQ_IF_DETACH; +extern unsigned IOCTL_PRIQ_ENABLE; +extern unsigned IOCTL_PRIQ_DISABLE; +extern unsigned IOCTL_PRIQ_CLEAR; +extern unsigned IOCTL_PRIQ_ADD_CLASS; +extern unsigned IOCTL_PRIQ_DEL_CLASS; +extern unsigned IOCTL_PRIQ_MOD_CLASS; +extern unsigned IOCTL_PRIQ_ADD_FILTER; +extern unsigned IOCTL_PRIQ_DEL_FILTER; +extern unsigned IOCTL_PRIQ_GETSTATS; +extern unsigned IOCTL_RED_IF_ATTACH; +extern unsigned IOCTL_RED_IF_DETACH; +extern unsigned IOCTL_RED_ENABLE; +extern unsigned IOCTL_RED_DISABLE; +extern unsigned IOCTL_RED_CONFIG; +extern unsigned IOCTL_RED_GETSTATS; +extern unsigned IOCTL_RED_SETDEFAULTS; +extern unsigned IOCTL_RIO_IF_ATTACH; +extern unsigned IOCTL_RIO_IF_DETACH; +extern unsigned IOCTL_RIO_ENABLE; +extern unsigned IOCTL_RIO_DISABLE; +extern unsigned IOCTL_RIO_CONFIG; +extern unsigned IOCTL_RIO_GETSTATS; +extern unsigned IOCTL_RIO_SETDEFAULTS; +extern unsigned IOCTL_WFQ_IF_ATTACH; +extern unsigned IOCTL_WFQ_IF_DETACH; +extern unsigned IOCTL_WFQ_ENABLE; +extern unsigned IOCTL_WFQ_DISABLE; +extern unsigned IOCTL_WFQ_CONFIG; +extern unsigned IOCTL_WFQ_GET_STATS; +extern unsigned IOCTL_WFQ_GET_QID; +extern unsigned IOCTL_WFQ_SET_WEIGHT; +extern unsigned IOCTL_CRIOGET; +extern unsigned IOCTL_CIOCFSESSION; +extern unsigned IOCTL_CIOCKEY; +extern unsigned IOCTL_CIOCNFKEYM; +extern unsigned IOCTL_CIOCNFSESSION; +extern unsigned IOCTL_CIOCNCRYPTRETM; +extern unsigned IOCTL_CIOCNCRYPTRET; +extern unsigned IOCTL_CIOCGSESSION; +extern unsigned IOCTL_CIOCNGSESSION; +extern unsigned IOCTL_CIOCCRYPT; +extern unsigned IOCTL_CIOCNCRYPTM; +extern unsigned IOCTL_CIOCASYMFEAT; +extern unsigned IOCTL_APM_IOC_REJECT; +extern unsigned IOCTL_APM_IOC_STANDBY; +extern unsigned IOCTL_APM_IOC_SUSPEND; +extern unsigned IOCTL_OAPM_IOC_GETPOWER; +extern unsigned IOCTL_APM_IOC_GETPOWER; +extern unsigned IOCTL_APM_IOC_NEXTEVENT; +extern unsigned IOCTL_APM_IOC_DEV_CTL; +extern unsigned IOCTL_NETBSD_DM_IOCTL; +extern unsigned IOCTL_DMIO_SETFUNC; +extern unsigned IOCTL_DMX_START; +extern unsigned IOCTL_DMX_STOP; +extern unsigned IOCTL_DMX_SET_FILTER; +extern unsigned IOCTL_DMX_SET_PES_FILTER; +extern unsigned IOCTL_DMX_SET_BUFFER_SIZE; +extern unsigned IOCTL_DMX_GET_STC; +extern unsigned IOCTL_DMX_ADD_PID; +extern unsigned IOCTL_DMX_REMOVE_PID; +extern unsigned IOCTL_DMX_GET_CAPS; +extern unsigned IOCTL_DMX_SET_SOURCE; +extern unsigned IOCTL_FE_READ_STATUS; +extern unsigned IOCTL_FE_READ_BER; +extern unsigned IOCTL_FE_READ_SNR; +extern unsigned IOCTL_FE_READ_SIGNAL_STRENGTH; +extern unsigned IOCTL_FE_READ_UNCORRECTED_BLOCKS; +extern unsigned IOCTL_FE_SET_FRONTEND; +extern unsigned IOCTL_FE_GET_FRONTEND; +extern unsigned IOCTL_FE_GET_EVENT; +extern unsigned IOCTL_FE_GET_INFO; +extern unsigned IOCTL_FE_DISEQC_RESET_OVERLOAD; +extern unsigned IOCTL_FE_DISEQC_SEND_MASTER_CMD; +extern unsigned IOCTL_FE_DISEQC_RECV_SLAVE_REPLY; +extern unsigned IOCTL_FE_DISEQC_SEND_BURST; +extern unsigned IOCTL_FE_SET_TONE; +extern unsigned IOCTL_FE_SET_VOLTAGE; +extern unsigned IOCTL_FE_ENABLE_HIGH_LNB_VOLTAGE; +extern unsigned IOCTL_FE_SET_FRONTEND_TUNE_MODE; +extern unsigned IOCTL_FE_DISHNETWORK_SEND_LEGACY_CMD; +extern unsigned IOCTL_FILEMON_SET_FD; +extern unsigned IOCTL_FILEMON_SET_PID; +extern unsigned IOCTL_HDAUDIO_FGRP_INFO; +extern unsigned IOCTL_HDAUDIO_FGRP_GETCONFIG; +extern unsigned IOCTL_HDAUDIO_FGRP_SETCONFIG; +extern unsigned IOCTL_HDAUDIO_FGRP_WIDGET_INFO; +extern unsigned IOCTL_HDAUDIO_FGRP_CODEC_INFO; +extern unsigned IOCTL_HDAUDIO_AFG_WIDGET_INFO; +extern unsigned IOCTL_HDAUDIO_AFG_CODEC_INFO; +extern unsigned IOCTL_CEC_GET_PHYS_ADDR; +extern unsigned IOCTL_CEC_GET_LOG_ADDRS; +extern unsigned IOCTL_CEC_SET_LOG_ADDRS; +extern unsigned IOCTL_CEC_GET_VENDOR_ID; +extern unsigned IOCTL_HPCFBIO_GCONF; +extern unsigned IOCTL_HPCFBIO_SCONF; +extern unsigned IOCTL_HPCFBIO_GDSPCONF; +extern unsigned IOCTL_HPCFBIO_SDSPCONF; +extern unsigned IOCTL_HPCFBIO_GOP; +extern unsigned IOCTL_HPCFBIO_SOP; +extern unsigned IOCTL_IOPIOCPT; +extern unsigned IOCTL_IOPIOCGLCT; +extern unsigned IOCTL_IOPIOCGSTATUS; +extern unsigned IOCTL_IOPIOCRECONFIG; +extern unsigned IOCTL_IOPIOCGTIDMAP; +extern unsigned IOCTL_SIOCGATHSTATS; +extern unsigned IOCTL_SIOCGATHDIAG; +extern unsigned IOCTL_METEORCAPTUR; +extern unsigned IOCTL_METEORCAPFRM; +extern unsigned IOCTL_METEORSETGEO; +extern unsigned IOCTL_METEORGETGEO; +extern unsigned IOCTL_METEORSTATUS; +extern unsigned IOCTL_METEORSHUE; +extern unsigned IOCTL_METEORGHUE; +extern unsigned IOCTL_METEORSFMT; +extern unsigned IOCTL_METEORGFMT; +extern unsigned IOCTL_METEORSINPUT; +extern unsigned IOCTL_METEORGINPUT; +extern unsigned IOCTL_METEORSCHCV; +extern unsigned IOCTL_METEORGCHCV; +extern unsigned IOCTL_METEORSCOUNT; +extern unsigned IOCTL_METEORGCOUNT; +extern unsigned IOCTL_METEORSFPS; +extern unsigned IOCTL_METEORGFPS; +extern unsigned IOCTL_METEORSSIGNAL; +extern unsigned IOCTL_METEORGSIGNAL; +extern unsigned IOCTL_METEORSVIDEO; +extern unsigned IOCTL_METEORGVIDEO; +extern unsigned IOCTL_METEORSBRIG; +extern unsigned IOCTL_METEORGBRIG; +extern unsigned IOCTL_METEORSCSAT; +extern unsigned IOCTL_METEORGCSAT; +extern unsigned IOCTL_METEORSCONT; +extern unsigned IOCTL_METEORGCONT; +extern unsigned IOCTL_METEORSHWS; +extern unsigned IOCTL_METEORGHWS; +extern unsigned IOCTL_METEORSVWS; +extern unsigned IOCTL_METEORGVWS; +extern unsigned IOCTL_METEORSTS; +extern unsigned IOCTL_METEORGTS; +extern unsigned IOCTL_TVTUNER_SETCHNL; +extern unsigned IOCTL_TVTUNER_GETCHNL; +extern unsigned IOCTL_TVTUNER_SETTYPE; +extern unsigned IOCTL_TVTUNER_GETTYPE; +extern unsigned IOCTL_TVTUNER_GETSTATUS; +extern unsigned IOCTL_TVTUNER_SETFREQ; +extern unsigned IOCTL_TVTUNER_GETFREQ; +extern unsigned IOCTL_TVTUNER_SETAFC; +extern unsigned IOCTL_TVTUNER_GETAFC; +extern unsigned IOCTL_RADIO_SETMODE; +extern unsigned IOCTL_RADIO_GETMODE; +extern unsigned IOCTL_RADIO_SETFREQ; +extern unsigned IOCTL_RADIO_GETFREQ; +extern unsigned IOCTL_METEORSACTPIXFMT; +extern unsigned IOCTL_METEORGACTPIXFMT; +extern unsigned IOCTL_METEORGSUPPIXFMT; +extern unsigned IOCTL_TVTUNER_GETCHNLSET; +extern unsigned IOCTL_REMOTE_GETKEY; +extern unsigned IOCTL_GDT_IOCTL_GENERAL; +extern unsigned IOCTL_GDT_IOCTL_DRVERS; +extern unsigned IOCTL_GDT_IOCTL_CTRTYPE; +extern unsigned IOCTL_GDT_IOCTL_OSVERS; +extern unsigned IOCTL_GDT_IOCTL_CTRCNT; +extern unsigned IOCTL_GDT_IOCTL_EVENT; +extern unsigned IOCTL_GDT_IOCTL_STATIST; +extern unsigned IOCTL_GDT_IOCTL_RESCAN; +extern unsigned IOCTL_ISP_SDBLEV; +extern unsigned IOCTL_ISP_RESETHBA; +extern unsigned IOCTL_ISP_RESCAN; +extern unsigned IOCTL_ISP_SETROLE; +extern unsigned IOCTL_ISP_GETROLE; +extern unsigned IOCTL_ISP_GET_STATS; +extern unsigned IOCTL_ISP_CLR_STATS; +extern unsigned IOCTL_ISP_FC_LIP; +extern unsigned IOCTL_ISP_FC_GETDINFO; +extern unsigned IOCTL_ISP_GET_FW_CRASH_DUMP; +extern unsigned IOCTL_ISP_FORCE_CRASH_DUMP; +extern unsigned IOCTL_ISP_FC_GETHINFO; +extern unsigned IOCTL_ISP_TSK_MGMT; +extern unsigned IOCTL_ISP_FC_GETDLIST; +extern unsigned IOCTL_MLXD_STATUS; +extern unsigned IOCTL_MLXD_CHECKASYNC; +extern unsigned IOCTL_MLXD_DETACH; +extern unsigned IOCTL_MLX_RESCAN_DRIVES; +extern unsigned IOCTL_MLX_PAUSE_CHANNEL; +extern unsigned IOCTL_MLX_COMMAND; +extern unsigned IOCTL_MLX_REBUILDASYNC; +extern unsigned IOCTL_MLX_REBUILDSTAT; +extern unsigned IOCTL_MLX_GET_SYSDRIVE; +extern unsigned IOCTL_MLX_GET_CINFO; +extern unsigned IOCTL_NVME_PASSTHROUGH_CMD; +extern unsigned IOCTL_FWCFGIO_SET_INDEX; +extern unsigned IOCTL_IRDA_RESET_PARAMS; +extern unsigned IOCTL_IRDA_SET_PARAMS; +extern unsigned IOCTL_IRDA_GET_SPEEDMASK; +extern unsigned IOCTL_IRDA_GET_TURNAROUNDMASK; +extern unsigned IOCTL_IRFRAMETTY_GET_DEVICE; +extern unsigned IOCTL_IRFRAMETTY_GET_DONGLE; +extern unsigned IOCTL_IRFRAMETTY_SET_DONGLE; +extern unsigned IOCTL_ISV_CMD; +extern unsigned IOCTL_WTQICMD; +extern unsigned IOCTL_ISCSI_GET_VERSION; +extern unsigned IOCTL_ISCSI_LOGIN; +extern unsigned IOCTL_ISCSI_LOGOUT; +extern unsigned IOCTL_ISCSI_ADD_CONNECTION; +extern unsigned IOCTL_ISCSI_RESTORE_CONNECTION; +extern unsigned IOCTL_ISCSI_REMOVE_CONNECTION; +extern unsigned IOCTL_ISCSI_CONNECTION_STATUS; +extern unsigned IOCTL_ISCSI_SEND_TARGETS; +extern unsigned IOCTL_ISCSI_SET_NODE_NAME; +extern unsigned IOCTL_ISCSI_IO_COMMAND; +extern unsigned IOCTL_ISCSI_REGISTER_EVENT; +extern unsigned IOCTL_ISCSI_DEREGISTER_EVENT; +extern unsigned IOCTL_ISCSI_WAIT_EVENT; +extern unsigned IOCTL_ISCSI_POLL_EVENT; +extern unsigned IOCTL_OFIOCGET; +extern unsigned IOCTL_OFIOCSET; +extern unsigned IOCTL_OFIOCNEXTPROP; +extern unsigned IOCTL_OFIOCGETOPTNODE; +extern unsigned IOCTL_OFIOCGETNEXT; +extern unsigned IOCTL_OFIOCGETCHILD; +extern unsigned IOCTL_OFIOCFINDDEVICE; +extern unsigned IOCTL_AMR_IO_VERSION; +extern unsigned IOCTL_AMR_IO_COMMAND; +extern unsigned IOCTL_MLYIO_COMMAND; +extern unsigned IOCTL_MLYIO_HEALTH; +extern unsigned IOCTL_PCI_IOC_CFGREAD; +extern unsigned IOCTL_PCI_IOC_CFGWRITE; +extern unsigned IOCTL_PCI_IOC_BDF_CFGREAD; +extern unsigned IOCTL_PCI_IOC_BDF_CFGWRITE; +extern unsigned IOCTL_PCI_IOC_BUSINFO; +extern unsigned IOCTL_PCI_IOC_DRVNAME; +extern unsigned IOCTL_PCI_IOC_DRVNAMEONBUS; +extern unsigned IOCTL_TWEIO_COMMAND; +extern unsigned IOCTL_TWEIO_STATS; +extern unsigned IOCTL_TWEIO_AEN_POLL; +extern unsigned IOCTL_TWEIO_AEN_WAIT; +extern unsigned IOCTL_TWEIO_SET_PARAM; +extern unsigned IOCTL_TWEIO_GET_PARAM; +extern unsigned IOCTL_TWEIO_RESET; +extern unsigned IOCTL_TWEIO_ADD_UNIT; +extern unsigned IOCTL_TWEIO_DEL_UNIT; +extern unsigned IOCTL_SIOCSCNWDOMAIN; +extern unsigned IOCTL_SIOCGCNWDOMAIN; +extern unsigned IOCTL_SIOCSCNWKEY; +extern unsigned IOCTL_SIOCGCNWSTATUS; +extern unsigned IOCTL_SIOCGCNWSTATS; +extern unsigned IOCTL_SIOCGCNWTRAIL; +extern unsigned IOCTL_SIOCGRAYSIGLEV; +extern unsigned IOCTL_RAIDFRAME_SHUTDOWN; +extern unsigned IOCTL_RAIDFRAME_TUR; +extern unsigned IOCTL_RAIDFRAME_FAIL_DISK; +extern unsigned IOCTL_RAIDFRAME_CHECK_RECON_STATUS; +extern unsigned IOCTL_RAIDFRAME_REWRITEPARITY; +extern unsigned IOCTL_RAIDFRAME_COPYBACK; +extern unsigned IOCTL_RAIDFRAME_SPARET_WAIT; +extern unsigned IOCTL_RAIDFRAME_SEND_SPARET; +extern unsigned IOCTL_RAIDFRAME_ABORT_SPARET_WAIT; +extern unsigned IOCTL_RAIDFRAME_START_ATRACE; +extern unsigned IOCTL_RAIDFRAME_STOP_ATRACE; +extern unsigned IOCTL_RAIDFRAME_GET_SIZE; +extern unsigned IOCTL_RAIDFRAME_RESET_ACCTOTALS; +extern unsigned IOCTL_RAIDFRAME_KEEP_ACCTOTALS; +extern unsigned IOCTL_RAIDFRAME_GET_COMPONENT_LABEL; +extern unsigned IOCTL_RAIDFRAME_SET_COMPONENT_LABEL; +extern unsigned IOCTL_RAIDFRAME_INIT_LABELS; +extern unsigned IOCTL_RAIDFRAME_ADD_HOT_SPARE; +extern unsigned IOCTL_RAIDFRAME_REMOVE_HOT_SPARE; +extern unsigned IOCTL_RAIDFRAME_REBUILD_IN_PLACE; +extern unsigned IOCTL_RAIDFRAME_CHECK_PARITY; +extern unsigned IOCTL_RAIDFRAME_CHECK_PARITYREWRITE_STATUS; +extern unsigned IOCTL_RAIDFRAME_CHECK_COPYBACK_STATUS; +extern unsigned IOCTL_RAIDFRAME_SET_AUTOCONFIG; +extern unsigned IOCTL_RAIDFRAME_SET_ROOT; +extern unsigned IOCTL_RAIDFRAME_DELETE_COMPONENT; +extern unsigned IOCTL_RAIDFRAME_INCORPORATE_HOT_SPARE; +extern unsigned IOCTL_RAIDFRAME_CHECK_RECON_STATUS_EXT; +extern unsigned IOCTL_RAIDFRAME_CHECK_PARITYREWRITE_STATUS_EXT; +extern unsigned IOCTL_RAIDFRAME_CHECK_COPYBACK_STATUS_EXT; +extern unsigned IOCTL_RAIDFRAME_CONFIGURE; +extern unsigned IOCTL_RAIDFRAME_GET_INFO; +extern unsigned IOCTL_RAIDFRAME_PARITYMAP_STATUS; +extern unsigned IOCTL_RAIDFRAME_PARITYMAP_GET_DISABLE; +extern unsigned IOCTL_RAIDFRAME_PARITYMAP_SET_DISABLE; +extern unsigned IOCTL_RAIDFRAME_PARITYMAP_SET_PARAMS; +extern unsigned IOCTL_RAIDFRAME_SET_LAST_UNIT; +extern unsigned IOCTL_MBPPIOCSPARAM; +extern unsigned IOCTL_MBPPIOCGPARAM; +extern unsigned IOCTL_MBPPIOCGSTAT; +extern unsigned IOCTL_SESIOC_GETNOBJ; +extern unsigned IOCTL_SESIOC_GETOBJMAP; +extern unsigned IOCTL_SESIOC_GETENCSTAT; +extern unsigned IOCTL_SESIOC_SETENCSTAT; +extern unsigned IOCTL_SESIOC_GETOBJSTAT; +extern unsigned IOCTL_SESIOC_SETOBJSTAT; +extern unsigned IOCTL_SESIOC_GETTEXT; +extern unsigned IOCTL_SESIOC_INIT; +extern unsigned IOCTL_SUN_DKIOCGGEOM; +extern unsigned IOCTL_SUN_DKIOCINFO; +extern unsigned IOCTL_SUN_DKIOCGPART; +extern unsigned IOCTL_FBIOGTYPE; +extern unsigned IOCTL_FBIOPUTCMAP; +extern unsigned IOCTL_FBIOGETCMAP; +extern unsigned IOCTL_FBIOGATTR; +extern unsigned IOCTL_FBIOSVIDEO; +extern unsigned IOCTL_FBIOGVIDEO; +extern unsigned IOCTL_FBIOSCURSOR; +extern unsigned IOCTL_FBIOGCURSOR; +extern unsigned IOCTL_FBIOSCURPOS; +extern unsigned IOCTL_FBIOGCURPOS; +extern unsigned IOCTL_FBIOGCURMAX; +extern unsigned IOCTL_KIOCTRANS; +extern unsigned IOCTL_KIOCSETKEY; +extern unsigned IOCTL_KIOCGETKEY; +extern unsigned IOCTL_KIOCGTRANS; +extern unsigned IOCTL_KIOCCMD; +extern unsigned IOCTL_KIOCTYPE; +extern unsigned IOCTL_KIOCSDIRECT; +extern unsigned IOCTL_KIOCSKEY; +extern unsigned IOCTL_KIOCGKEY; +extern unsigned IOCTL_KIOCSLED; +extern unsigned IOCTL_KIOCGLED; +extern unsigned IOCTL_KIOCLAYOUT; +extern unsigned IOCTL_VUIDSFORMAT; +extern unsigned IOCTL_VUIDGFORMAT; +extern unsigned IOCTL_STICIO_GXINFO; +extern unsigned IOCTL_STICIO_RESET; +extern unsigned IOCTL_STICIO_STARTQ; +extern unsigned IOCTL_STICIO_STOPQ; +extern unsigned IOCTL_UKYOPON_IDENTIFY; +extern unsigned IOCTL_URIO_SEND_COMMAND; +extern unsigned IOCTL_URIO_RECV_COMMAND; +extern unsigned IOCTL_USB_REQUEST; +extern unsigned IOCTL_USB_SETDEBUG; +extern unsigned IOCTL_USB_DISCOVER; +extern unsigned IOCTL_USB_DEVICEINFO; +extern unsigned IOCTL_USB_DEVICEINFO_OLD; +extern unsigned IOCTL_USB_DEVICESTATS; +extern unsigned IOCTL_USB_GET_REPORT_DESC; +extern unsigned IOCTL_USB_SET_IMMED; +extern unsigned IOCTL_USB_GET_REPORT; +extern unsigned IOCTL_USB_SET_REPORT; +extern unsigned IOCTL_USB_GET_REPORT_ID; +extern unsigned IOCTL_USB_GET_CONFIG; +extern unsigned IOCTL_USB_SET_CONFIG; +extern unsigned IOCTL_USB_GET_ALTINTERFACE; +extern unsigned IOCTL_USB_SET_ALTINTERFACE; +extern unsigned IOCTL_USB_GET_NO_ALT; +extern unsigned IOCTL_USB_GET_DEVICE_DESC; +extern unsigned IOCTL_USB_GET_CONFIG_DESC; +extern unsigned IOCTL_USB_GET_INTERFACE_DESC; +extern unsigned IOCTL_USB_GET_ENDPOINT_DESC; +extern unsigned IOCTL_USB_GET_FULL_DESC; +extern unsigned IOCTL_USB_GET_STRING_DESC; +extern unsigned IOCTL_USB_DO_REQUEST; +extern unsigned IOCTL_USB_GET_DEVICEINFO; +extern unsigned IOCTL_USB_GET_DEVICEINFO_OLD; +extern unsigned IOCTL_USB_SET_SHORT_XFER; +extern unsigned IOCTL_USB_SET_TIMEOUT; +extern unsigned IOCTL_USB_SET_BULK_RA; +extern unsigned IOCTL_USB_SET_BULK_WB; +extern unsigned IOCTL_USB_SET_BULK_RA_OPT; +extern unsigned IOCTL_USB_SET_BULK_WB_OPT; +extern unsigned IOCTL_USB_GET_CM_OVER_DATA; +extern unsigned IOCTL_USB_SET_CM_OVER_DATA; +extern unsigned IOCTL_UTOPPYIOTURBO; +extern unsigned IOCTL_UTOPPYIOCANCEL; +extern unsigned IOCTL_UTOPPYIOREBOOT; +extern unsigned IOCTL_UTOPPYIOSTATS; +extern unsigned IOCTL_UTOPPYIORENAME; +extern unsigned IOCTL_UTOPPYIOMKDIR; +extern unsigned IOCTL_UTOPPYIODELETE; +extern unsigned IOCTL_UTOPPYIOREADDIR; +extern unsigned IOCTL_UTOPPYIOREADFILE; +extern unsigned IOCTL_UTOPPYIOWRITEFILE; +extern unsigned IOCTL_DIOSXDCMD; +extern unsigned IOCTL_VT_OPENQRY; +extern unsigned IOCTL_VT_SETMODE; +extern unsigned IOCTL_VT_GETMODE; +extern unsigned IOCTL_VT_RELDISP; +extern unsigned IOCTL_VT_ACTIVATE; +extern unsigned IOCTL_VT_WAITACTIVE; +extern unsigned IOCTL_VT_GETACTIVE; +extern unsigned IOCTL_VT_GETSTATE; +extern unsigned IOCTL_KDGETKBENT; +extern unsigned IOCTL_KDGKBMODE; +extern unsigned IOCTL_KDSKBMODE; +extern unsigned IOCTL_KDMKTONE; +extern unsigned IOCTL_KDSETMODE; +extern unsigned IOCTL_KDENABIO; +extern unsigned IOCTL_KDDISABIO; +extern unsigned IOCTL_KDGKBTYPE; +extern unsigned IOCTL_KDGETLED; +extern unsigned IOCTL_KDSETLED; +extern unsigned IOCTL_KDSETRAD; +extern unsigned IOCTL_VGAPCVTID; +extern unsigned IOCTL_CONS_GETVERS; +extern unsigned IOCTL_WSKBDIO_GTYPE; +extern unsigned IOCTL_WSKBDIO_BELL; +extern unsigned IOCTL_WSKBDIO_COMPLEXBELL; +extern unsigned IOCTL_WSKBDIO_SETBELL; +extern unsigned IOCTL_WSKBDIO_GETBELL; +extern unsigned IOCTL_WSKBDIO_SETDEFAULTBELL; +extern unsigned IOCTL_WSKBDIO_GETDEFAULTBELL; +extern unsigned IOCTL_WSKBDIO_SETKEYREPEAT; +extern unsigned IOCTL_WSKBDIO_GETKEYREPEAT; +extern unsigned IOCTL_WSKBDIO_SETDEFAULTKEYREPEAT; +extern unsigned IOCTL_WSKBDIO_GETDEFAULTKEYREPEAT; +extern unsigned IOCTL_WSKBDIO_SETLEDS; +extern unsigned IOCTL_WSKBDIO_GETLEDS; +extern unsigned IOCTL_WSKBDIO_GETMAP; +extern unsigned IOCTL_WSKBDIO_SETMAP; +extern unsigned IOCTL_WSKBDIO_GETENCODING; +extern unsigned IOCTL_WSKBDIO_SETENCODING; +extern unsigned IOCTL_WSKBDIO_SETMODE; +extern unsigned IOCTL_WSKBDIO_GETMODE; +extern unsigned IOCTL_WSKBDIO_SETKEYCLICK; +extern unsigned IOCTL_WSKBDIO_GETKEYCLICK; +extern unsigned IOCTL_WSKBDIO_GETSCROLL; +extern unsigned IOCTL_WSKBDIO_SETSCROLL; +extern unsigned IOCTL_WSKBDIO_SETVERSION; +extern unsigned IOCTL_WSMOUSEIO_GTYPE; +extern unsigned IOCTL_WSMOUSEIO_SRES; +extern unsigned IOCTL_WSMOUSEIO_SSCALE; +extern unsigned IOCTL_WSMOUSEIO_SRATE; +extern unsigned IOCTL_WSMOUSEIO_SCALIBCOORDS; +extern unsigned IOCTL_WSMOUSEIO_GCALIBCOORDS; +extern unsigned IOCTL_WSMOUSEIO_GETID; +extern unsigned IOCTL_WSMOUSEIO_GETREPEAT; +extern unsigned IOCTL_WSMOUSEIO_SETREPEAT; +extern unsigned IOCTL_WSMOUSEIO_SETVERSION; +extern unsigned IOCTL_WSDISPLAYIO_GTYPE; +extern unsigned IOCTL_WSDISPLAYIO_GINFO; +extern unsigned IOCTL_WSDISPLAYIO_GETCMAP; +extern unsigned IOCTL_WSDISPLAYIO_PUTCMAP; +extern unsigned IOCTL_WSDISPLAYIO_GVIDEO; +extern unsigned IOCTL_WSDISPLAYIO_SVIDEO; +extern unsigned IOCTL_WSDISPLAYIO_GCURPOS; +extern unsigned IOCTL_WSDISPLAYIO_SCURPOS; +extern unsigned IOCTL_WSDISPLAYIO_GCURMAX; +extern unsigned IOCTL_WSDISPLAYIO_GCURSOR; +extern unsigned IOCTL_WSDISPLAYIO_SCURSOR; +extern unsigned IOCTL_WSDISPLAYIO_GMODE; +extern unsigned IOCTL_WSDISPLAYIO_SMODE; +extern unsigned IOCTL_WSDISPLAYIO_LDFONT; +extern unsigned IOCTL_WSDISPLAYIO_ADDSCREEN; +extern unsigned IOCTL_WSDISPLAYIO_DELSCREEN; +extern unsigned IOCTL_WSDISPLAYIO_SFONT; +extern unsigned IOCTL__O_WSDISPLAYIO_SETKEYBOARD; +extern unsigned IOCTL_WSDISPLAYIO_GETPARAM; +extern unsigned IOCTL_WSDISPLAYIO_SETPARAM; +extern unsigned IOCTL_WSDISPLAYIO_GETACTIVESCREEN; +extern unsigned IOCTL_WSDISPLAYIO_GETWSCHAR; +extern unsigned IOCTL_WSDISPLAYIO_PUTWSCHAR; +extern unsigned IOCTL_WSDISPLAYIO_DGSCROLL; +extern unsigned IOCTL_WSDISPLAYIO_DSSCROLL; +extern unsigned IOCTL_WSDISPLAYIO_GMSGATTRS; +extern unsigned IOCTL_WSDISPLAYIO_SMSGATTRS; +extern unsigned IOCTL_WSDISPLAYIO_GBORDER; +extern unsigned IOCTL_WSDISPLAYIO_SBORDER; +extern unsigned IOCTL_WSDISPLAYIO_SSPLASH; +extern unsigned IOCTL_WSDISPLAYIO_SPROGRESS; +extern unsigned IOCTL_WSDISPLAYIO_LINEBYTES; +extern unsigned IOCTL_WSDISPLAYIO_SETVERSION; +extern unsigned IOCTL_WSMUXIO_ADD_DEVICE; +extern unsigned IOCTL_WSMUXIO_REMOVE_DEVICE; +extern unsigned IOCTL_WSMUXIO_LIST_DEVICES; +extern unsigned IOCTL_WSMUXIO_INJECTEVENT; +extern unsigned IOCTL_WSDISPLAYIO_GET_BUSID; +extern unsigned IOCTL_WSDISPLAYIO_GET_EDID; +extern unsigned IOCTL_WSDISPLAYIO_SET_POLLING; +extern unsigned IOCTL_WSDISPLAYIO_GET_FBINFO; +extern unsigned IOCTL_WSDISPLAYIO_DOBLIT; +extern unsigned IOCTL_WSDISPLAYIO_WAITBLIT; +extern unsigned IOCTL_BIOCLOCATE; +extern unsigned IOCTL_BIOCINQ; +extern unsigned IOCTL_BIOCDISK_NOVOL; +extern unsigned IOCTL_BIOCDISK; +extern unsigned IOCTL_BIOCVOL; +extern unsigned IOCTL_BIOCALARM; +extern unsigned IOCTL_BIOCBLINK; +extern unsigned IOCTL_BIOCSETSTATE; +extern unsigned IOCTL_BIOCVOLOPS; +extern unsigned IOCTL_MD_GETCONF; +extern unsigned IOCTL_MD_SETCONF; +extern unsigned IOCTL_CCDIOCSET; +extern unsigned IOCTL_CCDIOCCLR; +extern unsigned IOCTL_CGDIOCSET; +extern unsigned IOCTL_CGDIOCCLR; +extern unsigned IOCTL_CGDIOCGET; +extern unsigned IOCTL_FSSIOCSET; +extern unsigned IOCTL_FSSIOCGET; +extern unsigned IOCTL_FSSIOCCLR; +extern unsigned IOCTL_FSSIOFSET; +extern unsigned IOCTL_FSSIOFGET; +extern unsigned IOCTL_BTDEV_ATTACH; +extern unsigned IOCTL_BTDEV_DETACH; +extern unsigned IOCTL_BTSCO_GETINFO; +extern unsigned IOCTL_KTTCP_IO_SEND; +extern unsigned IOCTL_KTTCP_IO_RECV; +extern unsigned IOCTL_IOC_LOCKSTAT_GVERSION; +extern unsigned IOCTL_IOC_LOCKSTAT_ENABLE; +extern unsigned IOCTL_IOC_LOCKSTAT_DISABLE; +extern unsigned IOCTL_VNDIOCSET; +extern unsigned IOCTL_VNDIOCCLR; +extern unsigned IOCTL_VNDIOCGET; +extern unsigned IOCTL_SPKRTONE; +extern unsigned IOCTL_SPKRTUNE; +extern unsigned IOCTL_SPKRGETVOL; +extern unsigned IOCTL_SPKRSETVOL; +#if defined(__x86_64__) +extern unsigned IOCTL_NVMM_IOC_CAPABILITY; +extern unsigned IOCTL_NVMM_IOC_MACHINE_CREATE; +extern unsigned IOCTL_NVMM_IOC_MACHINE_DESTROY; +extern unsigned IOCTL_NVMM_IOC_MACHINE_CONFIGURE; +extern unsigned IOCTL_NVMM_IOC_VCPU_CREATE; +extern unsigned IOCTL_NVMM_IOC_VCPU_DESTROY; +extern unsigned IOCTL_NVMM_IOC_VCPU_CONFIGURE; +extern unsigned IOCTL_NVMM_IOC_VCPU_SETSTATE; +extern unsigned IOCTL_NVMM_IOC_VCPU_GETSTATE; +extern unsigned IOCTL_NVMM_IOC_VCPU_INJECT; +extern unsigned IOCTL_NVMM_IOC_VCPU_RUN; +extern unsigned IOCTL_NVMM_IOC_GPA_MAP; +extern unsigned IOCTL_NVMM_IOC_GPA_UNMAP; +extern unsigned IOCTL_NVMM_IOC_HVA_MAP; +extern unsigned IOCTL_NVMM_IOC_HVA_UNMAP; +extern unsigned IOCTL_NVMM_IOC_CTL; +#endif +extern unsigned IOCTL_AUTOFSREQUEST; +extern unsigned IOCTL_AUTOFSDONE; +extern unsigned IOCTL_BIOCGBLEN; +extern unsigned IOCTL_BIOCSBLEN; +extern unsigned IOCTL_BIOCSETF; +extern unsigned IOCTL_BIOCFLUSH; +extern unsigned IOCTL_BIOCPROMISC; +extern unsigned IOCTL_BIOCGDLT; +extern unsigned IOCTL_BIOCGETIF; +extern unsigned IOCTL_BIOCSETIF; +extern unsigned IOCTL_BIOCGSTATS; +extern unsigned IOCTL_BIOCGSTATSOLD; +extern unsigned IOCTL_BIOCIMMEDIATE; +extern unsigned IOCTL_BIOCVERSION; +extern unsigned IOCTL_BIOCSTCPF; +extern unsigned IOCTL_BIOCSUDPF; +extern unsigned IOCTL_BIOCGHDRCMPLT; +extern unsigned IOCTL_BIOCSHDRCMPLT; +extern unsigned IOCTL_BIOCSDLT; +extern unsigned IOCTL_BIOCGDLTLIST; +extern unsigned IOCTL_BIOCGDIRECTION; +extern unsigned IOCTL_BIOCSDIRECTION; +extern unsigned IOCTL_BIOCSRTIMEOUT; +extern unsigned IOCTL_BIOCGRTIMEOUT; +extern unsigned IOCTL_BIOCGFEEDBACK; +extern unsigned IOCTL_BIOCSFEEDBACK; +extern unsigned IOCTL_GRESADDRS; +extern unsigned IOCTL_GRESADDRD; +extern unsigned IOCTL_GREGADDRS; +extern unsigned IOCTL_GREGADDRD; +extern unsigned IOCTL_GRESPROTO; +extern unsigned IOCTL_GREGPROTO; +extern unsigned IOCTL_GRESSOCK; +extern unsigned IOCTL_GREDSOCK; +extern unsigned IOCTL_PPPIOCGRAWIN; +extern unsigned IOCTL_PPPIOCGFLAGS; +extern unsigned IOCTL_PPPIOCSFLAGS; +extern unsigned IOCTL_PPPIOCGASYNCMAP; +extern unsigned IOCTL_PPPIOCSASYNCMAP; +extern unsigned IOCTL_PPPIOCGUNIT; +extern unsigned IOCTL_PPPIOCGRASYNCMAP; +extern unsigned IOCTL_PPPIOCSRASYNCMAP; +extern unsigned IOCTL_PPPIOCGMRU; +extern unsigned IOCTL_PPPIOCSMRU; +extern unsigned IOCTL_PPPIOCSMAXCID; +extern unsigned IOCTL_PPPIOCGXASYNCMAP; +extern unsigned IOCTL_PPPIOCSXASYNCMAP; +extern unsigned IOCTL_PPPIOCXFERUNIT; +extern unsigned IOCTL_PPPIOCSCOMPRESS; +extern unsigned IOCTL_PPPIOCGNPMODE; +extern unsigned IOCTL_PPPIOCSNPMODE; +extern unsigned IOCTL_PPPIOCGIDLE; +extern unsigned IOCTL_PPPIOCGMTU; +extern unsigned IOCTL_PPPIOCSMTU; +extern unsigned IOCTL_SIOCGPPPSTATS; +extern unsigned IOCTL_SIOCGPPPCSTATS; +extern unsigned IOCTL_IOC_NPF_VERSION; +extern unsigned IOCTL_IOC_NPF_SWITCH; +extern unsigned IOCTL_IOC_NPF_LOAD; +extern unsigned IOCTL_IOC_NPF_TABLE; +extern unsigned IOCTL_IOC_NPF_STATS; +extern unsigned IOCTL_IOC_NPF_SAVE; +extern unsigned IOCTL_IOC_NPF_RULE; +extern unsigned IOCTL_IOC_NPF_CONN_LOOKUP; +extern unsigned IOCTL_IOC_NPF_TABLE_REPLACE; +extern unsigned IOCTL_PPPOESETPARMS; +extern unsigned IOCTL_PPPOEGETPARMS; +extern unsigned IOCTL_PPPOEGETSESSION; +extern unsigned IOCTL_SPPPGETAUTHCFG; +extern unsigned IOCTL_SPPPSETAUTHCFG; +extern unsigned IOCTL_SPPPGETLCPCFG; +extern unsigned IOCTL_SPPPSETLCPCFG; +extern unsigned IOCTL_SPPPGETSTATUS; +extern unsigned IOCTL_SPPPGETSTATUSNCP; +extern unsigned IOCTL_SPPPGETIDLETO; +extern unsigned IOCTL_SPPPSETIDLETO; +extern unsigned IOCTL_SPPPGETAUTHFAILURES; +extern unsigned IOCTL_SPPPSETAUTHFAILURE; +extern unsigned IOCTL_SPPPSETDNSOPTS; +extern unsigned IOCTL_SPPPGETDNSOPTS; +extern unsigned IOCTL_SPPPGETDNSADDRS; +extern unsigned IOCTL_SPPPSETKEEPALIVE; +extern unsigned IOCTL_SPPPGETKEEPALIVE; +extern unsigned IOCTL_SRT_GETNRT; +extern unsigned IOCTL_SRT_GETRT; +extern unsigned IOCTL_SRT_SETRT; +extern unsigned IOCTL_SRT_DELRT; +extern unsigned IOCTL_SRT_SFLAGS; +extern unsigned IOCTL_SRT_GFLAGS; +extern unsigned IOCTL_SRT_SGFLAGS; +extern unsigned IOCTL_SRT_DEBUG; +extern unsigned IOCTL_TAPGIFNAME; +extern unsigned IOCTL_TUNSDEBUG; +extern unsigned IOCTL_TUNGDEBUG; +extern unsigned IOCTL_TUNSIFMODE; +extern unsigned IOCTL_TUNSLMODE; +extern unsigned IOCTL_TUNSIFHEAD; +extern unsigned IOCTL_TUNGIFHEAD; +extern unsigned IOCTL_DIOCSTART; +extern unsigned IOCTL_DIOCSTOP; +extern unsigned IOCTL_DIOCADDRULE; +extern unsigned IOCTL_DIOCGETRULES; +extern unsigned IOCTL_DIOCGETRULE; +extern unsigned IOCTL_DIOCSETLCK; +extern unsigned IOCTL_DIOCCLRSTATES; +extern unsigned IOCTL_DIOCGETSTATE; +extern unsigned IOCTL_DIOCSETSTATUSIF; +extern unsigned IOCTL_DIOCGETSTATUS; +extern unsigned IOCTL_DIOCCLRSTATUS; +extern unsigned IOCTL_DIOCNATLOOK; +extern unsigned IOCTL_DIOCSETDEBUG; +extern unsigned IOCTL_DIOCGETSTATES; +extern unsigned IOCTL_DIOCCHANGERULE; +extern unsigned IOCTL_DIOCSETTIMEOUT; +extern unsigned IOCTL_DIOCGETTIMEOUT; +extern unsigned IOCTL_DIOCADDSTATE; +extern unsigned IOCTL_DIOCCLRRULECTRS; +extern unsigned IOCTL_DIOCGETLIMIT; +extern unsigned IOCTL_DIOCSETLIMIT; +extern unsigned IOCTL_DIOCKILLSTATES; +extern unsigned IOCTL_DIOCSTARTALTQ; +extern unsigned IOCTL_DIOCSTOPALTQ; +extern unsigned IOCTL_DIOCADDALTQ; +extern unsigned IOCTL_DIOCGETALTQS; +extern unsigned IOCTL_DIOCGETALTQ; +extern unsigned IOCTL_DIOCCHANGEALTQ; +extern unsigned IOCTL_DIOCGETQSTATS; +extern unsigned IOCTL_DIOCBEGINADDRS; +extern unsigned IOCTL_DIOCADDADDR; +extern unsigned IOCTL_DIOCGETADDRS; +extern unsigned IOCTL_DIOCGETADDR; +extern unsigned IOCTL_DIOCCHANGEADDR; +extern unsigned IOCTL_DIOCADDSTATES; +extern unsigned IOCTL_DIOCGETRULESETS; +extern unsigned IOCTL_DIOCGETRULESET; +extern unsigned IOCTL_DIOCRCLRTABLES; +extern unsigned IOCTL_DIOCRADDTABLES; +extern unsigned IOCTL_DIOCRDELTABLES; +extern unsigned IOCTL_DIOCRGETTABLES; +extern unsigned IOCTL_DIOCRGETTSTATS; +extern unsigned IOCTL_DIOCRCLRTSTATS; +extern unsigned IOCTL_DIOCRCLRADDRS; +extern unsigned IOCTL_DIOCRADDADDRS; +extern unsigned IOCTL_DIOCRDELADDRS; +extern unsigned IOCTL_DIOCRSETADDRS; +extern unsigned IOCTL_DIOCRGETADDRS; +extern unsigned IOCTL_DIOCRGETASTATS; +extern unsigned IOCTL_DIOCRCLRASTATS; +extern unsigned IOCTL_DIOCRTSTADDRS; +extern unsigned IOCTL_DIOCRSETTFLAGS; +extern unsigned IOCTL_DIOCRINADEFINE; +extern unsigned IOCTL_DIOCOSFPFLUSH; +extern unsigned IOCTL_DIOCOSFPADD; +extern unsigned IOCTL_DIOCOSFPGET; +extern unsigned IOCTL_DIOCXBEGIN; +extern unsigned IOCTL_DIOCXCOMMIT; +extern unsigned IOCTL_DIOCXROLLBACK; +extern unsigned IOCTL_DIOCGETSRCNODES; +extern unsigned IOCTL_DIOCCLRSRCNODES; +extern unsigned IOCTL_DIOCSETHOSTID; +extern unsigned IOCTL_DIOCIGETIFACES; +extern unsigned IOCTL_DIOCSETIFFLAG; +extern unsigned IOCTL_DIOCCLRIFFLAG; +extern unsigned IOCTL_DIOCKILLSRCNODES; +extern unsigned IOCTL_SLIOCGUNIT; +extern unsigned IOCTL_SIOCGBTINFO; +extern unsigned IOCTL_SIOCGBTINFOA; +extern unsigned IOCTL_SIOCNBTINFO; +extern unsigned IOCTL_SIOCSBTFLAGS; +extern unsigned IOCTL_SIOCSBTPOLICY; +extern unsigned IOCTL_SIOCSBTPTYPE; +extern unsigned IOCTL_SIOCGBTSTATS; +extern unsigned IOCTL_SIOCZBTSTATS; +extern unsigned IOCTL_SIOCBTDUMP; +extern unsigned IOCTL_SIOCSBTSCOMTU; +extern unsigned IOCTL_SIOCGBTFEAT; +extern unsigned IOCTL_SIOCADNAT; +extern unsigned IOCTL_SIOCRMNAT; +extern unsigned IOCTL_SIOCGNATS; +extern unsigned IOCTL_SIOCGNATL; +extern unsigned IOCTL_SIOCPURGENAT; +extern unsigned IOCTL_SIOCCONNECTX; +extern unsigned IOCTL_SIOCCONNECTXDEL; +extern unsigned IOCTL_SIOCSIFINFO_FLAGS; +extern unsigned IOCTL_SIOCAADDRCTL_POLICY; +extern unsigned IOCTL_SIOCDADDRCTL_POLICY; +extern unsigned IOCTL_SMBIOC_OPENSESSION; +extern unsigned IOCTL_SMBIOC_OPENSHARE; +extern unsigned IOCTL_SMBIOC_REQUEST; +extern unsigned IOCTL_SMBIOC_SETFLAGS; +extern unsigned IOCTL_SMBIOC_LOOKUP; +extern unsigned IOCTL_SMBIOC_READ; +extern unsigned IOCTL_SMBIOC_WRITE; +extern unsigned IOCTL_AGPIOC_INFO; +extern unsigned IOCTL_AGPIOC_ACQUIRE; +extern unsigned IOCTL_AGPIOC_RELEASE; +extern unsigned IOCTL_AGPIOC_SETUP; +extern unsigned IOCTL_AGPIOC_ALLOCATE; +extern unsigned IOCTL_AGPIOC_DEALLOCATE; +extern unsigned IOCTL_AGPIOC_BIND; +extern unsigned IOCTL_AGPIOC_UNBIND; +extern unsigned IOCTL_AUDIO_GETINFO; +extern unsigned IOCTL_AUDIO_SETINFO; +extern unsigned IOCTL_AUDIO_DRAIN; +extern unsigned IOCTL_AUDIO_FLUSH; +extern unsigned IOCTL_AUDIO_WSEEK; +extern unsigned IOCTL_AUDIO_RERROR; +extern unsigned IOCTL_AUDIO_GETDEV; +extern unsigned IOCTL_AUDIO_GETENC; +extern unsigned IOCTL_AUDIO_GETFD; +extern unsigned IOCTL_AUDIO_SETFD; +extern unsigned IOCTL_AUDIO_PERROR; +extern unsigned IOCTL_AUDIO_GETIOFFS; +extern unsigned IOCTL_AUDIO_GETOOFFS; +extern unsigned IOCTL_AUDIO_GETPROPS; +extern unsigned IOCTL_AUDIO_GETBUFINFO; +extern unsigned IOCTL_AUDIO_SETCHAN; +extern unsigned IOCTL_AUDIO_GETCHAN; +extern unsigned IOCTL_AUDIO_QUERYFORMAT; +extern unsigned IOCTL_AUDIO_GETFORMAT; +extern unsigned IOCTL_AUDIO_SETFORMAT; +extern unsigned IOCTL_AUDIO_MIXER_READ; +extern unsigned IOCTL_AUDIO_MIXER_WRITE; +extern unsigned IOCTL_AUDIO_MIXER_DEVINFO; +extern unsigned IOCTL_ATAIOCCOMMAND; +extern unsigned IOCTL_ATABUSIOSCAN; +extern unsigned IOCTL_ATABUSIORESET; +extern unsigned IOCTL_ATABUSIODETACH; +extern unsigned IOCTL_CDIOCPLAYTRACKS; +extern unsigned IOCTL_CDIOCPLAYBLOCKS; +extern unsigned IOCTL_CDIOCREADSUBCHANNEL; +extern unsigned IOCTL_CDIOREADTOCHEADER; +extern unsigned IOCTL_CDIOREADTOCENTRIES; +extern unsigned IOCTL_CDIOREADMSADDR; +extern unsigned IOCTL_CDIOCSETPATCH; +extern unsigned IOCTL_CDIOCGETVOL; +extern unsigned IOCTL_CDIOCSETVOL; +extern unsigned IOCTL_CDIOCSETMONO; +extern unsigned IOCTL_CDIOCSETSTEREO; +extern unsigned IOCTL_CDIOCSETMUTE; +extern unsigned IOCTL_CDIOCSETLEFT; +extern unsigned IOCTL_CDIOCSETRIGHT; +extern unsigned IOCTL_CDIOCSETDEBUG; +extern unsigned IOCTL_CDIOCCLRDEBUG; +extern unsigned IOCTL_CDIOCPAUSE; +extern unsigned IOCTL_CDIOCRESUME; +extern unsigned IOCTL_CDIOCRESET; +extern unsigned IOCTL_CDIOCSTART; +extern unsigned IOCTL_CDIOCSTOP; +extern unsigned IOCTL_CDIOCEJECT; +extern unsigned IOCTL_CDIOCALLOW; +extern unsigned IOCTL_CDIOCPREVENT; +extern unsigned IOCTL_CDIOCCLOSE; +extern unsigned IOCTL_CDIOCPLAYMSF; +extern unsigned IOCTL_CDIOCLOADUNLOAD; +extern unsigned IOCTL_CHIOMOVE; +extern unsigned IOCTL_CHIOEXCHANGE; +extern unsigned IOCTL_CHIOPOSITION; +extern unsigned IOCTL_CHIOGPICKER; +extern unsigned IOCTL_CHIOSPICKER; +extern unsigned IOCTL_CHIOGPARAMS; +extern unsigned IOCTL_CHIOIELEM; +extern unsigned IOCTL_OCHIOGSTATUS; +extern unsigned IOCTL_CHIOGSTATUS; +extern unsigned IOCTL_CHIOSVOLTAG; +extern unsigned IOCTL_CLOCKCTL_SETTIMEOFDAY; +extern unsigned IOCTL_CLOCKCTL_ADJTIME; +extern unsigned IOCTL_CLOCKCTL_CLOCK_SETTIME; +extern unsigned IOCTL_CLOCKCTL_NTP_ADJTIME; +extern unsigned IOCTL_IOC_CPU_SETSTATE; +extern unsigned IOCTL_IOC_CPU_GETSTATE; +extern unsigned IOCTL_IOC_CPU_GETCOUNT; +extern unsigned IOCTL_IOC_CPU_MAPID; +extern unsigned IOCTL_IOC_CPU_UCODE_GET_VERSION; +extern unsigned IOCTL_IOC_CPU_UCODE_APPLY; +extern unsigned IOCTL_DIOCGDINFO; +extern unsigned IOCTL_DIOCSDINFO; +extern unsigned IOCTL_DIOCWDINFO; +extern unsigned IOCTL_DIOCRFORMAT; +extern unsigned IOCTL_DIOCWFORMAT; +extern unsigned IOCTL_DIOCSSTEP; +extern unsigned IOCTL_DIOCSRETRIES; +extern unsigned IOCTL_DIOCKLABEL; +extern unsigned IOCTL_DIOCWLABEL; +extern unsigned IOCTL_DIOCSBAD; +extern unsigned IOCTL_DIOCEJECT; +extern unsigned IOCTL_ODIOCEJECT; +extern unsigned IOCTL_DIOCLOCK; +extern unsigned IOCTL_DIOCGDEFLABEL; +extern unsigned IOCTL_DIOCCLRLABEL; +extern unsigned IOCTL_DIOCGCACHE; +extern unsigned IOCTL_DIOCSCACHE; +extern unsigned IOCTL_DIOCCACHESYNC; +extern unsigned IOCTL_DIOCBSLIST; +extern unsigned IOCTL_DIOCBSFLUSH; +extern unsigned IOCTL_DIOCAWEDGE; +extern unsigned IOCTL_DIOCGWEDGEINFO; +extern unsigned IOCTL_DIOCDWEDGE; +extern unsigned IOCTL_DIOCLWEDGES; +extern unsigned IOCTL_DIOCGSTRATEGY; +extern unsigned IOCTL_DIOCSSTRATEGY; +extern unsigned IOCTL_DIOCGDISKINFO; +extern unsigned IOCTL_DIOCTUR; +extern unsigned IOCTL_DIOCMWEDGES; +extern unsigned IOCTL_DIOCGSECTORSIZE; +extern unsigned IOCTL_DIOCGMEDIASIZE; +extern unsigned IOCTL_DIOCRMWEDGES; +extern unsigned IOCTL_DRVDETACHDEV; +extern unsigned IOCTL_DRVRESCANBUS; +extern unsigned IOCTL_DRVCTLCOMMAND; +extern unsigned IOCTL_DRVRESUMEDEV; +extern unsigned IOCTL_DRVLISTDEV; +extern unsigned IOCTL_DRVGETEVENT; +extern unsigned IOCTL_DRVSUSPENDDEV; +extern unsigned IOCTL_DVD_READ_STRUCT; +extern unsigned IOCTL_DVD_WRITE_STRUCT; +extern unsigned IOCTL_DVD_AUTH; +extern unsigned IOCTL_ENVSYS_GETDICTIONARY; +extern unsigned IOCTL_ENVSYS_SETDICTIONARY; +extern unsigned IOCTL_ENVSYS_REMOVEPROPS; +extern unsigned IOCTL_ENVSYS_GTREDATA; +extern unsigned IOCTL_ENVSYS_GTREINFO; +extern unsigned IOCTL_KFILTER_BYFILTER; +extern unsigned IOCTL_KFILTER_BYNAME; +extern unsigned IOCTL_FDIOCGETOPTS; +extern unsigned IOCTL_FDIOCSETOPTS; +extern unsigned IOCTL_FDIOCSETFORMAT; +extern unsigned IOCTL_FDIOCGETFORMAT; +extern unsigned IOCTL_FDIOCFORMAT_TRACK; +extern unsigned IOCTL_FIOCLEX; +extern unsigned IOCTL_FIONCLEX; +extern unsigned IOCTL_FIOSEEKDATA; +extern unsigned IOCTL_FIOSEEKHOLE; +extern unsigned IOCTL_FIONREAD; +extern unsigned IOCTL_FIONBIO; +extern unsigned IOCTL_FIOASYNC; +extern unsigned IOCTL_FIOSETOWN; +extern unsigned IOCTL_FIOGETOWN; +extern unsigned IOCTL_OFIOGETBMAP; +extern unsigned IOCTL_FIOGETBMAP; +extern unsigned IOCTL_FIONWRITE; +extern unsigned IOCTL_FIONSPACE; +extern unsigned IOCTL_GPIOINFO; +extern unsigned IOCTL_GPIOSET; +extern unsigned IOCTL_GPIOUNSET; +extern unsigned IOCTL_GPIOREAD; +extern unsigned IOCTL_GPIOWRITE; +extern unsigned IOCTL_GPIOTOGGLE; +extern unsigned IOCTL_GPIOATTACH; +extern unsigned IOCTL_PTIOCNETBSD; +extern unsigned IOCTL_PTIOCSUNOS; +extern unsigned IOCTL_PTIOCLINUX; +extern unsigned IOCTL_PTIOCFREEBSD; +extern unsigned IOCTL_PTIOCULTRIX; +extern unsigned IOCTL_TIOCHPCL; +extern unsigned IOCTL_TIOCGETP; +extern unsigned IOCTL_TIOCSETP; +extern unsigned IOCTL_TIOCSETN; +extern unsigned IOCTL_TIOCSETC; +extern unsigned IOCTL_TIOCGETC; +extern unsigned IOCTL_TIOCLBIS; +extern unsigned IOCTL_TIOCLBIC; +extern unsigned IOCTL_TIOCLSET; +extern unsigned IOCTL_TIOCLGET; +extern unsigned IOCTL_TIOCSLTC; +extern unsigned IOCTL_TIOCGLTC; +extern unsigned IOCTL_OTIOCCONS; +extern unsigned IOCTL_JOY_SETTIMEOUT; +extern unsigned IOCTL_JOY_GETTIMEOUT; +extern unsigned IOCTL_JOY_SET_X_OFFSET; +extern unsigned IOCTL_JOY_SET_Y_OFFSET; +extern unsigned IOCTL_JOY_GET_X_OFFSET; +extern unsigned IOCTL_JOY_GET_Y_OFFSET; +extern unsigned IOCTL_OKIOCGSYMBOL; +extern unsigned IOCTL_OKIOCGVALUE; +extern unsigned IOCTL_KIOCGSIZE; +extern unsigned IOCTL_KIOCGVALUE; +extern unsigned IOCTL_KIOCGSYMBOL; +extern unsigned IOCTL_LUAINFO; +extern unsigned IOCTL_LUACREATE; +extern unsigned IOCTL_LUADESTROY; +extern unsigned IOCTL_LUAREQUIRE; +extern unsigned IOCTL_LUALOAD; +extern unsigned IOCTL_MIDI_PRETIME; +extern unsigned IOCTL_MIDI_MPUMODE; +extern unsigned IOCTL_MIDI_MPUCMD; +extern unsigned IOCTL_SEQUENCER_RESET; +extern unsigned IOCTL_SEQUENCER_SYNC; +extern unsigned IOCTL_SEQUENCER_INFO; +extern unsigned IOCTL_SEQUENCER_CTRLRATE; +extern unsigned IOCTL_SEQUENCER_GETOUTCOUNT; +extern unsigned IOCTL_SEQUENCER_GETINCOUNT; +extern unsigned IOCTL_SEQUENCER_RESETSAMPLES; +extern unsigned IOCTL_SEQUENCER_NRSYNTHS; +extern unsigned IOCTL_SEQUENCER_NRMIDIS; +extern unsigned IOCTL_SEQUENCER_THRESHOLD; +extern unsigned IOCTL_SEQUENCER_MEMAVL; +extern unsigned IOCTL_SEQUENCER_PANIC; +extern unsigned IOCTL_SEQUENCER_OUTOFBAND; +extern unsigned IOCTL_SEQUENCER_GETTIME; +extern unsigned IOCTL_SEQUENCER_TMR_TIMEBASE; +extern unsigned IOCTL_SEQUENCER_TMR_START; +extern unsigned IOCTL_SEQUENCER_TMR_STOP; +extern unsigned IOCTL_SEQUENCER_TMR_CONTINUE; +extern unsigned IOCTL_SEQUENCER_TMR_TEMPO; +extern unsigned IOCTL_SEQUENCER_TMR_SOURCE; +extern unsigned IOCTL_SEQUENCER_TMR_METRONOME; +extern unsigned IOCTL_SEQUENCER_TMR_SELECT; +extern unsigned IOCTL_SPI_IOCTL_CONFIGURE; +extern unsigned IOCTL_SPI_IOCTL_TRANSFER; +extern unsigned IOCTL_MTIOCTOP; +extern unsigned IOCTL_MTIOCGET; +extern unsigned IOCTL_MTIOCIEOT; +extern unsigned IOCTL_MTIOCEEOT; +extern unsigned IOCTL_MTIOCRDSPOS; +extern unsigned IOCTL_MTIOCRDHPOS; +extern unsigned IOCTL_MTIOCSLOCATE; +extern unsigned IOCTL_MTIOCHLOCATE; +extern unsigned IOCTL_POWER_EVENT_RECVDICT; +extern unsigned IOCTL_POWER_IOC_GET_TYPE; +extern unsigned IOCTL_RIOCGINFO; +extern unsigned IOCTL_RIOCSINFO; +extern unsigned IOCTL_RIOCSSRCH; +extern unsigned IOCTL_RNDGETENTCNT; +extern unsigned IOCTL_RNDGETSRCNUM; +extern unsigned IOCTL_RNDGETSRCNAME; +extern unsigned IOCTL_RNDCTL; +extern unsigned IOCTL_RNDADDDATA; +extern unsigned IOCTL_RNDGETPOOLSTAT; +extern unsigned IOCTL_RNDGETESTNUM; +extern unsigned IOCTL_RNDGETESTNAME; +extern unsigned IOCTL_SCIOCGET; +extern unsigned IOCTL_SCIOCSET; +extern unsigned IOCTL_SCIOCRESTART; +extern unsigned IOCTL_SCIOC_USE_ADF; +extern unsigned IOCTL_SCIOCCOMMAND; +extern unsigned IOCTL_SCIOCDEBUG; +extern unsigned IOCTL_SCIOCIDENTIFY; +extern unsigned IOCTL_OSCIOCIDENTIFY; +extern unsigned IOCTL_SCIOCDECONFIG; +extern unsigned IOCTL_SCIOCRECONFIG; +extern unsigned IOCTL_SCIOCRESET; +extern unsigned IOCTL_SCBUSIOSCAN; +extern unsigned IOCTL_SCBUSIORESET; +extern unsigned IOCTL_SCBUSIODETACH; +extern unsigned IOCTL_SCBUSACCEL; +extern unsigned IOCTL_SCBUSIOLLSCAN; +extern unsigned IOCTL_SIOCSHIWAT; +extern unsigned IOCTL_SIOCGHIWAT; +extern unsigned IOCTL_SIOCSLOWAT; +extern unsigned IOCTL_SIOCGLOWAT; +extern unsigned IOCTL_SIOCATMARK; +extern unsigned IOCTL_SIOCSPGRP; +extern unsigned IOCTL_SIOCGPGRP; +extern unsigned IOCTL_SIOCPEELOFF; +extern unsigned IOCTL_SIOCADDRT; +extern unsigned IOCTL_SIOCDELRT; +extern unsigned IOCTL_SIOCSIFADDR; +extern unsigned IOCTL_SIOCGIFADDR; +extern unsigned IOCTL_SIOCSIFDSTADDR; +extern unsigned IOCTL_SIOCGIFDSTADDR; +extern unsigned IOCTL_SIOCSIFFLAGS; +extern unsigned IOCTL_SIOCGIFFLAGS; +extern unsigned IOCTL_SIOCGIFBRDADDR; +extern unsigned IOCTL_SIOCSIFBRDADDR; +extern unsigned IOCTL_SIOCGIFCONF; +extern unsigned IOCTL_SIOCGIFNETMASK; +extern unsigned IOCTL_SIOCSIFNETMASK; +extern unsigned IOCTL_SIOCGIFMETRIC; +extern unsigned IOCTL_SIOCSIFMETRIC; +extern unsigned IOCTL_SIOCDIFADDR; +extern unsigned IOCTL_SIOCAIFADDR; +extern unsigned IOCTL_SIOCGIFALIAS; +extern unsigned IOCTL_SIOCGIFAFLAG_IN; +extern unsigned IOCTL_SIOCALIFADDR; +extern unsigned IOCTL_SIOCGLIFADDR; +extern unsigned IOCTL_SIOCDLIFADDR; +extern unsigned IOCTL_SIOCSIFADDRPREF; +extern unsigned IOCTL_SIOCGIFADDRPREF; +extern unsigned IOCTL_SIOCADDMULTI; +extern unsigned IOCTL_SIOCDELMULTI; +extern unsigned IOCTL_SIOCGETVIFCNT; +extern unsigned IOCTL_SIOCGETSGCNT; +extern unsigned IOCTL_SIOCSIFMEDIA; +extern unsigned IOCTL_SIOCGIFMEDIA; +extern unsigned IOCTL_SIOCSIFGENERIC; +extern unsigned IOCTL_SIOCGIFGENERIC; +extern unsigned IOCTL_SIOCSIFPHYADDR; +extern unsigned IOCTL_SIOCGIFPSRCADDR; +extern unsigned IOCTL_SIOCGIFPDSTADDR; +extern unsigned IOCTL_SIOCDIFPHYADDR; +extern unsigned IOCTL_SIOCSLIFPHYADDR; +extern unsigned IOCTL_SIOCGLIFPHYADDR; +extern unsigned IOCTL_SIOCSIFMTU; +extern unsigned IOCTL_SIOCGIFMTU; +extern unsigned IOCTL_SIOCSDRVSPEC; +extern unsigned IOCTL_SIOCGDRVSPEC; +extern unsigned IOCTL_SIOCIFCREATE; +extern unsigned IOCTL_SIOCIFDESTROY; +extern unsigned IOCTL_SIOCIFGCLONERS; +extern unsigned IOCTL_SIOCGIFDLT; +extern unsigned IOCTL_SIOCGIFCAP; +extern unsigned IOCTL_SIOCSIFCAP; +extern unsigned IOCTL_SIOCSVH; +extern unsigned IOCTL_SIOCGVH; +extern unsigned IOCTL_SIOCINITIFADDR; +extern unsigned IOCTL_SIOCGIFDATA; +extern unsigned IOCTL_SIOCZIFDATA; +extern unsigned IOCTL_SIOCGLINKSTR; +extern unsigned IOCTL_SIOCSLINKSTR; +extern unsigned IOCTL_SIOCGETHERCAP; +extern unsigned IOCTL_SIOCGIFINDEX; +extern unsigned IOCTL_SIOCSETHERCAP; +extern unsigned IOCTL_SIOCSIFDESCR; +extern unsigned IOCTL_SIOCGIFDESCR; +extern unsigned IOCTL_SIOCGUMBINFO; +extern unsigned IOCTL_SIOCSUMBPARAM; +extern unsigned IOCTL_SIOCGUMBPARAM; +extern unsigned IOCTL_SIOCSETPFSYNC; +extern unsigned IOCTL_SIOCGETPFSYNC; +extern unsigned IOCTL_PPS_IOC_CREATE; +extern unsigned IOCTL_PPS_IOC_DESTROY; +extern unsigned IOCTL_PPS_IOC_SETPARAMS; +extern unsigned IOCTL_PPS_IOC_GETPARAMS; +extern unsigned IOCTL_PPS_IOC_GETCAP; +extern unsigned IOCTL_PPS_IOC_FETCH; +extern unsigned IOCTL_PPS_IOC_KCBIND; +extern unsigned IOCTL_TIOCEXCL; +extern unsigned IOCTL_TIOCNXCL; +extern unsigned IOCTL_TIOCFLUSH; +extern unsigned IOCTL_TIOCGETA; +extern unsigned IOCTL_TIOCSETA; +extern unsigned IOCTL_TIOCSETAW; +extern unsigned IOCTL_TIOCSETAF; +extern unsigned IOCTL_TIOCGETD; +extern unsigned IOCTL_TIOCSETD; +extern unsigned IOCTL_TIOCGLINED; +extern unsigned IOCTL_TIOCSLINED; +extern unsigned IOCTL_TIOCSBRK; +extern unsigned IOCTL_TIOCCBRK; +extern unsigned IOCTL_TIOCSDTR; +extern unsigned IOCTL_TIOCCDTR; +extern unsigned IOCTL_TIOCGPGRP; +extern unsigned IOCTL_TIOCSPGRP; +extern unsigned IOCTL_TIOCOUTQ; +extern unsigned IOCTL_TIOCSTI; +extern unsigned IOCTL_TIOCNOTTY; +extern unsigned IOCTL_TIOCPKT; +extern unsigned IOCTL_TIOCSTOP; +extern unsigned IOCTL_TIOCSTART; +extern unsigned IOCTL_TIOCMSET; +extern unsigned IOCTL_TIOCMBIS; +extern unsigned IOCTL_TIOCMBIC; +extern unsigned IOCTL_TIOCMGET; +extern unsigned IOCTL_TIOCREMOTE; +extern unsigned IOCTL_TIOCGWINSZ; +extern unsigned IOCTL_TIOCSWINSZ; +extern unsigned IOCTL_TIOCUCNTL; +extern unsigned IOCTL_TIOCSTAT; +extern unsigned IOCTL_TIOCGSID; +extern unsigned IOCTL_TIOCCONS; +extern unsigned IOCTL_TIOCSCTTY; +extern unsigned IOCTL_TIOCEXT; +extern unsigned IOCTL_TIOCSIG; +extern unsigned IOCTL_TIOCDRAIN; +extern unsigned IOCTL_TIOCGFLAGS; +extern unsigned IOCTL_TIOCSFLAGS; +extern unsigned IOCTL_TIOCDCDTIMESTAMP; +extern unsigned IOCTL_TIOCRCVFRAME; +extern unsigned IOCTL_TIOCXMTFRAME; +extern unsigned IOCTL_TIOCPTMGET; +extern unsigned IOCTL_TIOCGRANTPT; +extern unsigned IOCTL_TIOCPTSNAME; +extern unsigned IOCTL_TIOCSQSIZE; +extern unsigned IOCTL_TIOCGQSIZE; +extern unsigned IOCTL_VERIEXEC_LOAD; +extern unsigned IOCTL_VERIEXEC_TABLESIZE; +extern unsigned IOCTL_VERIEXEC_DELETE; +extern unsigned IOCTL_VERIEXEC_QUERY; +extern unsigned IOCTL_VERIEXEC_DUMP; +extern unsigned IOCTL_VERIEXEC_FLUSH; +extern unsigned IOCTL_VIDIOC_QUERYCAP; +extern unsigned IOCTL_VIDIOC_RESERVED; +extern unsigned IOCTL_VIDIOC_ENUM_FMT; +extern unsigned IOCTL_VIDIOC_G_FMT; +extern unsigned IOCTL_VIDIOC_S_FMT; +extern unsigned IOCTL_VIDIOC_REQBUFS; +extern unsigned IOCTL_VIDIOC_QUERYBUF; +extern unsigned IOCTL_VIDIOC_G_FBUF; +extern unsigned IOCTL_VIDIOC_S_FBUF; +extern unsigned IOCTL_VIDIOC_OVERLAY; +extern unsigned IOCTL_VIDIOC_QBUF; +extern unsigned IOCTL_VIDIOC_DQBUF; +extern unsigned IOCTL_VIDIOC_STREAMON; +extern unsigned IOCTL_VIDIOC_STREAMOFF; +extern unsigned IOCTL_VIDIOC_G_PARM; +extern unsigned IOCTL_VIDIOC_S_PARM; +extern unsigned IOCTL_VIDIOC_G_STD; +extern unsigned IOCTL_VIDIOC_S_STD; +extern unsigned IOCTL_VIDIOC_ENUMSTD; +extern unsigned IOCTL_VIDIOC_ENUMINPUT; +extern unsigned IOCTL_VIDIOC_G_CTRL; +extern unsigned IOCTL_VIDIOC_S_CTRL; +extern unsigned IOCTL_VIDIOC_G_TUNER; +extern unsigned IOCTL_VIDIOC_S_TUNER; +extern unsigned IOCTL_VIDIOC_G_AUDIO; +extern unsigned IOCTL_VIDIOC_S_AUDIO; +extern unsigned IOCTL_VIDIOC_QUERYCTRL; +extern unsigned IOCTL_VIDIOC_QUERYMENU; +extern unsigned IOCTL_VIDIOC_G_INPUT; +extern unsigned IOCTL_VIDIOC_S_INPUT; +extern unsigned IOCTL_VIDIOC_G_OUTPUT; +extern unsigned IOCTL_VIDIOC_S_OUTPUT; +extern unsigned IOCTL_VIDIOC_ENUMOUTPUT; +extern unsigned IOCTL_VIDIOC_G_AUDOUT; +extern unsigned IOCTL_VIDIOC_S_AUDOUT; +extern unsigned IOCTL_VIDIOC_G_MODULATOR; +extern unsigned IOCTL_VIDIOC_S_MODULATOR; +extern unsigned IOCTL_VIDIOC_G_FREQUENCY; +extern unsigned IOCTL_VIDIOC_S_FREQUENCY; +extern unsigned IOCTL_VIDIOC_CROPCAP; +extern unsigned IOCTL_VIDIOC_G_CROP; +extern unsigned IOCTL_VIDIOC_S_CROP; +extern unsigned IOCTL_VIDIOC_G_JPEGCOMP; +extern unsigned IOCTL_VIDIOC_S_JPEGCOMP; +extern unsigned IOCTL_VIDIOC_QUERYSTD; +extern unsigned IOCTL_VIDIOC_TRY_FMT; +extern unsigned IOCTL_VIDIOC_ENUMAUDIO; +extern unsigned IOCTL_VIDIOC_ENUMAUDOUT; +extern unsigned IOCTL_VIDIOC_G_PRIORITY; +extern unsigned IOCTL_VIDIOC_S_PRIORITY; +extern unsigned IOCTL_VIDIOC_ENUM_FRAMESIZES; +extern unsigned IOCTL_VIDIOC_ENUM_FRAMEINTERVALS; +extern unsigned IOCTL_WDOGIOC_GMODE; +extern unsigned IOCTL_WDOGIOC_SMODE; +extern unsigned IOCTL_WDOGIOC_WHICH; +extern unsigned IOCTL_WDOGIOC_TICKLE; +extern unsigned IOCTL_WDOGIOC_GTICKLER; +extern unsigned IOCTL_WDOGIOC_GWDOGS; +extern unsigned IOCTL_KCOV_IOC_SETBUFSIZE; +extern unsigned IOCTL_KCOV_IOC_ENABLE; +extern unsigned IOCTL_KCOV_IOC_DISABLE; +extern unsigned IOCTL_IPMICTL_RECEIVE_MSG_TRUNC; +extern unsigned IOCTL_IPMICTL_RECEIVE_MSG; +extern unsigned IOCTL_IPMICTL_SEND_COMMAND; +extern unsigned IOCTL_IPMICTL_REGISTER_FOR_CMD; +extern unsigned IOCTL_IPMICTL_UNREGISTER_FOR_CMD; +extern unsigned IOCTL_IPMICTL_SET_GETS_EVENTS_CMD; +extern unsigned IOCTL_IPMICTL_SET_MY_ADDRESS_CMD; +extern unsigned IOCTL_IPMICTL_GET_MY_ADDRESS_CMD; +extern unsigned IOCTL_IPMICTL_SET_MY_LUN_CMD; +extern unsigned IOCTL_IPMICTL_GET_MY_LUN_CMD; +extern unsigned IOCTL_SNDCTL_DSP_RESET; +extern unsigned IOCTL_SNDCTL_DSP_SYNC; +extern unsigned IOCTL_SNDCTL_DSP_SPEED; +extern unsigned IOCTL_SOUND_PCM_READ_RATE; +extern unsigned IOCTL_SNDCTL_DSP_STEREO; +extern unsigned IOCTL_SNDCTL_DSP_GETBLKSIZE; +extern unsigned IOCTL_SNDCTL_DSP_SETFMT; +extern unsigned IOCTL_SOUND_PCM_READ_BITS; +extern unsigned IOCTL_SNDCTL_DSP_CHANNELS; +extern unsigned IOCTL_SOUND_PCM_READ_CHANNELS; +extern unsigned IOCTL_SOUND_PCM_WRITE_FILTER; +extern unsigned IOCTL_SOUND_PCM_READ_FILTER; +extern unsigned IOCTL_SNDCTL_DSP_POST; +extern unsigned IOCTL_SNDCTL_DSP_SUBDIVIDE; +extern unsigned IOCTL_SNDCTL_DSP_SETFRAGMENT; +extern unsigned IOCTL_SNDCTL_DSP_GETFMTS; +extern unsigned IOCTL_SNDCTL_DSP_GETOSPACE; +extern unsigned IOCTL_SNDCTL_DSP_GETISPACE; +extern unsigned IOCTL_SNDCTL_DSP_NONBLOCK; +extern unsigned IOCTL_SNDCTL_DSP_GETCAPS; +extern unsigned IOCTL_SNDCTL_DSP_GETTRIGGER; +extern unsigned IOCTL_SNDCTL_DSP_SETTRIGGER; +extern unsigned IOCTL_SNDCTL_DSP_GETIPTR; +extern unsigned IOCTL_SNDCTL_DSP_GETOPTR; +extern unsigned IOCTL_SNDCTL_DSP_MAPINBUF; +extern unsigned IOCTL_SNDCTL_DSP_MAPOUTBUF; +extern unsigned IOCTL_SNDCTL_DSP_SETSYNCRO; +extern unsigned IOCTL_SNDCTL_DSP_SETDUPLEX; +extern unsigned IOCTL_SNDCTL_DSP_PROFILE; +extern unsigned IOCTL_SNDCTL_DSP_GETODELAY; +extern unsigned IOCTL_SOUND_MIXER_INFO; +extern unsigned IOCTL_SOUND_OLD_MIXER_INFO; +extern unsigned IOCTL_OSS_GETVERSION; +extern unsigned IOCTL_SNDCTL_SYSINFO; +extern unsigned IOCTL_SNDCTL_AUDIOINFO; +extern unsigned IOCTL_SNDCTL_ENGINEINFO; +extern unsigned IOCTL_SNDCTL_DSP_GETPLAYVOL; +extern unsigned IOCTL_SNDCTL_DSP_SETPLAYVOL; +extern unsigned IOCTL_SNDCTL_DSP_GETRECVOL; +extern unsigned IOCTL_SNDCTL_DSP_SETRECVOL; +extern unsigned IOCTL_SNDCTL_DSP_SKIP; +extern unsigned IOCTL_SNDCTL_DSP_SILENCE; + +extern const int si_SEGV_MAPERR; +extern const int si_SEGV_ACCERR; + +extern const unsigned SHA1_CTX_sz; +extern const unsigned SHA1_return_length; + +extern const unsigned MD4_CTX_sz; +extern const unsigned MD4_return_length; + +extern const unsigned RMD160_CTX_sz; +extern const unsigned RMD160_return_length; + +extern const unsigned MD5_CTX_sz; +extern const unsigned MD5_return_length; + +extern const unsigned fpos_t_sz; + +extern const unsigned MD2_CTX_sz; +extern const unsigned MD2_return_length; + +#define SHA2_EXTERN(LEN) \ + extern const unsigned SHA##LEN##_CTX_sz; \ + extern const unsigned SHA##LEN##_return_length; \ + extern const unsigned SHA##LEN##_block_length; \ + extern const unsigned SHA##LEN##_digest_length + +SHA2_EXTERN(224); +SHA2_EXTERN(256); +SHA2_EXTERN(384); +SHA2_EXTERN(512); + +#undef SHA2_EXTERN + +extern const int unvis_valid; +extern const int unvis_validpush; + +struct __sanitizer_cdbr { + void (*unmap)(void *, void *, uptr); + void *cookie; + u8 *mmap_base; + uptr mmap_size; + + u8 *hash_base; + u8 *offset_base; + u8 *data_base; + + u32 data_size; + u32 entries; + u32 entries_index; + u32 seed; + + u8 offset_size; + u8 index_size; + + u32 entries_m; + u32 entries_index_m; + u8 entries_s1, entries_s2; + u8 entries_index_s1, entries_index_s2; +}; + +struct __sanitizer_cdbw { + uptr data_counter; + uptr data_allocated; + uptr data_size; + uptr *data_len; + void **data_ptr; + uptr hash_size; + void *hash; + uptr key_counter; +}; +} // namespace __sanitizer + +#define CHECK_TYPE_SIZE(TYPE) \ + COMPILER_CHECK(sizeof(__sanitizer_##TYPE) == sizeof(TYPE)) + +#define CHECK_SIZE_AND_OFFSET(CLASS, MEMBER) \ + COMPILER_CHECK(sizeof(((__sanitizer_##CLASS *)NULL)->MEMBER) == \ + sizeof(((CLASS *)NULL)->MEMBER)); \ + COMPILER_CHECK(offsetof(__sanitizer_##CLASS, MEMBER) == \ + offsetof(CLASS, MEMBER)) + +// For sigaction, which is a function and struct at the same time, +// and thus requires explicit "struct" in sizeof() expression. +#define CHECK_STRUCT_SIZE_AND_OFFSET(CLASS, MEMBER) \ + COMPILER_CHECK(sizeof(((struct __sanitizer_##CLASS *)NULL)->MEMBER) == \ + sizeof(((struct CLASS *)NULL)->MEMBER)); \ + COMPILER_CHECK(offsetof(struct __sanitizer_##CLASS, MEMBER) == \ + offsetof(struct CLASS, MEMBER)) + +#define SIGACTION_SYMNAME __sigaction14 + +// Compat with 9.0 +extern unsigned struct_statvfs90_sz; + +#endif // SANITIZER_NETBSD + +#endif diff --git a/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_platform_limits_openbsd.h b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_platform_limits_openbsd.h new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_platform_limits_openbsd.h diff --git a/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_platform_limits_posix.cpp b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_platform_limits_posix.cpp new file mode 100644 index 0000000000..edcba3521b --- /dev/null +++ b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_platform_limits_posix.cpp @@ -0,0 +1,1308 @@ +//===-- sanitizer_platform_limits_posix.cpp -------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file is a part of Sanitizer common code. +// +// Sizes and layouts of platform-specific POSIX data structures. +//===----------------------------------------------------------------------===// + +#if defined(__linux__) || defined(__APPLE__) +// Tests in this file assume that off_t-dependent data structures match the +// libc ABI. For example, struct dirent here is what readdir() function (as +// exported from libc) returns, and not the user-facing "dirent", which +// depends on _FILE_OFFSET_BITS setting. +// To get this "true" dirent definition, we undefine _FILE_OFFSET_BITS below. +#undef _FILE_OFFSET_BITS +#endif + +// Must go after undef _FILE_OFFSET_BITS. +#include "sanitizer_platform.h" + +#if SANITIZER_LINUX || SANITIZER_MAC +// Must go after undef _FILE_OFFSET_BITS. +#include "sanitizer_glibc_version.h" + +#include <arpa/inet.h> +#include <dirent.h> +#include <grp.h> +#include <limits.h> +#include <net/if.h> +#include <netdb.h> +#include <poll.h> +#include <pthread.h> +#include <pwd.h> +#include <signal.h> +#include <stddef.h> +#include <stdio.h> +#include <sys/mman.h> +#include <sys/resource.h> +#include <sys/socket.h> +#include <sys/stat.h> +#include <sys/time.h> +#include <sys/times.h> +#include <sys/types.h> +#include <sys/utsname.h> +#include <termios.h> +#include <time.h> +#include <wchar.h> +#include <regex.h> +#if !SANITIZER_MAC +#include <utmp.h> +#endif + +#if !SANITIZER_IOS +#include <net/route.h> +#endif + +#if !SANITIZER_ANDROID +#include <sys/mount.h> +#include <sys/timeb.h> +#include <utmpx.h> +#endif + +#if SANITIZER_LINUX +#include <malloc.h> +#include <mntent.h> +#include <netinet/ether.h> +#include <sys/sysinfo.h> +#include <sys/vt.h> +#include <linux/cdrom.h> +#include <linux/fd.h> +#include <linux/fs.h> +#include <linux/hdreg.h> +#include <linux/input.h> +#include <linux/ioctl.h> +#include <linux/soundcard.h> +#include <linux/sysctl.h> +#include <linux/utsname.h> +#include <linux/posix_types.h> +#include <net/if_arp.h> +#endif + +#if SANITIZER_IOS +#undef IOC_DIRMASK +#endif + +#if SANITIZER_LINUX +# include <utime.h> +# include <sys/ptrace.h> +# if defined(__mips64) || defined(__aarch64__) || defined(__arm__) || \ + defined(__hexagon__) || SANITIZER_RISCV64 +# include <asm/ptrace.h> +# ifdef __arm__ +typedef struct user_fpregs elf_fpregset_t; +# define ARM_VFPREGS_SIZE_ASAN (32 * 8 /*fpregs*/ + 4 /*fpscr*/) +# if !defined(ARM_VFPREGS_SIZE) +# define ARM_VFPREGS_SIZE ARM_VFPREGS_SIZE_ASAN +# endif +# endif +# endif +# include <semaphore.h> +#endif + +#if !SANITIZER_ANDROID +#include <ifaddrs.h> +#include <sys/ucontext.h> +#include <wordexp.h> +#endif + +#if SANITIZER_LINUX +#if SANITIZER_GLIBC +#include <fstab.h> +#include <net/if_ppp.h> +#include <netax25/ax25.h> +#include <netipx/ipx.h> +#include <netrom/netrom.h> +#include <obstack.h> +#if HAVE_RPC_XDR_H +# error #include <rpc/xdr.h> +#endif +#include <scsi/scsi.h> +#else +#include <linux/if_ppp.h> +#include <linux/kd.h> +#include <linux/ppp_defs.h> +#endif // SANITIZER_GLIBC + +#if SANITIZER_ANDROID +#include <linux/mtio.h> +#else +#include <glob.h> +#include <mqueue.h> +#include <sys/kd.h> +#include <sys/mtio.h> +#include <sys/shm.h> +#include <sys/statvfs.h> +#include <sys/timex.h> +#if defined(__mips64) +# include <sys/procfs.h> +#endif +#include <sys/user.h> +#include <linux/if_eql.h> +#include <linux/if_plip.h> +#include <linux/lp.h> +#include <linux/mroute.h> +#include <linux/mroute6.h> +#include <linux/scc.h> +#include <linux/serial.h> +#include <sys/msg.h> +#include <sys/ipc.h> +#include <crypt.h> +#endif // SANITIZER_ANDROID + +#include <link.h> +#include <sys/vfs.h> +#include <sys/epoll.h> +#include <linux/capability.h> +#else +#include <fstab.h> +#endif // SANITIZER_LINUX + +#if SANITIZER_MAC +#include <net/ethernet.h> +#include <sys/filio.h> +#include <sys/sockio.h> +#endif + +// Include these after system headers to avoid name clashes and ambiguities. +# include "sanitizer_common.h" +# include "sanitizer_internal_defs.h" +# include "sanitizer_platform_limits_posix.h" + +namespace __sanitizer { + unsigned struct_utsname_sz = sizeof(struct utsname); + unsigned struct_stat_sz = sizeof(struct stat); +#if !SANITIZER_IOS && !(SANITIZER_MAC && TARGET_CPU_ARM64) + unsigned struct_stat64_sz = sizeof(struct stat64); +#endif // !SANITIZER_IOS && !(SANITIZER_MAC && TARGET_CPU_ARM64) + unsigned struct_rusage_sz = sizeof(struct rusage); + unsigned struct_tm_sz = sizeof(struct tm); + unsigned struct_passwd_sz = sizeof(struct passwd); + unsigned struct_group_sz = sizeof(struct group); + unsigned siginfo_t_sz = sizeof(siginfo_t); + unsigned struct_sigaction_sz = sizeof(struct sigaction); + unsigned struct_stack_t_sz = sizeof(stack_t); + unsigned struct_itimerval_sz = sizeof(struct itimerval); + unsigned pthread_t_sz = sizeof(pthread_t); + unsigned pthread_mutex_t_sz = sizeof(pthread_mutex_t); + unsigned pthread_cond_t_sz = sizeof(pthread_cond_t); + unsigned pid_t_sz = sizeof(pid_t); + unsigned timeval_sz = sizeof(timeval); + unsigned uid_t_sz = sizeof(uid_t); + unsigned gid_t_sz = sizeof(gid_t); + unsigned mbstate_t_sz = sizeof(mbstate_t); + unsigned sigset_t_sz = sizeof(sigset_t); + unsigned struct_timezone_sz = sizeof(struct timezone); + unsigned struct_tms_sz = sizeof(struct tms); + unsigned struct_sigevent_sz = sizeof(struct sigevent); + unsigned struct_sched_param_sz = sizeof(struct sched_param); + unsigned struct_regex_sz = sizeof(regex_t); + unsigned struct_regmatch_sz = sizeof(regmatch_t); + +#if (SANITIZER_MAC && !TARGET_CPU_ARM64) && !SANITIZER_IOS + unsigned struct_statfs64_sz = sizeof(struct statfs64); +#endif // (SANITIZER_MAC && !TARGET_CPU_ARM64) && !SANITIZER_IOS + +#if SANITIZER_GLIBC || SANITIZER_FREEBSD || SANITIZER_NETBSD || SANITIZER_MAC + unsigned struct_fstab_sz = sizeof(struct fstab); +#endif // SANITIZER_GLIBC || SANITIZER_FREEBSD || SANITIZER_NETBSD || + // SANITIZER_MAC +#if !SANITIZER_ANDROID + unsigned struct_statfs_sz = sizeof(struct statfs); + unsigned struct_sockaddr_sz = sizeof(struct sockaddr); + + unsigned ucontext_t_sz(void *ctx) { +# if SANITIZER_GLIBC && SANITIZER_X64 + // See kernel arch/x86/kernel/fpu/signal.c for details. + const auto *fpregs = static_cast<ucontext_t *>(ctx)->uc_mcontext.fpregs; + // The member names differ across header versions, but the actual layout + // is always the same. So avoid using members, just use arithmetic. + const uint32_t *after_xmm = + reinterpret_cast<const uint32_t *>(fpregs + 1) - 24; + if (after_xmm[12] == FP_XSTATE_MAGIC1) + return reinterpret_cast<const char *>(fpregs) + after_xmm[13] - + static_cast<const char *>(ctx); +# endif + return sizeof(ucontext_t); + } +# endif // !SANITIZER_ANDROID + +# if SANITIZER_LINUX + unsigned struct_epoll_event_sz = sizeof(struct epoll_event); + unsigned struct_sysinfo_sz = sizeof(struct sysinfo); + unsigned __user_cap_header_struct_sz = + sizeof(struct __user_cap_header_struct); + unsigned __user_cap_data_struct_sz = sizeof(struct __user_cap_data_struct); + unsigned struct_new_utsname_sz = sizeof(struct new_utsname); + unsigned struct_old_utsname_sz = sizeof(struct old_utsname); + unsigned struct_oldold_utsname_sz = sizeof(struct oldold_utsname); +#endif // SANITIZER_LINUX + +#if SANITIZER_LINUX + unsigned struct_rlimit_sz = sizeof(struct rlimit); + unsigned struct_timespec_sz = sizeof(struct timespec); + unsigned struct_utimbuf_sz = sizeof(struct utimbuf); + unsigned struct_itimerspec_sz = sizeof(struct itimerspec); +#endif // SANITIZER_LINUX + +#if SANITIZER_LINUX && !SANITIZER_ANDROID + // Use pre-computed size of struct ustat to avoid <sys/ustat.h> which + // has been removed from glibc 2.28. +#if defined(__aarch64__) || defined(__s390x__) || defined(__mips64) || \ + defined(__powerpc64__) || defined(__arch64__) || defined(__sparcv9) || \ + defined(__x86_64__) || SANITIZER_RISCV64 +#define SIZEOF_STRUCT_USTAT 32 +# elif defined(__arm__) || defined(__i386__) || defined(__mips__) || \ + defined(__powerpc__) || defined(__s390__) || defined(__sparc__) || \ + defined(__hexagon__) +# define SIZEOF_STRUCT_USTAT 20 +# else +# error Unknown size of struct ustat +# endif + unsigned struct_ustat_sz = SIZEOF_STRUCT_USTAT; + unsigned struct_rlimit64_sz = sizeof(struct rlimit64); + unsigned struct_statvfs64_sz = sizeof(struct statvfs64); + unsigned struct_crypt_data_sz = sizeof(struct crypt_data); +#endif // SANITIZER_LINUX && !SANITIZER_ANDROID + +#if SANITIZER_LINUX && !SANITIZER_ANDROID + unsigned struct_timex_sz = sizeof(struct timex); + unsigned struct_msqid_ds_sz = sizeof(struct msqid_ds); + unsigned struct_mq_attr_sz = sizeof(struct mq_attr); + unsigned struct_statvfs_sz = sizeof(struct statvfs); +#endif // SANITIZER_LINUX && !SANITIZER_ANDROID + + const uptr sig_ign = (uptr)SIG_IGN; + const uptr sig_dfl = (uptr)SIG_DFL; + const uptr sig_err = (uptr)SIG_ERR; + const uptr sa_siginfo = (uptr)SA_SIGINFO; + +#if SANITIZER_LINUX + int e_tabsz = (int)E_TABSZ; +#endif + + +#if SANITIZER_LINUX && !SANITIZER_ANDROID + unsigned struct_shminfo_sz = sizeof(struct shminfo); + unsigned struct_shm_info_sz = sizeof(struct shm_info); + int shmctl_ipc_stat = (int)IPC_STAT; + int shmctl_ipc_info = (int)IPC_INFO; + int shmctl_shm_info = (int)SHM_INFO; + int shmctl_shm_stat = (int)SHM_STAT; +#endif + +#if !SANITIZER_MAC && !SANITIZER_FREEBSD + unsigned struct_utmp_sz = sizeof(struct utmp); +#endif +#if !SANITIZER_ANDROID + unsigned struct_utmpx_sz = sizeof(struct utmpx); +#endif + + int map_fixed = MAP_FIXED; + + int af_inet = (int)AF_INET; + int af_inet6 = (int)AF_INET6; + + uptr __sanitizer_in_addr_sz(int af) { + if (af == AF_INET) + return sizeof(struct in_addr); + else if (af == AF_INET6) + return sizeof(struct in6_addr); + else + return 0; + } + +#if SANITIZER_LINUX +unsigned struct_ElfW_Phdr_sz = sizeof(ElfW(Phdr)); +#elif SANITIZER_FREEBSD +unsigned struct_ElfW_Phdr_sz = sizeof(Elf_Phdr); +#endif + +#if SANITIZER_GLIBC + int glob_nomatch = GLOB_NOMATCH; + int glob_altdirfunc = GLOB_ALTDIRFUNC; +#endif + +# if !SANITIZER_ANDROID + const int wordexp_wrde_dooffs = WRDE_DOOFFS; +# endif // !SANITIZER_ANDROID + +#if SANITIZER_LINUX && !SANITIZER_ANDROID && \ + (defined(__i386) || defined(__x86_64) || defined(__mips64) || \ + defined(__powerpc64__) || defined(__aarch64__) || defined(__arm__) || \ + defined(__s390__) || SANITIZER_RISCV64) +#if defined(__mips64) || defined(__powerpc64__) || defined(__arm__) + unsigned struct_user_regs_struct_sz = sizeof(struct pt_regs); + unsigned struct_user_fpregs_struct_sz = sizeof(elf_fpregset_t); +#elif SANITIZER_RISCV64 + unsigned struct_user_regs_struct_sz = sizeof(struct user_regs_struct); + unsigned struct_user_fpregs_struct_sz = sizeof(struct __riscv_q_ext_state); +#elif defined(__aarch64__) + unsigned struct_user_regs_struct_sz = sizeof(struct user_pt_regs); + unsigned struct_user_fpregs_struct_sz = sizeof(struct user_fpsimd_state); +#elif defined(__s390__) + unsigned struct_user_regs_struct_sz = sizeof(struct _user_regs_struct); + unsigned struct_user_fpregs_struct_sz = sizeof(struct _user_fpregs_struct); +#else + unsigned struct_user_regs_struct_sz = sizeof(struct user_regs_struct); + unsigned struct_user_fpregs_struct_sz = sizeof(struct user_fpregs_struct); +#endif // __mips64 || __powerpc64__ || __aarch64__ +#if defined(__x86_64) || defined(__mips64) || defined(__powerpc64__) || \ + defined(__aarch64__) || defined(__arm__) || defined(__s390__) || \ + SANITIZER_RISCV64 + unsigned struct_user_fpxregs_struct_sz = 0; +#else + unsigned struct_user_fpxregs_struct_sz = sizeof(struct user_fpxregs_struct); +#endif // __x86_64 || __mips64 || __powerpc64__ || __aarch64__ || __arm__ +// || __s390__ +#ifdef __arm__ + unsigned struct_user_vfpregs_struct_sz = ARM_VFPREGS_SIZE; +#else + unsigned struct_user_vfpregs_struct_sz = 0; +#endif + + int ptrace_peektext = PTRACE_PEEKTEXT; + int ptrace_peekdata = PTRACE_PEEKDATA; + int ptrace_peekuser = PTRACE_PEEKUSER; +#if (defined(PTRACE_GETREGS) && defined(PTRACE_SETREGS)) || \ + (defined(PT_GETREGS) && defined(PT_SETREGS)) + int ptrace_getregs = PTRACE_GETREGS; + int ptrace_setregs = PTRACE_SETREGS; +#else + int ptrace_getregs = -1; + int ptrace_setregs = -1; +#endif +#if (defined(PTRACE_GETFPREGS) && defined(PTRACE_SETFPREGS)) || \ + (defined(PT_GETFPREGS) && defined(PT_SETFPREGS)) + int ptrace_getfpregs = PTRACE_GETFPREGS; + int ptrace_setfpregs = PTRACE_SETFPREGS; +#else + int ptrace_getfpregs = -1; + int ptrace_setfpregs = -1; +#endif +#if (defined(PTRACE_GETFPXREGS) && defined(PTRACE_SETFPXREGS)) || \ + (defined(PT_GETFPXREGS) && defined(PT_SETFPXREGS)) + int ptrace_getfpxregs = PTRACE_GETFPXREGS; + int ptrace_setfpxregs = PTRACE_SETFPXREGS; +#else + int ptrace_getfpxregs = -1; + int ptrace_setfpxregs = -1; +#endif // PTRACE_GETFPXREGS/PTRACE_SETFPXREGS +#if defined(PTRACE_GETVFPREGS) && defined(PTRACE_SETVFPREGS) + int ptrace_getvfpregs = PTRACE_GETVFPREGS; + int ptrace_setvfpregs = PTRACE_SETVFPREGS; +#else + int ptrace_getvfpregs = -1; + int ptrace_setvfpregs = -1; +#endif + int ptrace_geteventmsg = PTRACE_GETEVENTMSG; +#if (defined(PTRACE_GETSIGINFO) && defined(PTRACE_SETSIGINFO)) || \ + (defined(PT_GETSIGINFO) && defined(PT_SETSIGINFO)) + int ptrace_getsiginfo = PTRACE_GETSIGINFO; + int ptrace_setsiginfo = PTRACE_SETSIGINFO; +#else + int ptrace_getsiginfo = -1; + int ptrace_setsiginfo = -1; +#endif // PTRACE_GETSIGINFO/PTRACE_SETSIGINFO +#if defined(PTRACE_GETREGSET) && defined(PTRACE_SETREGSET) + int ptrace_getregset = PTRACE_GETREGSET; + int ptrace_setregset = PTRACE_SETREGSET; +#else + int ptrace_getregset = -1; + int ptrace_setregset = -1; +#endif // PTRACE_GETREGSET/PTRACE_SETREGSET +#endif + + unsigned path_max = PATH_MAX; + + // ioctl arguments + unsigned struct_ifreq_sz = sizeof(struct ifreq); + unsigned struct_termios_sz = sizeof(struct termios); + unsigned struct_winsize_sz = sizeof(struct winsize); + +#if SANITIZER_LINUX + unsigned struct_arpreq_sz = sizeof(struct arpreq); + unsigned struct_cdrom_msf_sz = sizeof(struct cdrom_msf); + unsigned struct_cdrom_multisession_sz = sizeof(struct cdrom_multisession); + unsigned struct_cdrom_read_audio_sz = sizeof(struct cdrom_read_audio); + unsigned struct_cdrom_subchnl_sz = sizeof(struct cdrom_subchnl); + unsigned struct_cdrom_ti_sz = sizeof(struct cdrom_ti); + unsigned struct_cdrom_tocentry_sz = sizeof(struct cdrom_tocentry); + unsigned struct_cdrom_tochdr_sz = sizeof(struct cdrom_tochdr); + unsigned struct_cdrom_volctrl_sz = sizeof(struct cdrom_volctrl); + unsigned struct_ff_effect_sz = sizeof(struct ff_effect); + unsigned struct_floppy_drive_params_sz = sizeof(struct floppy_drive_params); + unsigned struct_floppy_drive_struct_sz = sizeof(struct floppy_drive_struct); + unsigned struct_floppy_fdc_state_sz = sizeof(struct floppy_fdc_state); + unsigned struct_floppy_max_errors_sz = sizeof(struct floppy_max_errors); + unsigned struct_floppy_raw_cmd_sz = sizeof(struct floppy_raw_cmd); + unsigned struct_floppy_struct_sz = sizeof(struct floppy_struct); + unsigned struct_floppy_write_errors_sz = sizeof(struct floppy_write_errors); + unsigned struct_format_descr_sz = sizeof(struct format_descr); + unsigned struct_hd_driveid_sz = sizeof(struct hd_driveid); + unsigned struct_hd_geometry_sz = sizeof(struct hd_geometry); + unsigned struct_input_absinfo_sz = sizeof(struct input_absinfo); + unsigned struct_input_id_sz = sizeof(struct input_id); + unsigned struct_mtpos_sz = sizeof(struct mtpos); + unsigned struct_rtentry_sz = sizeof(struct rtentry); +#if SANITIZER_GLIBC || SANITIZER_ANDROID + unsigned struct_termio_sz = sizeof(struct termio); +#endif + unsigned struct_vt_consize_sz = sizeof(struct vt_consize); + unsigned struct_vt_sizes_sz = sizeof(struct vt_sizes); + unsigned struct_vt_stat_sz = sizeof(struct vt_stat); +#endif // SANITIZER_LINUX + +#if SANITIZER_LINUX +#if SOUND_VERSION >= 0x040000 + unsigned struct_copr_buffer_sz = 0; + unsigned struct_copr_debug_buf_sz = 0; + unsigned struct_copr_msg_sz = 0; +#else + unsigned struct_copr_buffer_sz = sizeof(struct copr_buffer); + unsigned struct_copr_debug_buf_sz = sizeof(struct copr_debug_buf); + unsigned struct_copr_msg_sz = sizeof(struct copr_msg); +#endif + unsigned struct_midi_info_sz = sizeof(struct midi_info); + unsigned struct_mtget_sz = sizeof(struct mtget); + unsigned struct_mtop_sz = sizeof(struct mtop); + unsigned struct_sbi_instrument_sz = sizeof(struct sbi_instrument); + unsigned struct_seq_event_rec_sz = sizeof(struct seq_event_rec); + unsigned struct_synth_info_sz = sizeof(struct synth_info); + unsigned struct_vt_mode_sz = sizeof(struct vt_mode); +#endif // SANITIZER_LINUX + +#if SANITIZER_GLIBC + unsigned struct_ax25_parms_struct_sz = sizeof(struct ax25_parms_struct); +#if EV_VERSION > (0x010000) + unsigned struct_input_keymap_entry_sz = sizeof(struct input_keymap_entry); +#else + unsigned struct_input_keymap_entry_sz = 0; +#endif + unsigned struct_ipx_config_data_sz = sizeof(struct ipx_config_data); + unsigned struct_kbdiacrs_sz = sizeof(struct kbdiacrs); + unsigned struct_kbentry_sz = sizeof(struct kbentry); + unsigned struct_kbkeycode_sz = sizeof(struct kbkeycode); + unsigned struct_kbsentry_sz = sizeof(struct kbsentry); + unsigned struct_mtconfiginfo_sz = sizeof(struct mtconfiginfo); + unsigned struct_nr_parms_struct_sz = sizeof(struct nr_parms_struct); + unsigned struct_scc_modem_sz = sizeof(struct scc_modem); + unsigned struct_scc_stat_sz = sizeof(struct scc_stat); + unsigned struct_serial_multiport_struct_sz + = sizeof(struct serial_multiport_struct); + unsigned struct_serial_struct_sz = sizeof(struct serial_struct); + unsigned struct_sockaddr_ax25_sz = sizeof(struct sockaddr_ax25); + unsigned struct_unimapdesc_sz = sizeof(struct unimapdesc); + unsigned struct_unimapinit_sz = sizeof(struct unimapinit); + + unsigned struct_audio_buf_info_sz = sizeof(struct audio_buf_info); + unsigned struct_ppp_stats_sz = sizeof(struct ppp_stats); +#endif // SANITIZER_GLIBC + +#if !SANITIZER_ANDROID && !SANITIZER_MAC + unsigned struct_sioc_sg_req_sz = sizeof(struct sioc_sg_req); + unsigned struct_sioc_vif_req_sz = sizeof(struct sioc_vif_req); +#endif + + const unsigned long __sanitizer_bufsiz = BUFSIZ; + + const unsigned IOCTL_NOT_PRESENT = 0; + + unsigned IOCTL_FIOASYNC = FIOASYNC; + unsigned IOCTL_FIOCLEX = FIOCLEX; + unsigned IOCTL_FIOGETOWN = FIOGETOWN; + unsigned IOCTL_FIONBIO = FIONBIO; + unsigned IOCTL_FIONCLEX = FIONCLEX; + unsigned IOCTL_FIOSETOWN = FIOSETOWN; + unsigned IOCTL_SIOCADDMULTI = SIOCADDMULTI; + unsigned IOCTL_SIOCATMARK = SIOCATMARK; + unsigned IOCTL_SIOCDELMULTI = SIOCDELMULTI; + unsigned IOCTL_SIOCGIFADDR = SIOCGIFADDR; + unsigned IOCTL_SIOCGIFBRDADDR = SIOCGIFBRDADDR; + unsigned IOCTL_SIOCGIFCONF = SIOCGIFCONF; + unsigned IOCTL_SIOCGIFDSTADDR = SIOCGIFDSTADDR; + unsigned IOCTL_SIOCGIFFLAGS = SIOCGIFFLAGS; + unsigned IOCTL_SIOCGIFMETRIC = SIOCGIFMETRIC; + unsigned IOCTL_SIOCGIFMTU = SIOCGIFMTU; + unsigned IOCTL_SIOCGIFNETMASK = SIOCGIFNETMASK; + unsigned IOCTL_SIOCGPGRP = SIOCGPGRP; + unsigned IOCTL_SIOCSIFADDR = SIOCSIFADDR; + unsigned IOCTL_SIOCSIFBRDADDR = SIOCSIFBRDADDR; + unsigned IOCTL_SIOCSIFDSTADDR = SIOCSIFDSTADDR; + unsigned IOCTL_SIOCSIFFLAGS = SIOCSIFFLAGS; + unsigned IOCTL_SIOCSIFMETRIC = SIOCSIFMETRIC; + unsigned IOCTL_SIOCSIFMTU = SIOCSIFMTU; + unsigned IOCTL_SIOCSIFNETMASK = SIOCSIFNETMASK; + unsigned IOCTL_SIOCSPGRP = SIOCSPGRP; + unsigned IOCTL_TIOCCONS = TIOCCONS; + unsigned IOCTL_TIOCEXCL = TIOCEXCL; + unsigned IOCTL_TIOCGETD = TIOCGETD; + unsigned IOCTL_TIOCGPGRP = TIOCGPGRP; + unsigned IOCTL_TIOCGWINSZ = TIOCGWINSZ; + unsigned IOCTL_TIOCMBIC = TIOCMBIC; + unsigned IOCTL_TIOCMBIS = TIOCMBIS; + unsigned IOCTL_TIOCMGET = TIOCMGET; + unsigned IOCTL_TIOCMSET = TIOCMSET; + unsigned IOCTL_TIOCNOTTY = TIOCNOTTY; + unsigned IOCTL_TIOCNXCL = TIOCNXCL; + unsigned IOCTL_TIOCOUTQ = TIOCOUTQ; + unsigned IOCTL_TIOCPKT = TIOCPKT; + unsigned IOCTL_TIOCSCTTY = TIOCSCTTY; + unsigned IOCTL_TIOCSETD = TIOCSETD; + unsigned IOCTL_TIOCSPGRP = TIOCSPGRP; + unsigned IOCTL_TIOCSTI = TIOCSTI; + unsigned IOCTL_TIOCSWINSZ = TIOCSWINSZ; +#if SANITIZER_LINUX && !SANITIZER_ANDROID + unsigned IOCTL_SIOCGETSGCNT = SIOCGETSGCNT; + unsigned IOCTL_SIOCGETVIFCNT = SIOCGETVIFCNT; +#endif + +#if SANITIZER_LINUX + unsigned IOCTL_EVIOCGABS = EVIOCGABS(0); + unsigned IOCTL_EVIOCGBIT = EVIOCGBIT(0, 0); + unsigned IOCTL_EVIOCGEFFECTS = EVIOCGEFFECTS; + unsigned IOCTL_EVIOCGID = EVIOCGID; + unsigned IOCTL_EVIOCGKEY = EVIOCGKEY(0); + unsigned IOCTL_EVIOCGKEYCODE = EVIOCGKEYCODE; + unsigned IOCTL_EVIOCGLED = EVIOCGLED(0); + unsigned IOCTL_EVIOCGNAME = EVIOCGNAME(0); + unsigned IOCTL_EVIOCGPHYS = EVIOCGPHYS(0); + unsigned IOCTL_EVIOCGRAB = EVIOCGRAB; + unsigned IOCTL_EVIOCGREP = EVIOCGREP; + unsigned IOCTL_EVIOCGSND = EVIOCGSND(0); + unsigned IOCTL_EVIOCGSW = EVIOCGSW(0); + unsigned IOCTL_EVIOCGUNIQ = EVIOCGUNIQ(0); + unsigned IOCTL_EVIOCGVERSION = EVIOCGVERSION; + unsigned IOCTL_EVIOCRMFF = EVIOCRMFF; + unsigned IOCTL_EVIOCSABS = EVIOCSABS(0); + unsigned IOCTL_EVIOCSFF = EVIOCSFF; + unsigned IOCTL_EVIOCSKEYCODE = EVIOCSKEYCODE; + unsigned IOCTL_EVIOCSREP = EVIOCSREP; + unsigned IOCTL_BLKFLSBUF = BLKFLSBUF; + unsigned IOCTL_BLKGETSIZE = BLKGETSIZE; + unsigned IOCTL_BLKRAGET = BLKRAGET; + unsigned IOCTL_BLKRASET = BLKRASET; + unsigned IOCTL_BLKROGET = BLKROGET; + unsigned IOCTL_BLKROSET = BLKROSET; + unsigned IOCTL_BLKRRPART = BLKRRPART; + unsigned IOCTL_CDROMAUDIOBUFSIZ = CDROMAUDIOBUFSIZ; + unsigned IOCTL_CDROMEJECT = CDROMEJECT; + unsigned IOCTL_CDROMEJECT_SW = CDROMEJECT_SW; + unsigned IOCTL_CDROMMULTISESSION = CDROMMULTISESSION; + unsigned IOCTL_CDROMPAUSE = CDROMPAUSE; + unsigned IOCTL_CDROMPLAYMSF = CDROMPLAYMSF; + unsigned IOCTL_CDROMPLAYTRKIND = CDROMPLAYTRKIND; + unsigned IOCTL_CDROMREADAUDIO = CDROMREADAUDIO; + unsigned IOCTL_CDROMREADCOOKED = CDROMREADCOOKED; + unsigned IOCTL_CDROMREADMODE1 = CDROMREADMODE1; + unsigned IOCTL_CDROMREADMODE2 = CDROMREADMODE2; + unsigned IOCTL_CDROMREADRAW = CDROMREADRAW; + unsigned IOCTL_CDROMREADTOCENTRY = CDROMREADTOCENTRY; + unsigned IOCTL_CDROMREADTOCHDR = CDROMREADTOCHDR; + unsigned IOCTL_CDROMRESET = CDROMRESET; + unsigned IOCTL_CDROMRESUME = CDROMRESUME; + unsigned IOCTL_CDROMSEEK = CDROMSEEK; + unsigned IOCTL_CDROMSTART = CDROMSTART; + unsigned IOCTL_CDROMSTOP = CDROMSTOP; + unsigned IOCTL_CDROMSUBCHNL = CDROMSUBCHNL; + unsigned IOCTL_CDROMVOLCTRL = CDROMVOLCTRL; + unsigned IOCTL_CDROMVOLREAD = CDROMVOLREAD; + unsigned IOCTL_CDROM_GET_UPC = CDROM_GET_UPC; + unsigned IOCTL_FDCLRPRM = FDCLRPRM; + unsigned IOCTL_FDDEFPRM = FDDEFPRM; + unsigned IOCTL_FDFLUSH = FDFLUSH; + unsigned IOCTL_FDFMTBEG = FDFMTBEG; + unsigned IOCTL_FDFMTEND = FDFMTEND; + unsigned IOCTL_FDFMTTRK = FDFMTTRK; + unsigned IOCTL_FDGETDRVPRM = FDGETDRVPRM; + unsigned IOCTL_FDGETDRVSTAT = FDGETDRVSTAT; + unsigned IOCTL_FDGETDRVTYP = FDGETDRVTYP; + unsigned IOCTL_FDGETFDCSTAT = FDGETFDCSTAT; + unsigned IOCTL_FDGETMAXERRS = FDGETMAXERRS; + unsigned IOCTL_FDGETPRM = FDGETPRM; + unsigned IOCTL_FDMSGOFF = FDMSGOFF; + unsigned IOCTL_FDMSGON = FDMSGON; + unsigned IOCTL_FDPOLLDRVSTAT = FDPOLLDRVSTAT; + unsigned IOCTL_FDRAWCMD = FDRAWCMD; + unsigned IOCTL_FDRESET = FDRESET; + unsigned IOCTL_FDSETDRVPRM = FDSETDRVPRM; + unsigned IOCTL_FDSETEMSGTRESH = FDSETEMSGTRESH; + unsigned IOCTL_FDSETMAXERRS = FDSETMAXERRS; + unsigned IOCTL_FDSETPRM = FDSETPRM; + unsigned IOCTL_FDTWADDLE = FDTWADDLE; + unsigned IOCTL_FDWERRORCLR = FDWERRORCLR; + unsigned IOCTL_FDWERRORGET = FDWERRORGET; + unsigned IOCTL_HDIO_DRIVE_CMD = HDIO_DRIVE_CMD; + unsigned IOCTL_HDIO_GETGEO = HDIO_GETGEO; + unsigned IOCTL_HDIO_GET_32BIT = HDIO_GET_32BIT; + unsigned IOCTL_HDIO_GET_DMA = HDIO_GET_DMA; + unsigned IOCTL_HDIO_GET_IDENTITY = HDIO_GET_IDENTITY; + unsigned IOCTL_HDIO_GET_KEEPSETTINGS = HDIO_GET_KEEPSETTINGS; + unsigned IOCTL_HDIO_GET_MULTCOUNT = HDIO_GET_MULTCOUNT; + unsigned IOCTL_HDIO_GET_NOWERR = HDIO_GET_NOWERR; + unsigned IOCTL_HDIO_GET_UNMASKINTR = HDIO_GET_UNMASKINTR; + unsigned IOCTL_HDIO_SET_32BIT = HDIO_SET_32BIT; + unsigned IOCTL_HDIO_SET_DMA = HDIO_SET_DMA; + unsigned IOCTL_HDIO_SET_KEEPSETTINGS = HDIO_SET_KEEPSETTINGS; + unsigned IOCTL_HDIO_SET_MULTCOUNT = HDIO_SET_MULTCOUNT; + unsigned IOCTL_HDIO_SET_NOWERR = HDIO_SET_NOWERR; + unsigned IOCTL_HDIO_SET_UNMASKINTR = HDIO_SET_UNMASKINTR; + unsigned IOCTL_MTIOCPOS = MTIOCPOS; + unsigned IOCTL_PPPIOCGASYNCMAP = PPPIOCGASYNCMAP; + unsigned IOCTL_PPPIOCGDEBUG = PPPIOCGDEBUG; + unsigned IOCTL_PPPIOCGFLAGS = PPPIOCGFLAGS; + unsigned IOCTL_PPPIOCGUNIT = PPPIOCGUNIT; + unsigned IOCTL_PPPIOCGXASYNCMAP = PPPIOCGXASYNCMAP; + unsigned IOCTL_PPPIOCSASYNCMAP = PPPIOCSASYNCMAP; + unsigned IOCTL_PPPIOCSDEBUG = PPPIOCSDEBUG; + unsigned IOCTL_PPPIOCSFLAGS = PPPIOCSFLAGS; + unsigned IOCTL_PPPIOCSMAXCID = PPPIOCSMAXCID; + unsigned IOCTL_PPPIOCSMRU = PPPIOCSMRU; + unsigned IOCTL_PPPIOCSXASYNCMAP = PPPIOCSXASYNCMAP; + unsigned IOCTL_SIOCADDRT = SIOCADDRT; + unsigned IOCTL_SIOCDARP = SIOCDARP; + unsigned IOCTL_SIOCDELRT = SIOCDELRT; + unsigned IOCTL_SIOCDRARP = SIOCDRARP; + unsigned IOCTL_SIOCGARP = SIOCGARP; + unsigned IOCTL_SIOCGIFENCAP = SIOCGIFENCAP; + unsigned IOCTL_SIOCGIFHWADDR = SIOCGIFHWADDR; + unsigned IOCTL_SIOCGIFMAP = SIOCGIFMAP; + unsigned IOCTL_SIOCGIFMEM = SIOCGIFMEM; + unsigned IOCTL_SIOCGIFNAME = SIOCGIFNAME; + unsigned IOCTL_SIOCGIFSLAVE = SIOCGIFSLAVE; + unsigned IOCTL_SIOCGRARP = SIOCGRARP; + unsigned IOCTL_SIOCGSTAMP = SIOCGSTAMP; + unsigned IOCTL_SIOCSARP = SIOCSARP; + unsigned IOCTL_SIOCSIFENCAP = SIOCSIFENCAP; + unsigned IOCTL_SIOCSIFHWADDR = SIOCSIFHWADDR; + unsigned IOCTL_SIOCSIFLINK = SIOCSIFLINK; + unsigned IOCTL_SIOCSIFMAP = SIOCSIFMAP; + unsigned IOCTL_SIOCSIFMEM = SIOCSIFMEM; + unsigned IOCTL_SIOCSIFSLAVE = SIOCSIFSLAVE; + unsigned IOCTL_SIOCSRARP = SIOCSRARP; +# if SOUND_VERSION >= 0x040000 + unsigned IOCTL_SNDCTL_COPR_HALT = IOCTL_NOT_PRESENT; + unsigned IOCTL_SNDCTL_COPR_LOAD = IOCTL_NOT_PRESENT; + unsigned IOCTL_SNDCTL_COPR_RCODE = IOCTL_NOT_PRESENT; + unsigned IOCTL_SNDCTL_COPR_RCVMSG = IOCTL_NOT_PRESENT; + unsigned IOCTL_SNDCTL_COPR_RDATA = IOCTL_NOT_PRESENT; + unsigned IOCTL_SNDCTL_COPR_RESET = IOCTL_NOT_PRESENT; + unsigned IOCTL_SNDCTL_COPR_RUN = IOCTL_NOT_PRESENT; + unsigned IOCTL_SNDCTL_COPR_SENDMSG = IOCTL_NOT_PRESENT; + unsigned IOCTL_SNDCTL_COPR_WCODE = IOCTL_NOT_PRESENT; + unsigned IOCTL_SNDCTL_COPR_WDATA = IOCTL_NOT_PRESENT; + unsigned IOCTL_SOUND_PCM_READ_BITS = IOCTL_NOT_PRESENT; + unsigned IOCTL_SOUND_PCM_READ_CHANNELS = IOCTL_NOT_PRESENT; + unsigned IOCTL_SOUND_PCM_READ_FILTER = IOCTL_NOT_PRESENT; + unsigned IOCTL_SOUND_PCM_READ_RATE = IOCTL_NOT_PRESENT; + unsigned IOCTL_SOUND_PCM_WRITE_CHANNELS = IOCTL_NOT_PRESENT; + unsigned IOCTL_SOUND_PCM_WRITE_FILTER = IOCTL_NOT_PRESENT; +# else // SOUND_VERSION + unsigned IOCTL_SNDCTL_COPR_HALT = SNDCTL_COPR_HALT; + unsigned IOCTL_SNDCTL_COPR_LOAD = SNDCTL_COPR_LOAD; + unsigned IOCTL_SNDCTL_COPR_RCODE = SNDCTL_COPR_RCODE; + unsigned IOCTL_SNDCTL_COPR_RCVMSG = SNDCTL_COPR_RCVMSG; + unsigned IOCTL_SNDCTL_COPR_RDATA = SNDCTL_COPR_RDATA; + unsigned IOCTL_SNDCTL_COPR_RESET = SNDCTL_COPR_RESET; + unsigned IOCTL_SNDCTL_COPR_RUN = SNDCTL_COPR_RUN; + unsigned IOCTL_SNDCTL_COPR_SENDMSG = SNDCTL_COPR_SENDMSG; + unsigned IOCTL_SNDCTL_COPR_WCODE = SNDCTL_COPR_WCODE; + unsigned IOCTL_SNDCTL_COPR_WDATA = SNDCTL_COPR_WDATA; + unsigned IOCTL_SOUND_PCM_READ_BITS = SOUND_PCM_READ_BITS; + unsigned IOCTL_SOUND_PCM_READ_CHANNELS = SOUND_PCM_READ_CHANNELS; + unsigned IOCTL_SOUND_PCM_READ_FILTER = SOUND_PCM_READ_FILTER; + unsigned IOCTL_SOUND_PCM_READ_RATE = SOUND_PCM_READ_RATE; + unsigned IOCTL_SOUND_PCM_WRITE_CHANNELS = SOUND_PCM_WRITE_CHANNELS; + unsigned IOCTL_SOUND_PCM_WRITE_FILTER = SOUND_PCM_WRITE_FILTER; +#endif // SOUND_VERSION + unsigned IOCTL_TCFLSH = TCFLSH; + unsigned IOCTL_TCGETA = TCGETA; + unsigned IOCTL_TCGETS = TCGETS; + unsigned IOCTL_TCSBRK = TCSBRK; + unsigned IOCTL_TCSBRKP = TCSBRKP; + unsigned IOCTL_TCSETA = TCSETA; + unsigned IOCTL_TCSETAF = TCSETAF; + unsigned IOCTL_TCSETAW = TCSETAW; + unsigned IOCTL_TCSETS = TCSETS; + unsigned IOCTL_TCSETSF = TCSETSF; + unsigned IOCTL_TCSETSW = TCSETSW; + unsigned IOCTL_TCXONC = TCXONC; + unsigned IOCTL_TIOCGLCKTRMIOS = TIOCGLCKTRMIOS; + unsigned IOCTL_TIOCGSOFTCAR = TIOCGSOFTCAR; + unsigned IOCTL_TIOCINQ = TIOCINQ; + unsigned IOCTL_TIOCLINUX = TIOCLINUX; + unsigned IOCTL_TIOCSERCONFIG = TIOCSERCONFIG; + unsigned IOCTL_TIOCSERGETLSR = TIOCSERGETLSR; + unsigned IOCTL_TIOCSERGWILD = TIOCSERGWILD; + unsigned IOCTL_TIOCSERSWILD = TIOCSERSWILD; + unsigned IOCTL_TIOCSLCKTRMIOS = TIOCSLCKTRMIOS; + unsigned IOCTL_TIOCSSOFTCAR = TIOCSSOFTCAR; + unsigned IOCTL_VT_DISALLOCATE = VT_DISALLOCATE; + unsigned IOCTL_VT_GETSTATE = VT_GETSTATE; + unsigned IOCTL_VT_RESIZE = VT_RESIZE; + unsigned IOCTL_VT_RESIZEX = VT_RESIZEX; + unsigned IOCTL_VT_SENDSIG = VT_SENDSIG; + unsigned IOCTL_MTIOCGET = MTIOCGET; + unsigned IOCTL_MTIOCTOP = MTIOCTOP; + unsigned IOCTL_SNDCTL_DSP_GETBLKSIZE = SNDCTL_DSP_GETBLKSIZE; + unsigned IOCTL_SNDCTL_DSP_GETFMTS = SNDCTL_DSP_GETFMTS; + unsigned IOCTL_SNDCTL_DSP_NONBLOCK = SNDCTL_DSP_NONBLOCK; + unsigned IOCTL_SNDCTL_DSP_POST = SNDCTL_DSP_POST; + unsigned IOCTL_SNDCTL_DSP_RESET = SNDCTL_DSP_RESET; + unsigned IOCTL_SNDCTL_DSP_SETFMT = SNDCTL_DSP_SETFMT; + unsigned IOCTL_SNDCTL_DSP_SETFRAGMENT = SNDCTL_DSP_SETFRAGMENT; + unsigned IOCTL_SNDCTL_DSP_SPEED = SNDCTL_DSP_SPEED; + unsigned IOCTL_SNDCTL_DSP_STEREO = SNDCTL_DSP_STEREO; + unsigned IOCTL_SNDCTL_DSP_SUBDIVIDE = SNDCTL_DSP_SUBDIVIDE; + unsigned IOCTL_SNDCTL_DSP_SYNC = SNDCTL_DSP_SYNC; + unsigned IOCTL_SNDCTL_FM_4OP_ENABLE = SNDCTL_FM_4OP_ENABLE; + unsigned IOCTL_SNDCTL_FM_LOAD_INSTR = SNDCTL_FM_LOAD_INSTR; + unsigned IOCTL_SNDCTL_MIDI_INFO = SNDCTL_MIDI_INFO; + unsigned IOCTL_SNDCTL_MIDI_PRETIME = SNDCTL_MIDI_PRETIME; + unsigned IOCTL_SNDCTL_SEQ_CTRLRATE = SNDCTL_SEQ_CTRLRATE; + unsigned IOCTL_SNDCTL_SEQ_GETINCOUNT = SNDCTL_SEQ_GETINCOUNT; + unsigned IOCTL_SNDCTL_SEQ_GETOUTCOUNT = SNDCTL_SEQ_GETOUTCOUNT; + unsigned IOCTL_SNDCTL_SEQ_NRMIDIS = SNDCTL_SEQ_NRMIDIS; + unsigned IOCTL_SNDCTL_SEQ_NRSYNTHS = SNDCTL_SEQ_NRSYNTHS; + unsigned IOCTL_SNDCTL_SEQ_OUTOFBAND = SNDCTL_SEQ_OUTOFBAND; + unsigned IOCTL_SNDCTL_SEQ_PANIC = SNDCTL_SEQ_PANIC; + unsigned IOCTL_SNDCTL_SEQ_PERCMODE = SNDCTL_SEQ_PERCMODE; + unsigned IOCTL_SNDCTL_SEQ_RESET = SNDCTL_SEQ_RESET; + unsigned IOCTL_SNDCTL_SEQ_RESETSAMPLES = SNDCTL_SEQ_RESETSAMPLES; + unsigned IOCTL_SNDCTL_SEQ_SYNC = SNDCTL_SEQ_SYNC; + unsigned IOCTL_SNDCTL_SEQ_TESTMIDI = SNDCTL_SEQ_TESTMIDI; + unsigned IOCTL_SNDCTL_SEQ_THRESHOLD = SNDCTL_SEQ_THRESHOLD; + unsigned IOCTL_SNDCTL_SYNTH_INFO = SNDCTL_SYNTH_INFO; + unsigned IOCTL_SNDCTL_SYNTH_MEMAVL = SNDCTL_SYNTH_MEMAVL; + unsigned IOCTL_SNDCTL_TMR_CONTINUE = SNDCTL_TMR_CONTINUE; + unsigned IOCTL_SNDCTL_TMR_METRONOME = SNDCTL_TMR_METRONOME; + unsigned IOCTL_SNDCTL_TMR_SELECT = SNDCTL_TMR_SELECT; + unsigned IOCTL_SNDCTL_TMR_SOURCE = SNDCTL_TMR_SOURCE; + unsigned IOCTL_SNDCTL_TMR_START = SNDCTL_TMR_START; + unsigned IOCTL_SNDCTL_TMR_STOP = SNDCTL_TMR_STOP; + unsigned IOCTL_SNDCTL_TMR_TEMPO = SNDCTL_TMR_TEMPO; + unsigned IOCTL_SNDCTL_TMR_TIMEBASE = SNDCTL_TMR_TIMEBASE; + unsigned IOCTL_SOUND_MIXER_READ_ALTPCM = SOUND_MIXER_READ_ALTPCM; + unsigned IOCTL_SOUND_MIXER_READ_BASS = SOUND_MIXER_READ_BASS; + unsigned IOCTL_SOUND_MIXER_READ_CAPS = SOUND_MIXER_READ_CAPS; + unsigned IOCTL_SOUND_MIXER_READ_CD = SOUND_MIXER_READ_CD; + unsigned IOCTL_SOUND_MIXER_READ_DEVMASK = SOUND_MIXER_READ_DEVMASK; + unsigned IOCTL_SOUND_MIXER_READ_ENHANCE = SOUND_MIXER_READ_ENHANCE; + unsigned IOCTL_SOUND_MIXER_READ_IGAIN = SOUND_MIXER_READ_IGAIN; + unsigned IOCTL_SOUND_MIXER_READ_IMIX = SOUND_MIXER_READ_IMIX; + unsigned IOCTL_SOUND_MIXER_READ_LINE = SOUND_MIXER_READ_LINE; + unsigned IOCTL_SOUND_MIXER_READ_LINE1 = SOUND_MIXER_READ_LINE1; + unsigned IOCTL_SOUND_MIXER_READ_LINE2 = SOUND_MIXER_READ_LINE2; + unsigned IOCTL_SOUND_MIXER_READ_LINE3 = SOUND_MIXER_READ_LINE3; + unsigned IOCTL_SOUND_MIXER_READ_LOUD = SOUND_MIXER_READ_LOUD; + unsigned IOCTL_SOUND_MIXER_READ_MIC = SOUND_MIXER_READ_MIC; + unsigned IOCTL_SOUND_MIXER_READ_MUTE = SOUND_MIXER_READ_MUTE; + unsigned IOCTL_SOUND_MIXER_READ_OGAIN = SOUND_MIXER_READ_OGAIN; + unsigned IOCTL_SOUND_MIXER_READ_PCM = SOUND_MIXER_READ_PCM; + unsigned IOCTL_SOUND_MIXER_READ_RECLEV = SOUND_MIXER_READ_RECLEV; + unsigned IOCTL_SOUND_MIXER_READ_RECMASK = SOUND_MIXER_READ_RECMASK; + unsigned IOCTL_SOUND_MIXER_READ_RECSRC = SOUND_MIXER_READ_RECSRC; + unsigned IOCTL_SOUND_MIXER_READ_SPEAKER = SOUND_MIXER_READ_SPEAKER; + unsigned IOCTL_SOUND_MIXER_READ_STEREODEVS = SOUND_MIXER_READ_STEREODEVS; + unsigned IOCTL_SOUND_MIXER_READ_SYNTH = SOUND_MIXER_READ_SYNTH; + unsigned IOCTL_SOUND_MIXER_READ_TREBLE = SOUND_MIXER_READ_TREBLE; + unsigned IOCTL_SOUND_MIXER_READ_VOLUME = SOUND_MIXER_READ_VOLUME; + unsigned IOCTL_SOUND_MIXER_WRITE_ALTPCM = SOUND_MIXER_WRITE_ALTPCM; + unsigned IOCTL_SOUND_MIXER_WRITE_BASS = SOUND_MIXER_WRITE_BASS; + unsigned IOCTL_SOUND_MIXER_WRITE_CD = SOUND_MIXER_WRITE_CD; + unsigned IOCTL_SOUND_MIXER_WRITE_ENHANCE = SOUND_MIXER_WRITE_ENHANCE; + unsigned IOCTL_SOUND_MIXER_WRITE_IGAIN = SOUND_MIXER_WRITE_IGAIN; + unsigned IOCTL_SOUND_MIXER_WRITE_IMIX = SOUND_MIXER_WRITE_IMIX; + unsigned IOCTL_SOUND_MIXER_WRITE_LINE = SOUND_MIXER_WRITE_LINE; + unsigned IOCTL_SOUND_MIXER_WRITE_LINE1 = SOUND_MIXER_WRITE_LINE1; + unsigned IOCTL_SOUND_MIXER_WRITE_LINE2 = SOUND_MIXER_WRITE_LINE2; + unsigned IOCTL_SOUND_MIXER_WRITE_LINE3 = SOUND_MIXER_WRITE_LINE3; + unsigned IOCTL_SOUND_MIXER_WRITE_LOUD = SOUND_MIXER_WRITE_LOUD; + unsigned IOCTL_SOUND_MIXER_WRITE_MIC = SOUND_MIXER_WRITE_MIC; + unsigned IOCTL_SOUND_MIXER_WRITE_MUTE = SOUND_MIXER_WRITE_MUTE; + unsigned IOCTL_SOUND_MIXER_WRITE_OGAIN = SOUND_MIXER_WRITE_OGAIN; + unsigned IOCTL_SOUND_MIXER_WRITE_PCM = SOUND_MIXER_WRITE_PCM; + unsigned IOCTL_SOUND_MIXER_WRITE_RECLEV = SOUND_MIXER_WRITE_RECLEV; + unsigned IOCTL_SOUND_MIXER_WRITE_RECSRC = SOUND_MIXER_WRITE_RECSRC; + unsigned IOCTL_SOUND_MIXER_WRITE_SPEAKER = SOUND_MIXER_WRITE_SPEAKER; + unsigned IOCTL_SOUND_MIXER_WRITE_SYNTH = SOUND_MIXER_WRITE_SYNTH; + unsigned IOCTL_SOUND_MIXER_WRITE_TREBLE = SOUND_MIXER_WRITE_TREBLE; + unsigned IOCTL_SOUND_MIXER_WRITE_VOLUME = SOUND_MIXER_WRITE_VOLUME; + unsigned IOCTL_VT_ACTIVATE = VT_ACTIVATE; + unsigned IOCTL_VT_GETMODE = VT_GETMODE; + unsigned IOCTL_VT_OPENQRY = VT_OPENQRY; + unsigned IOCTL_VT_RELDISP = VT_RELDISP; + unsigned IOCTL_VT_SETMODE = VT_SETMODE; + unsigned IOCTL_VT_WAITACTIVE = VT_WAITACTIVE; +#endif // SANITIZER_LINUX + +#if SANITIZER_LINUX && !SANITIZER_ANDROID + unsigned IOCTL_EQL_EMANCIPATE = EQL_EMANCIPATE; + unsigned IOCTL_EQL_ENSLAVE = EQL_ENSLAVE; + unsigned IOCTL_EQL_GETMASTRCFG = EQL_GETMASTRCFG; + unsigned IOCTL_EQL_GETSLAVECFG = EQL_GETSLAVECFG; + unsigned IOCTL_EQL_SETMASTRCFG = EQL_SETMASTRCFG; + unsigned IOCTL_EQL_SETSLAVECFG = EQL_SETSLAVECFG; +#if EV_VERSION > (0x010000) + unsigned IOCTL_EVIOCGKEYCODE_V2 = EVIOCGKEYCODE_V2; + unsigned IOCTL_EVIOCGPROP = EVIOCGPROP(0); + unsigned IOCTL_EVIOCSKEYCODE_V2 = EVIOCSKEYCODE_V2; +#else + unsigned IOCTL_EVIOCGKEYCODE_V2 = IOCTL_NOT_PRESENT; + unsigned IOCTL_EVIOCGPROP = IOCTL_NOT_PRESENT; + unsigned IOCTL_EVIOCSKEYCODE_V2 = IOCTL_NOT_PRESENT; +#endif + unsigned IOCTL_FS_IOC_GETFLAGS = FS_IOC_GETFLAGS; + unsigned IOCTL_FS_IOC_GETVERSION = FS_IOC_GETVERSION; + unsigned IOCTL_FS_IOC_SETFLAGS = FS_IOC_SETFLAGS; + unsigned IOCTL_FS_IOC_SETVERSION = FS_IOC_SETVERSION; + unsigned IOCTL_GIO_CMAP = GIO_CMAP; + unsigned IOCTL_GIO_FONT = GIO_FONT; + unsigned IOCTL_GIO_UNIMAP = GIO_UNIMAP; + unsigned IOCTL_GIO_UNISCRNMAP = GIO_UNISCRNMAP; + unsigned IOCTL_KDADDIO = KDADDIO; + unsigned IOCTL_KDDELIO = KDDELIO; + unsigned IOCTL_KDGETKEYCODE = KDGETKEYCODE; + unsigned IOCTL_KDGKBDIACR = KDGKBDIACR; + unsigned IOCTL_KDGKBENT = KDGKBENT; + unsigned IOCTL_KDGKBLED = KDGKBLED; + unsigned IOCTL_KDGKBMETA = KDGKBMETA; + unsigned IOCTL_KDGKBSENT = KDGKBSENT; + unsigned IOCTL_KDMAPDISP = KDMAPDISP; + unsigned IOCTL_KDSETKEYCODE = KDSETKEYCODE; + unsigned IOCTL_KDSIGACCEPT = KDSIGACCEPT; + unsigned IOCTL_KDSKBDIACR = KDSKBDIACR; + unsigned IOCTL_KDSKBENT = KDSKBENT; + unsigned IOCTL_KDSKBLED = KDSKBLED; + unsigned IOCTL_KDSKBMETA = KDSKBMETA; + unsigned IOCTL_KDSKBSENT = KDSKBSENT; + unsigned IOCTL_KDUNMAPDISP = KDUNMAPDISP; + unsigned IOCTL_LPABORT = LPABORT; + unsigned IOCTL_LPABORTOPEN = LPABORTOPEN; + unsigned IOCTL_LPCAREFUL = LPCAREFUL; + unsigned IOCTL_LPCHAR = LPCHAR; + unsigned IOCTL_LPGETIRQ = LPGETIRQ; + unsigned IOCTL_LPGETSTATUS = LPGETSTATUS; + unsigned IOCTL_LPRESET = LPRESET; + unsigned IOCTL_LPSETIRQ = LPSETIRQ; + unsigned IOCTL_LPTIME = LPTIME; + unsigned IOCTL_LPWAIT = LPWAIT; + unsigned IOCTL_MTIOCGETCONFIG = MTIOCGETCONFIG; + unsigned IOCTL_MTIOCSETCONFIG = MTIOCSETCONFIG; + unsigned IOCTL_PIO_CMAP = PIO_CMAP; + unsigned IOCTL_PIO_FONT = PIO_FONT; + unsigned IOCTL_PIO_UNIMAP = PIO_UNIMAP; + unsigned IOCTL_PIO_UNIMAPCLR = PIO_UNIMAPCLR; + unsigned IOCTL_PIO_UNISCRNMAP = PIO_UNISCRNMAP; +#if SANITIZER_GLIBC + unsigned IOCTL_SCSI_IOCTL_GET_IDLUN = SCSI_IOCTL_GET_IDLUN; + unsigned IOCTL_SCSI_IOCTL_PROBE_HOST = SCSI_IOCTL_PROBE_HOST; + unsigned IOCTL_SCSI_IOCTL_TAGGED_DISABLE = SCSI_IOCTL_TAGGED_DISABLE; + unsigned IOCTL_SCSI_IOCTL_TAGGED_ENABLE = SCSI_IOCTL_TAGGED_ENABLE; + unsigned IOCTL_SIOCAIPXITFCRT = SIOCAIPXITFCRT; + unsigned IOCTL_SIOCAIPXPRISLT = SIOCAIPXPRISLT; + unsigned IOCTL_SIOCAX25ADDUID = SIOCAX25ADDUID; + unsigned IOCTL_SIOCAX25DELUID = SIOCAX25DELUID; + unsigned IOCTL_SIOCAX25GETPARMS = SIOCAX25GETPARMS; + unsigned IOCTL_SIOCAX25GETUID = SIOCAX25GETUID; + unsigned IOCTL_SIOCAX25NOUID = SIOCAX25NOUID; + unsigned IOCTL_SIOCAX25SETPARMS = SIOCAX25SETPARMS; + unsigned IOCTL_SIOCDEVPLIP = SIOCDEVPLIP; + unsigned IOCTL_SIOCIPXCFGDATA = SIOCIPXCFGDATA; + unsigned IOCTL_SIOCNRDECOBS = SIOCNRDECOBS; + unsigned IOCTL_SIOCNRGETPARMS = SIOCNRGETPARMS; + unsigned IOCTL_SIOCNRRTCTL = SIOCNRRTCTL; + unsigned IOCTL_SIOCNRSETPARMS = SIOCNRSETPARMS; +#endif + unsigned IOCTL_TIOCGSERIAL = TIOCGSERIAL; + unsigned IOCTL_TIOCSERGETMULTI = TIOCSERGETMULTI; + unsigned IOCTL_TIOCSERSETMULTI = TIOCSERSETMULTI; + unsigned IOCTL_TIOCSSERIAL = TIOCSSERIAL; +#endif // SANITIZER_LINUX && !SANITIZER_ANDROID + +#if SANITIZER_LINUX && !SANITIZER_ANDROID + unsigned IOCTL_GIO_SCRNMAP = GIO_SCRNMAP; + unsigned IOCTL_KDDISABIO = KDDISABIO; + unsigned IOCTL_KDENABIO = KDENABIO; + unsigned IOCTL_KDGETLED = KDGETLED; + unsigned IOCTL_KDGETMODE = KDGETMODE; + unsigned IOCTL_KDGKBMODE = KDGKBMODE; + unsigned IOCTL_KDGKBTYPE = KDGKBTYPE; + unsigned IOCTL_KDMKTONE = KDMKTONE; + unsigned IOCTL_KDSETLED = KDSETLED; + unsigned IOCTL_KDSETMODE = KDSETMODE; + unsigned IOCTL_KDSKBMODE = KDSKBMODE; + unsigned IOCTL_KIOCSOUND = KIOCSOUND; + unsigned IOCTL_PIO_SCRNMAP = PIO_SCRNMAP; + unsigned IOCTL_SNDCTL_DSP_GETISPACE = SNDCTL_DSP_GETISPACE; + unsigned IOCTL_SNDCTL_DSP_GETOSPACE = SNDCTL_DSP_GETOSPACE; +#endif // (SANITIZER_LINUX || SANITIZER_FREEBSD) && !SANITIZER_ANDROID + + const int si_SEGV_MAPERR = SEGV_MAPERR; + const int si_SEGV_ACCERR = SEGV_ACCERR; +} // namespace __sanitizer + +using namespace __sanitizer; + +COMPILER_CHECK(sizeof(__sanitizer_pthread_attr_t) >= sizeof(pthread_attr_t)); + +COMPILER_CHECK(sizeof(socklen_t) == sizeof(unsigned)); +CHECK_TYPE_SIZE(pthread_key_t); + +#if SANITIZER_LINUX +// FIXME: We define those on Linux and Mac, but only check on Linux. +COMPILER_CHECK(IOC_NRBITS == _IOC_NRBITS); +COMPILER_CHECK(IOC_TYPEBITS == _IOC_TYPEBITS); +COMPILER_CHECK(IOC_SIZEBITS == _IOC_SIZEBITS); +COMPILER_CHECK(IOC_DIRBITS == _IOC_DIRBITS); +COMPILER_CHECK(IOC_NRMASK == _IOC_NRMASK); +COMPILER_CHECK(IOC_TYPEMASK == _IOC_TYPEMASK); +COMPILER_CHECK(IOC_SIZEMASK == _IOC_SIZEMASK); +COMPILER_CHECK(IOC_DIRMASK == _IOC_DIRMASK); +COMPILER_CHECK(IOC_NRSHIFT == _IOC_NRSHIFT); +COMPILER_CHECK(IOC_TYPESHIFT == _IOC_TYPESHIFT); +COMPILER_CHECK(IOC_SIZESHIFT == _IOC_SIZESHIFT); +COMPILER_CHECK(IOC_DIRSHIFT == _IOC_DIRSHIFT); +COMPILER_CHECK(IOC_NONE == _IOC_NONE); +COMPILER_CHECK(IOC_WRITE == _IOC_WRITE); +COMPILER_CHECK(IOC_READ == _IOC_READ); +COMPILER_CHECK(EVIOC_ABS_MAX == ABS_MAX); +COMPILER_CHECK(EVIOC_EV_MAX == EV_MAX); +COMPILER_CHECK(IOC_SIZE(0x12345678) == _IOC_SIZE(0x12345678)); +COMPILER_CHECK(IOC_DIR(0x12345678) == _IOC_DIR(0x12345678)); +COMPILER_CHECK(IOC_NR(0x12345678) == _IOC_NR(0x12345678)); +COMPILER_CHECK(IOC_TYPE(0x12345678) == _IOC_TYPE(0x12345678)); +#endif // SANITIZER_LINUX + +#if SANITIZER_LINUX || SANITIZER_FREEBSD +// There are more undocumented fields in dl_phdr_info that we are not interested +// in. +COMPILER_CHECK(sizeof(__sanitizer_dl_phdr_info) <= sizeof(dl_phdr_info)); +CHECK_SIZE_AND_OFFSET(dl_phdr_info, dlpi_addr); +CHECK_SIZE_AND_OFFSET(dl_phdr_info, dlpi_name); +CHECK_SIZE_AND_OFFSET(dl_phdr_info, dlpi_phdr); +CHECK_SIZE_AND_OFFSET(dl_phdr_info, dlpi_phnum); +#endif // SANITIZER_LINUX || SANITIZER_FREEBSD + +#if SANITIZER_GLIBC || SANITIZER_FREEBSD +CHECK_TYPE_SIZE(glob_t); +CHECK_SIZE_AND_OFFSET(glob_t, gl_pathc); +CHECK_SIZE_AND_OFFSET(glob_t, gl_pathv); +CHECK_SIZE_AND_OFFSET(glob_t, gl_offs); +CHECK_SIZE_AND_OFFSET(glob_t, gl_flags); +CHECK_SIZE_AND_OFFSET(glob_t, gl_closedir); +CHECK_SIZE_AND_OFFSET(glob_t, gl_readdir); +CHECK_SIZE_AND_OFFSET(glob_t, gl_opendir); +CHECK_SIZE_AND_OFFSET(glob_t, gl_lstat); +CHECK_SIZE_AND_OFFSET(glob_t, gl_stat); +#endif // SANITIZER_GLIBC || SANITIZER_FREEBSD + +CHECK_TYPE_SIZE(addrinfo); +CHECK_SIZE_AND_OFFSET(addrinfo, ai_flags); +CHECK_SIZE_AND_OFFSET(addrinfo, ai_family); +CHECK_SIZE_AND_OFFSET(addrinfo, ai_socktype); +CHECK_SIZE_AND_OFFSET(addrinfo, ai_protocol); +CHECK_SIZE_AND_OFFSET(addrinfo, ai_protocol); +CHECK_SIZE_AND_OFFSET(addrinfo, ai_addrlen); +CHECK_SIZE_AND_OFFSET(addrinfo, ai_canonname); +CHECK_SIZE_AND_OFFSET(addrinfo, ai_addr); + +CHECK_TYPE_SIZE(hostent); +CHECK_SIZE_AND_OFFSET(hostent, h_name); +CHECK_SIZE_AND_OFFSET(hostent, h_aliases); +CHECK_SIZE_AND_OFFSET(hostent, h_addrtype); +CHECK_SIZE_AND_OFFSET(hostent, h_length); +CHECK_SIZE_AND_OFFSET(hostent, h_addr_list); + +CHECK_TYPE_SIZE(iovec); +CHECK_SIZE_AND_OFFSET(iovec, iov_base); +CHECK_SIZE_AND_OFFSET(iovec, iov_len); + +// In POSIX, int msg_iovlen; socklen_t msg_controllen; socklen_t cmsg_len; but +// many implementations don't conform to the standard. Since we pick the +// non-conforming glibc definition, exclude the checks for musl (incompatible +// sizes but compatible offsets). +CHECK_TYPE_SIZE(msghdr); +CHECK_SIZE_AND_OFFSET(msghdr, msg_name); +CHECK_SIZE_AND_OFFSET(msghdr, msg_namelen); +CHECK_SIZE_AND_OFFSET(msghdr, msg_iov); +#if SANITIZER_GLIBC || SANITIZER_ANDROID +CHECK_SIZE_AND_OFFSET(msghdr, msg_iovlen); +#endif +CHECK_SIZE_AND_OFFSET(msghdr, msg_control); +#if SANITIZER_GLIBC || SANITIZER_ANDROID +CHECK_SIZE_AND_OFFSET(msghdr, msg_controllen); +#endif +CHECK_SIZE_AND_OFFSET(msghdr, msg_flags); + +CHECK_TYPE_SIZE(cmsghdr); +#if SANITIZER_GLIBC || SANITIZER_ANDROID +CHECK_SIZE_AND_OFFSET(cmsghdr, cmsg_len); +#endif +CHECK_SIZE_AND_OFFSET(cmsghdr, cmsg_level); +CHECK_SIZE_AND_OFFSET(cmsghdr, cmsg_type); + +#if SANITIZER_LINUX && (__ANDROID_API__ >= 21 || __GLIBC_PREREQ (2, 14)) +CHECK_TYPE_SIZE(mmsghdr); +CHECK_SIZE_AND_OFFSET(mmsghdr, msg_hdr); +CHECK_SIZE_AND_OFFSET(mmsghdr, msg_len); +#endif + +COMPILER_CHECK(sizeof(__sanitizer_dirent) <= sizeof(dirent)); +CHECK_SIZE_AND_OFFSET(dirent, d_ino); +#if SANITIZER_MAC +CHECK_SIZE_AND_OFFSET(dirent, d_seekoff); +#elif SANITIZER_FREEBSD +// There is no 'd_off' field on FreeBSD. +#else +CHECK_SIZE_AND_OFFSET(dirent, d_off); +#endif +CHECK_SIZE_AND_OFFSET(dirent, d_reclen); + +#if SANITIZER_LINUX && !SANITIZER_ANDROID +COMPILER_CHECK(sizeof(__sanitizer_dirent64) <= sizeof(dirent64)); +CHECK_SIZE_AND_OFFSET(dirent64, d_ino); +CHECK_SIZE_AND_OFFSET(dirent64, d_off); +CHECK_SIZE_AND_OFFSET(dirent64, d_reclen); +#endif + +CHECK_TYPE_SIZE(ifconf); +CHECK_SIZE_AND_OFFSET(ifconf, ifc_len); +CHECK_SIZE_AND_OFFSET(ifconf, ifc_ifcu); + +CHECK_TYPE_SIZE(pollfd); +CHECK_SIZE_AND_OFFSET(pollfd, fd); +CHECK_SIZE_AND_OFFSET(pollfd, events); +CHECK_SIZE_AND_OFFSET(pollfd, revents); + +CHECK_TYPE_SIZE(nfds_t); + +CHECK_TYPE_SIZE(sigset_t); + +COMPILER_CHECK(sizeof(__sanitizer_sigaction) == sizeof(struct sigaction)); +// Can't write checks for sa_handler and sa_sigaction due to them being +// preprocessor macros. +CHECK_STRUCT_SIZE_AND_OFFSET(sigaction, sa_mask); +#if !defined(__s390x__) || __GLIBC_PREREQ (2, 20) +// On s390x glibc 2.19 and earlier sa_flags was unsigned long, and sa_resv +// didn't exist. +CHECK_STRUCT_SIZE_AND_OFFSET(sigaction, sa_flags); +#endif +#if SANITIZER_LINUX && (!SANITIZER_ANDROID || !SANITIZER_MIPS32) +CHECK_STRUCT_SIZE_AND_OFFSET(sigaction, sa_restorer); +#endif + +#if SANITIZER_LINUX +CHECK_TYPE_SIZE(__sysctl_args); +CHECK_SIZE_AND_OFFSET(__sysctl_args, name); +CHECK_SIZE_AND_OFFSET(__sysctl_args, nlen); +CHECK_SIZE_AND_OFFSET(__sysctl_args, oldval); +CHECK_SIZE_AND_OFFSET(__sysctl_args, oldlenp); +CHECK_SIZE_AND_OFFSET(__sysctl_args, newval); +CHECK_SIZE_AND_OFFSET(__sysctl_args, newlen); + +CHECK_TYPE_SIZE(__kernel_uid_t); +CHECK_TYPE_SIZE(__kernel_gid_t); + +#if SANITIZER_USES_UID16_SYSCALLS +CHECK_TYPE_SIZE(__kernel_old_uid_t); +CHECK_TYPE_SIZE(__kernel_old_gid_t); +#endif + +CHECK_TYPE_SIZE(__kernel_off_t); +CHECK_TYPE_SIZE(__kernel_loff_t); +CHECK_TYPE_SIZE(__kernel_fd_set); +#endif + +#if !SANITIZER_ANDROID +CHECK_TYPE_SIZE(wordexp_t); +CHECK_SIZE_AND_OFFSET(wordexp_t, we_wordc); +CHECK_SIZE_AND_OFFSET(wordexp_t, we_wordv); +CHECK_SIZE_AND_OFFSET(wordexp_t, we_offs); +#endif + +CHECK_TYPE_SIZE(tm); +CHECK_SIZE_AND_OFFSET(tm, tm_sec); +CHECK_SIZE_AND_OFFSET(tm, tm_min); +CHECK_SIZE_AND_OFFSET(tm, tm_hour); +CHECK_SIZE_AND_OFFSET(tm, tm_mday); +CHECK_SIZE_AND_OFFSET(tm, tm_mon); +CHECK_SIZE_AND_OFFSET(tm, tm_year); +CHECK_SIZE_AND_OFFSET(tm, tm_wday); +CHECK_SIZE_AND_OFFSET(tm, tm_yday); +CHECK_SIZE_AND_OFFSET(tm, tm_isdst); +CHECK_SIZE_AND_OFFSET(tm, tm_gmtoff); +CHECK_SIZE_AND_OFFSET(tm, tm_zone); + +#if SANITIZER_LINUX +CHECK_TYPE_SIZE(mntent); +CHECK_SIZE_AND_OFFSET(mntent, mnt_fsname); +CHECK_SIZE_AND_OFFSET(mntent, mnt_dir); +CHECK_SIZE_AND_OFFSET(mntent, mnt_type); +CHECK_SIZE_AND_OFFSET(mntent, mnt_opts); +CHECK_SIZE_AND_OFFSET(mntent, mnt_freq); +CHECK_SIZE_AND_OFFSET(mntent, mnt_passno); +#endif + +CHECK_TYPE_SIZE(ether_addr); + +#if SANITIZER_GLIBC || SANITIZER_FREEBSD +CHECK_TYPE_SIZE(ipc_perm); +# if SANITIZER_FREEBSD +CHECK_SIZE_AND_OFFSET(ipc_perm, key); +CHECK_SIZE_AND_OFFSET(ipc_perm, seq); +# else +CHECK_SIZE_AND_OFFSET(ipc_perm, __key); +CHECK_SIZE_AND_OFFSET(ipc_perm, __seq); +# endif +CHECK_SIZE_AND_OFFSET(ipc_perm, uid); +CHECK_SIZE_AND_OFFSET(ipc_perm, gid); +CHECK_SIZE_AND_OFFSET(ipc_perm, cuid); +CHECK_SIZE_AND_OFFSET(ipc_perm, cgid); +#if !SANITIZER_LINUX || __GLIBC_PREREQ (2, 31) +/* glibc 2.30 and earlier provided 16-bit mode field instead of 32-bit + on many architectures. */ +CHECK_SIZE_AND_OFFSET(ipc_perm, mode); +#endif + +CHECK_TYPE_SIZE(shmid_ds); +CHECK_SIZE_AND_OFFSET(shmid_ds, shm_perm); +CHECK_SIZE_AND_OFFSET(shmid_ds, shm_segsz); +CHECK_SIZE_AND_OFFSET(shmid_ds, shm_atime); +CHECK_SIZE_AND_OFFSET(shmid_ds, shm_dtime); +CHECK_SIZE_AND_OFFSET(shmid_ds, shm_ctime); +CHECK_SIZE_AND_OFFSET(shmid_ds, shm_cpid); +CHECK_SIZE_AND_OFFSET(shmid_ds, shm_lpid); +CHECK_SIZE_AND_OFFSET(shmid_ds, shm_nattch); +#endif + +CHECK_TYPE_SIZE(clock_t); + +#if SANITIZER_LINUX +CHECK_TYPE_SIZE(clockid_t); +#endif + +#if !SANITIZER_ANDROID +CHECK_TYPE_SIZE(ifaddrs); +CHECK_SIZE_AND_OFFSET(ifaddrs, ifa_next); +CHECK_SIZE_AND_OFFSET(ifaddrs, ifa_name); +CHECK_SIZE_AND_OFFSET(ifaddrs, ifa_addr); +CHECK_SIZE_AND_OFFSET(ifaddrs, ifa_netmask); +#if SANITIZER_LINUX || SANITIZER_FREEBSD +// Compare against the union, because we can't reach into the union in a +// compliant way. +#ifdef ifa_dstaddr +#undef ifa_dstaddr +#endif +# if SANITIZER_FREEBSD +CHECK_SIZE_AND_OFFSET(ifaddrs, ifa_dstaddr); +# else +COMPILER_CHECK(sizeof(((__sanitizer_ifaddrs *)nullptr)->ifa_dstaddr) == + sizeof(((ifaddrs *)nullptr)->ifa_ifu)); +COMPILER_CHECK(offsetof(__sanitizer_ifaddrs, ifa_dstaddr) == + offsetof(ifaddrs, ifa_ifu)); +# endif // SANITIZER_FREEBSD +#else +CHECK_SIZE_AND_OFFSET(ifaddrs, ifa_dstaddr); +#endif // SANITIZER_LINUX +CHECK_SIZE_AND_OFFSET(ifaddrs, ifa_data); +#endif + +#if SANITIZER_GLIBC || SANITIZER_ANDROID +COMPILER_CHECK(sizeof(__sanitizer_struct_mallinfo) == sizeof(struct mallinfo)); +#endif + +#if !SANITIZER_ANDROID +CHECK_TYPE_SIZE(timeb); +CHECK_SIZE_AND_OFFSET(timeb, time); +CHECK_SIZE_AND_OFFSET(timeb, millitm); +CHECK_SIZE_AND_OFFSET(timeb, timezone); +CHECK_SIZE_AND_OFFSET(timeb, dstflag); +#endif + +CHECK_TYPE_SIZE(passwd); +CHECK_SIZE_AND_OFFSET(passwd, pw_name); +CHECK_SIZE_AND_OFFSET(passwd, pw_passwd); +CHECK_SIZE_AND_OFFSET(passwd, pw_uid); +CHECK_SIZE_AND_OFFSET(passwd, pw_gid); +CHECK_SIZE_AND_OFFSET(passwd, pw_dir); +CHECK_SIZE_AND_OFFSET(passwd, pw_shell); + +#if !SANITIZER_ANDROID +CHECK_SIZE_AND_OFFSET(passwd, pw_gecos); +#endif + +#if SANITIZER_MAC +CHECK_SIZE_AND_OFFSET(passwd, pw_change); +CHECK_SIZE_AND_OFFSET(passwd, pw_expire); +CHECK_SIZE_AND_OFFSET(passwd, pw_class); +#endif + + +CHECK_TYPE_SIZE(group); +CHECK_SIZE_AND_OFFSET(group, gr_name); +CHECK_SIZE_AND_OFFSET(group, gr_passwd); +CHECK_SIZE_AND_OFFSET(group, gr_gid); +CHECK_SIZE_AND_OFFSET(group, gr_mem); + +#if HAVE_RPC_XDR_H +CHECK_TYPE_SIZE(XDR); +CHECK_SIZE_AND_OFFSET(XDR, x_op); +CHECK_SIZE_AND_OFFSET(XDR, x_ops); +CHECK_SIZE_AND_OFFSET(XDR, x_public); +CHECK_SIZE_AND_OFFSET(XDR, x_private); +CHECK_SIZE_AND_OFFSET(XDR, x_base); +CHECK_SIZE_AND_OFFSET(XDR, x_handy); +COMPILER_CHECK(__sanitizer_XDR_ENCODE == XDR_ENCODE); +COMPILER_CHECK(__sanitizer_XDR_DECODE == XDR_DECODE); +COMPILER_CHECK(__sanitizer_XDR_FREE == XDR_FREE); +#endif + +#if SANITIZER_GLIBC +COMPILER_CHECK(sizeof(__sanitizer_FILE) <= sizeof(FILE)); +CHECK_SIZE_AND_OFFSET(FILE, _flags); +CHECK_SIZE_AND_OFFSET(FILE, _IO_read_ptr); +CHECK_SIZE_AND_OFFSET(FILE, _IO_read_end); +CHECK_SIZE_AND_OFFSET(FILE, _IO_read_base); +CHECK_SIZE_AND_OFFSET(FILE, _IO_write_ptr); +CHECK_SIZE_AND_OFFSET(FILE, _IO_write_end); +CHECK_SIZE_AND_OFFSET(FILE, _IO_write_base); +CHECK_SIZE_AND_OFFSET(FILE, _IO_buf_base); +CHECK_SIZE_AND_OFFSET(FILE, _IO_buf_end); +CHECK_SIZE_AND_OFFSET(FILE, _IO_save_base); +CHECK_SIZE_AND_OFFSET(FILE, _IO_backup_base); +CHECK_SIZE_AND_OFFSET(FILE, _IO_save_end); +CHECK_SIZE_AND_OFFSET(FILE, _markers); +CHECK_SIZE_AND_OFFSET(FILE, _chain); +CHECK_SIZE_AND_OFFSET(FILE, _fileno); + +COMPILER_CHECK(sizeof(__sanitizer__obstack_chunk) <= sizeof(_obstack_chunk)); +CHECK_SIZE_AND_OFFSET(_obstack_chunk, limit); +CHECK_SIZE_AND_OFFSET(_obstack_chunk, prev); +CHECK_TYPE_SIZE(obstack); +CHECK_SIZE_AND_OFFSET(obstack, chunk_size); +CHECK_SIZE_AND_OFFSET(obstack, chunk); +CHECK_SIZE_AND_OFFSET(obstack, object_base); +CHECK_SIZE_AND_OFFSET(obstack, next_free); + +CHECK_TYPE_SIZE(cookie_io_functions_t); +CHECK_SIZE_AND_OFFSET(cookie_io_functions_t, read); +CHECK_SIZE_AND_OFFSET(cookie_io_functions_t, write); +CHECK_SIZE_AND_OFFSET(cookie_io_functions_t, seek); +CHECK_SIZE_AND_OFFSET(cookie_io_functions_t, close); +#endif // SANITIZER_GLIBC + +#if SANITIZER_LINUX || SANITIZER_FREEBSD +CHECK_TYPE_SIZE(sem_t); +#endif + +#if SANITIZER_LINUX && defined(__arm__) +COMPILER_CHECK(ARM_VFPREGS_SIZE == ARM_VFPREGS_SIZE_ASAN); +#endif + +#endif // SANITIZER_LINUX || SANITIZER_FREEBSD || SANITIZER_MAC diff --git a/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_platform_limits_posix.h b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_platform_limits_posix.h new file mode 100644 index 0000000000..4472b6efa9 --- /dev/null +++ b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_platform_limits_posix.h @@ -0,0 +1,1459 @@ +//===-- sanitizer_platform_limits_posix.h ---------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file is a part of Sanitizer common code. +// +// Sizes and layouts of platform-specific POSIX data structures. +//===----------------------------------------------------------------------===// + +#ifndef SANITIZER_PLATFORM_LIMITS_POSIX_H +#define SANITIZER_PLATFORM_LIMITS_POSIX_H + +#if SANITIZER_LINUX || SANITIZER_MAC + +#include "sanitizer_internal_defs.h" +#include "sanitizer_platform.h" + +#if defined(__sparc__) +// FIXME: This can't be included from tsan which does not support sparc yet. +#include "sanitizer_glibc_version.h" +#endif + +# define GET_LINK_MAP_BY_DLOPEN_HANDLE(handle) ((link_map*)(handle)) + +namespace __sanitizer { +extern unsigned struct_utsname_sz; +extern unsigned struct_stat_sz; +#if !SANITIZER_IOS +extern unsigned struct_stat64_sz; +#endif +extern unsigned struct_rusage_sz; +extern unsigned siginfo_t_sz; +extern unsigned struct_itimerval_sz; +extern unsigned pthread_t_sz; +extern unsigned pthread_mutex_t_sz; +extern unsigned pthread_cond_t_sz; +extern unsigned pid_t_sz; +extern unsigned timeval_sz; +extern unsigned uid_t_sz; +extern unsigned gid_t_sz; +extern unsigned mbstate_t_sz; +extern unsigned struct_timezone_sz; +extern unsigned struct_tms_sz; +extern unsigned struct_itimerspec_sz; +extern unsigned struct_sigevent_sz; +extern unsigned struct_stack_t_sz; +extern unsigned struct_sched_param_sz; +extern unsigned struct_statfs64_sz; +extern unsigned struct_regex_sz; +extern unsigned struct_regmatch_sz; + +#if !SANITIZER_ANDROID +extern unsigned struct_fstab_sz; +extern unsigned struct_statfs_sz; +extern unsigned struct_sockaddr_sz; +unsigned ucontext_t_sz(void *uctx); +# endif // !SANITIZER_ANDROID + +# if SANITIZER_LINUX + +# if defined(__x86_64__) +const unsigned struct_kernel_stat_sz = 144; +const unsigned struct_kernel_stat64_sz = 0; +#elif defined(__i386__) +const unsigned struct_kernel_stat_sz = 64; +const unsigned struct_kernel_stat64_sz = 96; +#elif defined(__arm__) +const unsigned struct_kernel_stat_sz = 64; +const unsigned struct_kernel_stat64_sz = 104; +#elif defined(__aarch64__) +const unsigned struct_kernel_stat_sz = 128; +const unsigned struct_kernel_stat64_sz = 104; +#elif defined(__powerpc__) && !defined(__powerpc64__) +const unsigned struct_kernel_stat_sz = 72; +const unsigned struct_kernel_stat64_sz = 104; +#elif defined(__powerpc64__) +const unsigned struct_kernel_stat_sz = 144; +const unsigned struct_kernel_stat64_sz = 104; +#elif defined(__mips__) +const unsigned struct_kernel_stat_sz = SANITIZER_ANDROID + ? FIRST_32_SECOND_64(104, 128) + : FIRST_32_SECOND_64(160, 216); +const unsigned struct_kernel_stat64_sz = 104; +#elif defined(__s390__) && !defined(__s390x__) +const unsigned struct_kernel_stat_sz = 64; +const unsigned struct_kernel_stat64_sz = 104; +#elif defined(__s390x__) +const unsigned struct_kernel_stat_sz = 144; +const unsigned struct_kernel_stat64_sz = 0; +#elif defined(__sparc__) && defined(__arch64__) +const unsigned struct___old_kernel_stat_sz = 0; +const unsigned struct_kernel_stat_sz = 104; +const unsigned struct_kernel_stat64_sz = 144; +#elif defined(__sparc__) && !defined(__arch64__) +const unsigned struct___old_kernel_stat_sz = 0; +const unsigned struct_kernel_stat_sz = 64; +const unsigned struct_kernel_stat64_sz = 104; +#elif SANITIZER_RISCV64 +const unsigned struct_kernel_stat_sz = 128; +const unsigned struct_kernel_stat64_sz = 0; // RISCV64 does not use stat64 +# elif defined(__hexagon__) +const unsigned struct_kernel_stat_sz = 128; +const unsigned struct_kernel_stat64_sz = 0; +# endif +struct __sanitizer_perf_event_attr { + unsigned type; + unsigned size; + // More fields that vary with the kernel version. +}; + +extern unsigned struct_epoll_event_sz; +extern unsigned struct_sysinfo_sz; +extern unsigned __user_cap_header_struct_sz; +extern unsigned __user_cap_data_struct_sz; +extern unsigned struct_new_utsname_sz; +extern unsigned struct_old_utsname_sz; +extern unsigned struct_oldold_utsname_sz; + +const unsigned struct_kexec_segment_sz = 4 * sizeof(unsigned long); +#endif // SANITIZER_LINUX + +#if SANITIZER_LINUX + +#if defined(__powerpc64__) || defined(__s390__) +const unsigned struct___old_kernel_stat_sz = 0; +#elif !defined(__sparc__) +const unsigned struct___old_kernel_stat_sz = 32; +#endif + +extern unsigned struct_rlimit_sz; +extern unsigned struct_utimbuf_sz; +extern unsigned struct_timespec_sz; + +struct __sanitizer_iocb { + u64 aio_data; + u32 aio_key_or_aio_reserved1; // Simply crazy. + u32 aio_reserved1_or_aio_key; // Luckily, we don't need these. + u16 aio_lio_opcode; + s16 aio_reqprio; + u32 aio_fildes; + u64 aio_buf; + u64 aio_nbytes; + s64 aio_offset; + u64 aio_reserved2; + u64 aio_reserved3; +}; + +struct __sanitizer_io_event { + u64 data; + u64 obj; + u64 res; + u64 res2; +}; + +const unsigned iocb_cmd_pread = 0; +const unsigned iocb_cmd_pwrite = 1; +const unsigned iocb_cmd_preadv = 7; +const unsigned iocb_cmd_pwritev = 8; + +struct __sanitizer___sysctl_args { + int *name; + int nlen; + void *oldval; + uptr *oldlenp; + void *newval; + uptr newlen; + unsigned long ___unused[4]; +}; + +const unsigned old_sigset_t_sz = sizeof(unsigned long); + +struct __sanitizer_sem_t { +#if SANITIZER_ANDROID && defined(_LP64) + int data[4]; +#elif SANITIZER_ANDROID && !defined(_LP64) + int data; +#elif SANITIZER_LINUX + uptr data[4]; +#endif +}; +#endif // SANITIZER_LINUX + +#if SANITIZER_ANDROID +struct __sanitizer_struct_mallinfo { + uptr v[10]; +}; +#endif + +#if SANITIZER_LINUX && !SANITIZER_ANDROID +struct __sanitizer_struct_mallinfo { + int v[10]; +}; + +extern unsigned struct_ustat_sz; +extern unsigned struct_rlimit64_sz; +extern unsigned struct_statvfs64_sz; + +struct __sanitizer_ipc_perm { + int __key; + int uid; + int gid; + int cuid; + int cgid; +#ifdef __powerpc__ + unsigned mode; + unsigned __seq; + u64 __unused1; + u64 __unused2; +#elif defined(__sparc__) + unsigned mode; + unsigned short __pad2; + unsigned short __seq; + unsigned long long __unused1; + unsigned long long __unused2; +#else + unsigned int mode; + unsigned short __seq; + unsigned short __pad2; +#if defined(__x86_64__) && !defined(_LP64) + u64 __unused1; + u64 __unused2; +#else + unsigned long __unused1; + unsigned long __unused2; +#endif +#endif +}; + +struct __sanitizer_shmid_ds { + __sanitizer_ipc_perm shm_perm; +#if defined(__sparc__) +#if !defined(__arch64__) + u32 __pad1; +#endif + long shm_atime; +#if !defined(__arch64__) + u32 __pad2; +#endif + long shm_dtime; +#if !defined(__arch64__) + u32 __pad3; +#endif + long shm_ctime; + uptr shm_segsz; + int shm_cpid; + int shm_lpid; + unsigned long shm_nattch; + unsigned long __glibc_reserved1; + unsigned long __glibc_reserved2; +#else +#ifndef __powerpc__ + uptr shm_segsz; +#elif !defined(__powerpc64__) + uptr __unused0; +#endif +#if defined(__x86_64__) && !defined(_LP64) + u64 shm_atime; + u64 shm_dtime; + u64 shm_ctime; +#else + uptr shm_atime; +#if !defined(_LP64) && !defined(__mips__) + uptr __unused1; +#endif + uptr shm_dtime; +#if !defined(_LP64) && !defined(__mips__) + uptr __unused2; +#endif + uptr shm_ctime; +#if !defined(_LP64) && !defined(__mips__) + uptr __unused3; +#endif +#endif +#ifdef __powerpc__ + uptr shm_segsz; +#endif + int shm_cpid; + int shm_lpid; +#if defined(__x86_64__) && !defined(_LP64) + u64 shm_nattch; + u64 __unused4; + u64 __unused5; +#else + uptr shm_nattch; + uptr __unused4; + uptr __unused5; +#endif +#endif +}; +#endif + +#if SANITIZER_LINUX && !SANITIZER_ANDROID +extern unsigned struct_msqid_ds_sz; +extern unsigned struct_mq_attr_sz; +extern unsigned struct_timex_sz; +extern unsigned struct_statvfs_sz; +extern unsigned struct_crypt_data_sz; +#endif // SANITIZER_LINUX && !SANITIZER_ANDROID + +struct __sanitizer_iovec { + void *iov_base; + uptr iov_len; +}; + +#if !SANITIZER_ANDROID +struct __sanitizer_ifaddrs { + struct __sanitizer_ifaddrs *ifa_next; + char *ifa_name; + unsigned int ifa_flags; + void *ifa_addr; // (struct sockaddr *) + void *ifa_netmask; // (struct sockaddr *) + // This is a union on Linux. +# ifdef ifa_dstaddr +# undef ifa_dstaddr +# endif + void *ifa_dstaddr; // (struct sockaddr *) + void *ifa_data; +}; +#endif // !SANITIZER_ANDROID + +#if SANITIZER_MAC +typedef unsigned long __sanitizer_pthread_key_t; +#else +typedef unsigned __sanitizer_pthread_key_t; +#endif + +#if SANITIZER_LINUX && !SANITIZER_ANDROID + +struct __sanitizer_XDR { + int x_op; + void *x_ops; + uptr x_public; + uptr x_private; + uptr x_base; + unsigned x_handy; +}; + +const int __sanitizer_XDR_ENCODE = 0; +const int __sanitizer_XDR_DECODE = 1; +const int __sanitizer_XDR_FREE = 2; +#endif + +struct __sanitizer_passwd { + char *pw_name; + char *pw_passwd; + int pw_uid; + int pw_gid; +#if SANITIZER_MAC + long pw_change; + char *pw_class; +#endif +#if !(SANITIZER_ANDROID && (SANITIZER_WORDSIZE == 32)) + char *pw_gecos; +#endif + char *pw_dir; + char *pw_shell; +#if SANITIZER_MAC + long pw_expire; +#endif +}; + +struct __sanitizer_group { + char *gr_name; + char *gr_passwd; + int gr_gid; + char **gr_mem; +}; + +# if (defined(__x86_64__) && !defined(_LP64)) || defined(__hexagon__) +typedef long long __sanitizer_time_t; +#else +typedef long __sanitizer_time_t; +#endif + +typedef long __sanitizer_suseconds_t; + +struct __sanitizer_timeval { + __sanitizer_time_t tv_sec; + __sanitizer_suseconds_t tv_usec; +}; + +struct __sanitizer_itimerval { + struct __sanitizer_timeval it_interval; + struct __sanitizer_timeval it_value; +}; + +struct __sanitizer_timeb { + __sanitizer_time_t time; + unsigned short millitm; + short timezone; + short dstflag; +}; + +struct __sanitizer_ether_addr { + u8 octet[6]; +}; + +struct __sanitizer_tm { + int tm_sec; + int tm_min; + int tm_hour; + int tm_mday; + int tm_mon; + int tm_year; + int tm_wday; + int tm_yday; + int tm_isdst; + long int tm_gmtoff; + const char *tm_zone; +}; + +#if SANITIZER_LINUX +struct __sanitizer_mntent { + char *mnt_fsname; + char *mnt_dir; + char *mnt_type; + char *mnt_opts; + int mnt_freq; + int mnt_passno; +}; + +struct __sanitizer_file_handle { + unsigned int handle_bytes; + int handle_type; + unsigned char f_handle[1]; // variable sized +}; +#endif + +#if SANITIZER_MAC +struct __sanitizer_msghdr { + void *msg_name; + unsigned msg_namelen; + struct __sanitizer_iovec *msg_iov; + unsigned msg_iovlen; + void *msg_control; + unsigned msg_controllen; + int msg_flags; +}; +struct __sanitizer_cmsghdr { + unsigned cmsg_len; + int cmsg_level; + int cmsg_type; +}; +#else +// In POSIX, int msg_iovlen; socklen_t msg_controllen; socklen_t cmsg_len; but +// many implementations don't conform to the standard. +struct __sanitizer_msghdr { + void *msg_name; + unsigned msg_namelen; + struct __sanitizer_iovec *msg_iov; + uptr msg_iovlen; + void *msg_control; + uptr msg_controllen; + int msg_flags; +}; +struct __sanitizer_cmsghdr { + uptr cmsg_len; + int cmsg_level; + int cmsg_type; +}; +#endif + +#if SANITIZER_LINUX +struct __sanitizer_mmsghdr { + __sanitizer_msghdr msg_hdr; + unsigned int msg_len; +}; +#endif + +#if SANITIZER_MAC +struct __sanitizer_dirent { + unsigned long long d_ino; + unsigned long long d_seekoff; + unsigned short d_reclen; + // more fields that we don't care about +}; +# elif SANITIZER_ANDROID || defined(__x86_64__) || defined(__hexagon__) +struct __sanitizer_dirent { + unsigned long long d_ino; + unsigned long long d_off; + unsigned short d_reclen; + // more fields that we don't care about +}; +# else +struct __sanitizer_dirent { + uptr d_ino; + uptr d_off; + unsigned short d_reclen; + // more fields that we don't care about +}; +# endif + +# if SANITIZER_LINUX && !SANITIZER_ANDROID +struct __sanitizer_dirent64 { + unsigned long long d_ino; + unsigned long long d_off; + unsigned short d_reclen; + // more fields that we don't care about +}; +#endif + +#if defined(__x86_64__) && !defined(_LP64) +typedef long long __sanitizer_clock_t; +#else +typedef long __sanitizer_clock_t; +#endif + +#if SANITIZER_LINUX +typedef int __sanitizer_clockid_t; +#endif + +#if SANITIZER_LINUX +# if defined(_LP64) || defined(__x86_64__) || defined(__powerpc__) || \ + defined(__mips__) || defined(__hexagon__) +typedef unsigned __sanitizer___kernel_uid_t; +typedef unsigned __sanitizer___kernel_gid_t; +#else +typedef unsigned short __sanitizer___kernel_uid_t; +typedef unsigned short __sanitizer___kernel_gid_t; +#endif +#if defined(__x86_64__) && !defined(_LP64) +typedef long long __sanitizer___kernel_off_t; +#else +typedef long __sanitizer___kernel_off_t; +#endif + +#if defined(__powerpc__) || defined(__mips__) +typedef unsigned int __sanitizer___kernel_old_uid_t; +typedef unsigned int __sanitizer___kernel_old_gid_t; +#else +typedef unsigned short __sanitizer___kernel_old_uid_t; +typedef unsigned short __sanitizer___kernel_old_gid_t; +#endif + +typedef long long __sanitizer___kernel_loff_t; +typedef struct { + unsigned long fds_bits[1024 / (8 * sizeof(long))]; +} __sanitizer___kernel_fd_set; +#endif + +// This thing depends on the platform. We are only interested in the upper +// limit. Verified with a compiler assert in .cpp. +union __sanitizer_pthread_attr_t { + char size[128]; + void *align; +}; + +#if SANITIZER_ANDROID +# if SANITIZER_MIPS +typedef unsigned long __sanitizer_sigset_t[16 / sizeof(unsigned long)]; +# else +typedef unsigned long __sanitizer_sigset_t; +# endif +#elif SANITIZER_MAC +typedef unsigned __sanitizer_sigset_t; +#elif SANITIZER_LINUX +struct __sanitizer_sigset_t { + // The size is determined by looking at sizeof of real sigset_t on linux. + uptr val[128 / sizeof(uptr)]; +}; +#endif + +struct __sanitizer_siginfo { + // The size is determined by looking at sizeof of real siginfo_t on linux. + u64 opaque[128 / sizeof(u64)]; +}; + +using __sanitizer_sighandler_ptr = void (*)(int sig); +using __sanitizer_sigactionhandler_ptr = void (*)(int sig, + __sanitizer_siginfo *siginfo, + void *uctx); + +// Linux system headers define the 'sa_handler' and 'sa_sigaction' macros. +#if SANITIZER_ANDROID && (SANITIZER_WORDSIZE == 64) +struct __sanitizer_sigaction { + unsigned sa_flags; + union { + __sanitizer_sigactionhandler_ptr sigaction; + __sanitizer_sighandler_ptr handler; + }; + __sanitizer_sigset_t sa_mask; + void (*sa_restorer)(); +}; +#elif SANITIZER_ANDROID && SANITIZER_MIPS32 // check this before WORDSIZE == 32 +struct __sanitizer_sigaction { + unsigned sa_flags; + union { + __sanitizer_sigactionhandler_ptr sigaction; + __sanitizer_sighandler_ptr handler; + }; + __sanitizer_sigset_t sa_mask; +}; +#elif SANITIZER_ANDROID && (SANITIZER_WORDSIZE == 32) +struct __sanitizer_sigaction { + union { + __sanitizer_sigactionhandler_ptr sigaction; + __sanitizer_sighandler_ptr handler; + }; + __sanitizer_sigset_t sa_mask; + uptr sa_flags; + void (*sa_restorer)(); +}; +#else // !SANITIZER_ANDROID +struct __sanitizer_sigaction { +#if defined(__mips__) && !SANITIZER_FREEBSD + unsigned int sa_flags; +#endif + union { + __sanitizer_sigactionhandler_ptr sigaction; + __sanitizer_sighandler_ptr handler; + }; +#if SANITIZER_FREEBSD + int sa_flags; + __sanitizer_sigset_t sa_mask; +#else +#if defined(__s390x__) + int sa_resv; +#else + __sanitizer_sigset_t sa_mask; +#endif +#ifndef __mips__ +#if defined(__sparc__) +#if __GLIBC_PREREQ (2, 20) + // On sparc glibc 2.19 and earlier sa_flags was unsigned long. +#if defined(__arch64__) + // To maintain ABI compatibility on sparc64 when switching to an int, + // __glibc_reserved0 was added. + int __glibc_reserved0; +#endif + int sa_flags; +#else + unsigned long sa_flags; +#endif +#else + int sa_flags; +#endif +#endif +#endif +#if SANITIZER_LINUX + void (*sa_restorer)(); +#endif +#if defined(__mips__) && (SANITIZER_WORDSIZE == 32) + int sa_resv[1]; +#endif +#if defined(__s390x__) + __sanitizer_sigset_t sa_mask; +#endif +}; +#endif // !SANITIZER_ANDROID + +#if defined(__mips__) +#define __SANITIZER_KERNEL_NSIG 128 +#else +#define __SANITIZER_KERNEL_NSIG 64 +#endif + +struct __sanitizer_kernel_sigset_t { + uptr sig[__SANITIZER_KERNEL_NSIG / (sizeof(uptr) * 8)]; +}; + +// Linux system headers define the 'sa_handler' and 'sa_sigaction' macros. +#if SANITIZER_MIPS +struct __sanitizer_kernel_sigaction_t { + unsigned int sa_flags; + union { + void (*handler)(int signo); + void (*sigaction)(int signo, __sanitizer_siginfo *info, void *ctx); + }; + __sanitizer_kernel_sigset_t sa_mask; + void (*sa_restorer)(void); +}; +#else +struct __sanitizer_kernel_sigaction_t { + union { + void (*handler)(int signo); + void (*sigaction)(int signo, __sanitizer_siginfo *info, void *ctx); + }; + unsigned long sa_flags; + void (*sa_restorer)(void); + __sanitizer_kernel_sigset_t sa_mask; +}; +#endif + +extern const uptr sig_ign; +extern const uptr sig_dfl; +extern const uptr sig_err; +extern const uptr sa_siginfo; + +#if SANITIZER_LINUX +extern int e_tabsz; +#endif + +extern int af_inet; +extern int af_inet6; +uptr __sanitizer_in_addr_sz(int af); + +#if SANITIZER_LINUX +struct __sanitizer_dl_phdr_info { + uptr dlpi_addr; + const char *dlpi_name; + const void *dlpi_phdr; + short dlpi_phnum; +}; + +extern unsigned struct_ElfW_Phdr_sz; +#endif + +struct __sanitizer_protoent { + char *p_name; + char **p_aliases; + int p_proto; +}; + +struct __sanitizer_netent { + char *n_name; + char **n_aliases; + int n_addrtype; + u32 n_net; +}; + +struct __sanitizer_addrinfo { + int ai_flags; + int ai_family; + int ai_socktype; + int ai_protocol; +#if SANITIZER_ANDROID || SANITIZER_MAC + unsigned ai_addrlen; + char *ai_canonname; + void *ai_addr; +#else // LINUX + unsigned ai_addrlen; + void *ai_addr; + char *ai_canonname; +#endif + struct __sanitizer_addrinfo *ai_next; +}; + +struct __sanitizer_hostent { + char *h_name; + char **h_aliases; + int h_addrtype; + int h_length; + char **h_addr_list; +}; + +struct __sanitizer_pollfd { + int fd; + short events; + short revents; +}; + +#if SANITIZER_ANDROID || SANITIZER_MAC +typedef unsigned __sanitizer_nfds_t; +#else +typedef unsigned long __sanitizer_nfds_t; +#endif + +#if !SANITIZER_ANDROID +# if SANITIZER_LINUX +struct __sanitizer_glob_t { + uptr gl_pathc; + char **gl_pathv; + uptr gl_offs; + int gl_flags; + + void (*gl_closedir)(void *dirp); + void *(*gl_readdir)(void *dirp); + void *(*gl_opendir)(const char *); + int (*gl_lstat)(const char *, void *); + int (*gl_stat)(const char *, void *); +}; +# endif // SANITIZER_LINUX + +# if SANITIZER_LINUX +extern int glob_nomatch; +extern int glob_altdirfunc; +# endif +#endif // !SANITIZER_ANDROID + +extern unsigned path_max; + +# if !SANITIZER_ANDROID +extern const int wordexp_wrde_dooffs; +# endif // !SANITIZER_ANDROID + +struct __sanitizer_wordexp_t { + uptr we_wordc; + char **we_wordv; + uptr we_offs; +}; + +#if SANITIZER_LINUX && !SANITIZER_ANDROID +struct __sanitizer_FILE { + int _flags; + char *_IO_read_ptr; + char *_IO_read_end; + char *_IO_read_base; + char *_IO_write_base; + char *_IO_write_ptr; + char *_IO_write_end; + char *_IO_buf_base; + char *_IO_buf_end; + char *_IO_save_base; + char *_IO_backup_base; + char *_IO_save_end; + void *_markers; + __sanitizer_FILE *_chain; + int _fileno; +}; +# define SANITIZER_HAS_STRUCT_FILE 1 +#else +typedef void __sanitizer_FILE; +# define SANITIZER_HAS_STRUCT_FILE 0 +#endif + +#if SANITIZER_LINUX && !SANITIZER_ANDROID && \ + (defined(__i386) || defined(__x86_64) || defined(__mips64) || \ + defined(__powerpc64__) || defined(__aarch64__) || defined(__arm__) || \ + defined(__s390__) || SANITIZER_RISCV64) +extern unsigned struct_user_regs_struct_sz; +extern unsigned struct_user_fpregs_struct_sz; +extern unsigned struct_user_fpxregs_struct_sz; +extern unsigned struct_user_vfpregs_struct_sz; + +extern int ptrace_peektext; +extern int ptrace_peekdata; +extern int ptrace_peekuser; +extern int ptrace_getregs; +extern int ptrace_setregs; +extern int ptrace_getfpregs; +extern int ptrace_setfpregs; +extern int ptrace_getfpxregs; +extern int ptrace_setfpxregs; +extern int ptrace_getvfpregs; +extern int ptrace_setvfpregs; +extern int ptrace_getsiginfo; +extern int ptrace_setsiginfo; +extern int ptrace_getregset; +extern int ptrace_setregset; +extern int ptrace_geteventmsg; +#endif + +#if SANITIZER_LINUX && !SANITIZER_ANDROID +extern unsigned struct_shminfo_sz; +extern unsigned struct_shm_info_sz; +extern int shmctl_ipc_stat; +extern int shmctl_ipc_info; +extern int shmctl_shm_info; +extern int shmctl_shm_stat; +#endif + +#if !SANITIZER_MAC && !SANITIZER_FREEBSD +extern unsigned struct_utmp_sz; +#endif +#if !SANITIZER_ANDROID +extern unsigned struct_utmpx_sz; +#endif + +extern int map_fixed; + +// ioctl arguments +struct __sanitizer_ifconf { + int ifc_len; + union { + void *ifcu_req; + } ifc_ifcu; +#if SANITIZER_MAC +} __attribute__((packed)); +#else +}; +#endif + +#if SANITIZER_LINUX && !SANITIZER_ANDROID +struct __sanitizer__obstack_chunk { + char *limit; + struct __sanitizer__obstack_chunk *prev; +}; + +struct __sanitizer_obstack { + long chunk_size; + struct __sanitizer__obstack_chunk *chunk; + char *object_base; + char *next_free; + uptr more_fields[7]; +}; + +typedef uptr (*__sanitizer_cookie_io_read)(void *cookie, char *buf, uptr size); +typedef uptr (*__sanitizer_cookie_io_write)(void *cookie, const char *buf, + uptr size); +typedef int (*__sanitizer_cookie_io_seek)(void *cookie, u64 *offset, + int whence); +typedef int (*__sanitizer_cookie_io_close)(void *cookie); + +struct __sanitizer_cookie_io_functions_t { + __sanitizer_cookie_io_read read; + __sanitizer_cookie_io_write write; + __sanitizer_cookie_io_seek seek; + __sanitizer_cookie_io_close close; +}; +#endif + +#define IOC_NRBITS 8 +#define IOC_TYPEBITS 8 +#if defined(__powerpc__) || defined(__powerpc64__) || defined(__mips__) || \ + defined(__sparc__) +#define IOC_SIZEBITS 13 +#define IOC_DIRBITS 3 +#define IOC_NONE 1U +#define IOC_WRITE 4U +#define IOC_READ 2U +#else +#define IOC_SIZEBITS 14 +#define IOC_DIRBITS 2 +#define IOC_NONE 0U +#define IOC_WRITE 1U +#define IOC_READ 2U +#endif +#define IOC_NRMASK ((1 << IOC_NRBITS) - 1) +#define IOC_TYPEMASK ((1 << IOC_TYPEBITS) - 1) +#define IOC_SIZEMASK ((1 << IOC_SIZEBITS) - 1) +#if defined(IOC_DIRMASK) +#undef IOC_DIRMASK +#endif +#define IOC_DIRMASK ((1 << IOC_DIRBITS) - 1) +#define IOC_NRSHIFT 0 +#define IOC_TYPESHIFT (IOC_NRSHIFT + IOC_NRBITS) +#define IOC_SIZESHIFT (IOC_TYPESHIFT + IOC_TYPEBITS) +#define IOC_DIRSHIFT (IOC_SIZESHIFT + IOC_SIZEBITS) +#define EVIOC_EV_MAX 0x1f +#define EVIOC_ABS_MAX 0x3f + +#define IOC_DIR(nr) (((nr) >> IOC_DIRSHIFT) & IOC_DIRMASK) +#define IOC_TYPE(nr) (((nr) >> IOC_TYPESHIFT) & IOC_TYPEMASK) +#define IOC_NR(nr) (((nr) >> IOC_NRSHIFT) & IOC_NRMASK) + +#if defined(__sparc__) +// In sparc the 14 bits SIZE field overlaps with the +// least significant bit of DIR, so either IOC_READ or +// IOC_WRITE shall be 1 in order to get a non-zero SIZE. +#define IOC_SIZE(nr) \ + ((((((nr) >> 29) & 0x7) & (4U | 2U)) == 0) ? 0 : (((nr) >> 16) & 0x3fff)) +#else +#define IOC_SIZE(nr) (((nr) >> IOC_SIZESHIFT) & IOC_SIZEMASK) +#endif + +extern unsigned struct_ifreq_sz; +extern unsigned struct_termios_sz; +extern unsigned struct_winsize_sz; + +#if SANITIZER_LINUX +extern unsigned struct_arpreq_sz; +extern unsigned struct_cdrom_msf_sz; +extern unsigned struct_cdrom_multisession_sz; +extern unsigned struct_cdrom_read_audio_sz; +extern unsigned struct_cdrom_subchnl_sz; +extern unsigned struct_cdrom_ti_sz; +extern unsigned struct_cdrom_tocentry_sz; +extern unsigned struct_cdrom_tochdr_sz; +extern unsigned struct_cdrom_volctrl_sz; +extern unsigned struct_ff_effect_sz; +extern unsigned struct_floppy_drive_params_sz; +extern unsigned struct_floppy_drive_struct_sz; +extern unsigned struct_floppy_fdc_state_sz; +extern unsigned struct_floppy_max_errors_sz; +extern unsigned struct_floppy_raw_cmd_sz; +extern unsigned struct_floppy_struct_sz; +extern unsigned struct_floppy_write_errors_sz; +extern unsigned struct_format_descr_sz; +extern unsigned struct_hd_driveid_sz; +extern unsigned struct_hd_geometry_sz; +extern unsigned struct_input_absinfo_sz; +extern unsigned struct_input_id_sz; +extern unsigned struct_mtpos_sz; +extern unsigned struct_termio_sz; +extern unsigned struct_vt_consize_sz; +extern unsigned struct_vt_sizes_sz; +extern unsigned struct_vt_stat_sz; +#endif // SANITIZER_LINUX + +#if SANITIZER_LINUX +extern unsigned struct_copr_buffer_sz; +extern unsigned struct_copr_debug_buf_sz; +extern unsigned struct_copr_msg_sz; +extern unsigned struct_midi_info_sz; +extern unsigned struct_mtget_sz; +extern unsigned struct_mtop_sz; +extern unsigned struct_rtentry_sz; +extern unsigned struct_sbi_instrument_sz; +extern unsigned struct_seq_event_rec_sz; +extern unsigned struct_synth_info_sz; +extern unsigned struct_vt_mode_sz; +#endif // SANITIZER_LINUX + +#if SANITIZER_LINUX && !SANITIZER_ANDROID +extern unsigned struct_ax25_parms_struct_sz; +extern unsigned struct_input_keymap_entry_sz; +extern unsigned struct_ipx_config_data_sz; +extern unsigned struct_kbdiacrs_sz; +extern unsigned struct_kbentry_sz; +extern unsigned struct_kbkeycode_sz; +extern unsigned struct_kbsentry_sz; +extern unsigned struct_mtconfiginfo_sz; +extern unsigned struct_nr_parms_struct_sz; +extern unsigned struct_scc_modem_sz; +extern unsigned struct_scc_stat_sz; +extern unsigned struct_serial_multiport_struct_sz; +extern unsigned struct_serial_struct_sz; +extern unsigned struct_sockaddr_ax25_sz; +extern unsigned struct_unimapdesc_sz; +extern unsigned struct_unimapinit_sz; +#endif // SANITIZER_LINUX && !SANITIZER_ANDROID + +extern const unsigned long __sanitizer_bufsiz; + +#if SANITIZER_LINUX && !SANITIZER_ANDROID +extern unsigned struct_audio_buf_info_sz; +extern unsigned struct_ppp_stats_sz; +#endif // (SANITIZER_LINUX || SANITIZER_FREEBSD) && !SANITIZER_ANDROID + +#if !SANITIZER_ANDROID && !SANITIZER_MAC +extern unsigned struct_sioc_sg_req_sz; +extern unsigned struct_sioc_vif_req_sz; +#endif + +// ioctl request identifiers + +// A special value to mark ioctls that are not present on the target platform, +// when it can not be determined without including any system headers. +extern const unsigned IOCTL_NOT_PRESENT; + +extern unsigned IOCTL_FIOASYNC; +extern unsigned IOCTL_FIOCLEX; +extern unsigned IOCTL_FIOGETOWN; +extern unsigned IOCTL_FIONBIO; +extern unsigned IOCTL_FIONCLEX; +extern unsigned IOCTL_FIOSETOWN; +extern unsigned IOCTL_SIOCADDMULTI; +extern unsigned IOCTL_SIOCATMARK; +extern unsigned IOCTL_SIOCDELMULTI; +extern unsigned IOCTL_SIOCGIFADDR; +extern unsigned IOCTL_SIOCGIFBRDADDR; +extern unsigned IOCTL_SIOCGIFCONF; +extern unsigned IOCTL_SIOCGIFDSTADDR; +extern unsigned IOCTL_SIOCGIFFLAGS; +extern unsigned IOCTL_SIOCGIFMETRIC; +extern unsigned IOCTL_SIOCGIFMTU; +extern unsigned IOCTL_SIOCGIFNETMASK; +extern unsigned IOCTL_SIOCGPGRP; +extern unsigned IOCTL_SIOCSIFADDR; +extern unsigned IOCTL_SIOCSIFBRDADDR; +extern unsigned IOCTL_SIOCSIFDSTADDR; +extern unsigned IOCTL_SIOCSIFFLAGS; +extern unsigned IOCTL_SIOCSIFMETRIC; +extern unsigned IOCTL_SIOCSIFMTU; +extern unsigned IOCTL_SIOCSIFNETMASK; +extern unsigned IOCTL_SIOCSPGRP; +extern unsigned IOCTL_TIOCCONS; +extern unsigned IOCTL_TIOCEXCL; +extern unsigned IOCTL_TIOCGETD; +extern unsigned IOCTL_TIOCGPGRP; +extern unsigned IOCTL_TIOCGWINSZ; +extern unsigned IOCTL_TIOCMBIC; +extern unsigned IOCTL_TIOCMBIS; +extern unsigned IOCTL_TIOCMGET; +extern unsigned IOCTL_TIOCMSET; +extern unsigned IOCTL_TIOCNOTTY; +extern unsigned IOCTL_TIOCNXCL; +extern unsigned IOCTL_TIOCOUTQ; +extern unsigned IOCTL_TIOCPKT; +extern unsigned IOCTL_TIOCSCTTY; +extern unsigned IOCTL_TIOCSETD; +extern unsigned IOCTL_TIOCSPGRP; +extern unsigned IOCTL_TIOCSTI; +extern unsigned IOCTL_TIOCSWINSZ; +#if SANITIZER_LINUX && !SANITIZER_ANDROID +extern unsigned IOCTL_SIOCGETSGCNT; +extern unsigned IOCTL_SIOCGETVIFCNT; +#endif +#if SANITIZER_LINUX +extern unsigned IOCTL_EVIOCGABS; +extern unsigned IOCTL_EVIOCGBIT; +extern unsigned IOCTL_EVIOCGEFFECTS; +extern unsigned IOCTL_EVIOCGID; +extern unsigned IOCTL_EVIOCGKEY; +extern unsigned IOCTL_EVIOCGKEYCODE; +extern unsigned IOCTL_EVIOCGLED; +extern unsigned IOCTL_EVIOCGNAME; +extern unsigned IOCTL_EVIOCGPHYS; +extern unsigned IOCTL_EVIOCGRAB; +extern unsigned IOCTL_EVIOCGREP; +extern unsigned IOCTL_EVIOCGSND; +extern unsigned IOCTL_EVIOCGSW; +extern unsigned IOCTL_EVIOCGUNIQ; +extern unsigned IOCTL_EVIOCGVERSION; +extern unsigned IOCTL_EVIOCRMFF; +extern unsigned IOCTL_EVIOCSABS; +extern unsigned IOCTL_EVIOCSFF; +extern unsigned IOCTL_EVIOCSKEYCODE; +extern unsigned IOCTL_EVIOCSREP; +extern unsigned IOCTL_BLKFLSBUF; +extern unsigned IOCTL_BLKGETSIZE; +extern unsigned IOCTL_BLKRAGET; +extern unsigned IOCTL_BLKRASET; +extern unsigned IOCTL_BLKROGET; +extern unsigned IOCTL_BLKROSET; +extern unsigned IOCTL_BLKRRPART; +extern unsigned IOCTL_CDROMAUDIOBUFSIZ; +extern unsigned IOCTL_CDROMEJECT; +extern unsigned IOCTL_CDROMEJECT_SW; +extern unsigned IOCTL_CDROMMULTISESSION; +extern unsigned IOCTL_CDROMPAUSE; +extern unsigned IOCTL_CDROMPLAYMSF; +extern unsigned IOCTL_CDROMPLAYTRKIND; +extern unsigned IOCTL_CDROMREADAUDIO; +extern unsigned IOCTL_CDROMREADCOOKED; +extern unsigned IOCTL_CDROMREADMODE1; +extern unsigned IOCTL_CDROMREADMODE2; +extern unsigned IOCTL_CDROMREADRAW; +extern unsigned IOCTL_CDROMREADTOCENTRY; +extern unsigned IOCTL_CDROMREADTOCHDR; +extern unsigned IOCTL_CDROMRESET; +extern unsigned IOCTL_CDROMRESUME; +extern unsigned IOCTL_CDROMSEEK; +extern unsigned IOCTL_CDROMSTART; +extern unsigned IOCTL_CDROMSTOP; +extern unsigned IOCTL_CDROMSUBCHNL; +extern unsigned IOCTL_CDROMVOLCTRL; +extern unsigned IOCTL_CDROMVOLREAD; +extern unsigned IOCTL_CDROM_GET_UPC; +extern unsigned IOCTL_FDCLRPRM; +extern unsigned IOCTL_FDDEFPRM; +extern unsigned IOCTL_FDFLUSH; +extern unsigned IOCTL_FDFMTBEG; +extern unsigned IOCTL_FDFMTEND; +extern unsigned IOCTL_FDFMTTRK; +extern unsigned IOCTL_FDGETDRVPRM; +extern unsigned IOCTL_FDGETDRVSTAT; +extern unsigned IOCTL_FDGETDRVTYP; +extern unsigned IOCTL_FDGETFDCSTAT; +extern unsigned IOCTL_FDGETMAXERRS; +extern unsigned IOCTL_FDGETPRM; +extern unsigned IOCTL_FDMSGOFF; +extern unsigned IOCTL_FDMSGON; +extern unsigned IOCTL_FDPOLLDRVSTAT; +extern unsigned IOCTL_FDRAWCMD; +extern unsigned IOCTL_FDRESET; +extern unsigned IOCTL_FDSETDRVPRM; +extern unsigned IOCTL_FDSETEMSGTRESH; +extern unsigned IOCTL_FDSETMAXERRS; +extern unsigned IOCTL_FDSETPRM; +extern unsigned IOCTL_FDTWADDLE; +extern unsigned IOCTL_FDWERRORCLR; +extern unsigned IOCTL_FDWERRORGET; +extern unsigned IOCTL_HDIO_DRIVE_CMD; +extern unsigned IOCTL_HDIO_GETGEO; +extern unsigned IOCTL_HDIO_GET_32BIT; +extern unsigned IOCTL_HDIO_GET_DMA; +extern unsigned IOCTL_HDIO_GET_IDENTITY; +extern unsigned IOCTL_HDIO_GET_KEEPSETTINGS; +extern unsigned IOCTL_HDIO_GET_MULTCOUNT; +extern unsigned IOCTL_HDIO_GET_NOWERR; +extern unsigned IOCTL_HDIO_GET_UNMASKINTR; +extern unsigned IOCTL_HDIO_SET_32BIT; +extern unsigned IOCTL_HDIO_SET_DMA; +extern unsigned IOCTL_HDIO_SET_KEEPSETTINGS; +extern unsigned IOCTL_HDIO_SET_MULTCOUNT; +extern unsigned IOCTL_HDIO_SET_NOWERR; +extern unsigned IOCTL_HDIO_SET_UNMASKINTR; +extern unsigned IOCTL_MTIOCPOS; +extern unsigned IOCTL_PPPIOCGASYNCMAP; +extern unsigned IOCTL_PPPIOCGDEBUG; +extern unsigned IOCTL_PPPIOCGFLAGS; +extern unsigned IOCTL_PPPIOCGUNIT; +extern unsigned IOCTL_PPPIOCGXASYNCMAP; +extern unsigned IOCTL_PPPIOCSASYNCMAP; +extern unsigned IOCTL_PPPIOCSDEBUG; +extern unsigned IOCTL_PPPIOCSFLAGS; +extern unsigned IOCTL_PPPIOCSMAXCID; +extern unsigned IOCTL_PPPIOCSMRU; +extern unsigned IOCTL_PPPIOCSXASYNCMAP; +extern unsigned IOCTL_SIOCDARP; +extern unsigned IOCTL_SIOCDRARP; +extern unsigned IOCTL_SIOCGARP; +extern unsigned IOCTL_SIOCGIFENCAP; +extern unsigned IOCTL_SIOCGIFHWADDR; +extern unsigned IOCTL_SIOCGIFMAP; +extern unsigned IOCTL_SIOCGIFMEM; +extern unsigned IOCTL_SIOCGIFNAME; +extern unsigned IOCTL_SIOCGIFSLAVE; +extern unsigned IOCTL_SIOCGRARP; +extern unsigned IOCTL_SIOCGSTAMP; +extern unsigned IOCTL_SIOCSARP; +extern unsigned IOCTL_SIOCSIFENCAP; +extern unsigned IOCTL_SIOCSIFHWADDR; +extern unsigned IOCTL_SIOCSIFLINK; +extern unsigned IOCTL_SIOCSIFMAP; +extern unsigned IOCTL_SIOCSIFMEM; +extern unsigned IOCTL_SIOCSIFSLAVE; +extern unsigned IOCTL_SIOCSRARP; +extern unsigned IOCTL_SNDCTL_COPR_HALT; +extern unsigned IOCTL_SNDCTL_COPR_LOAD; +extern unsigned IOCTL_SNDCTL_COPR_RCODE; +extern unsigned IOCTL_SNDCTL_COPR_RCVMSG; +extern unsigned IOCTL_SNDCTL_COPR_RDATA; +extern unsigned IOCTL_SNDCTL_COPR_RESET; +extern unsigned IOCTL_SNDCTL_COPR_RUN; +extern unsigned IOCTL_SNDCTL_COPR_SENDMSG; +extern unsigned IOCTL_SNDCTL_COPR_WCODE; +extern unsigned IOCTL_SNDCTL_COPR_WDATA; +extern unsigned IOCTL_TCFLSH; +extern unsigned IOCTL_TCGETA; +extern unsigned IOCTL_TCGETS; +extern unsigned IOCTL_TCSBRK; +extern unsigned IOCTL_TCSBRKP; +extern unsigned IOCTL_TCSETA; +extern unsigned IOCTL_TCSETAF; +extern unsigned IOCTL_TCSETAW; +extern unsigned IOCTL_TCSETS; +extern unsigned IOCTL_TCSETSF; +extern unsigned IOCTL_TCSETSW; +extern unsigned IOCTL_TCXONC; +extern unsigned IOCTL_TIOCGLCKTRMIOS; +extern unsigned IOCTL_TIOCGSOFTCAR; +extern unsigned IOCTL_TIOCINQ; +extern unsigned IOCTL_TIOCLINUX; +extern unsigned IOCTL_TIOCSERCONFIG; +extern unsigned IOCTL_TIOCSERGETLSR; +extern unsigned IOCTL_TIOCSERGWILD; +extern unsigned IOCTL_TIOCSERSWILD; +extern unsigned IOCTL_TIOCSLCKTRMIOS; +extern unsigned IOCTL_TIOCSSOFTCAR; +extern unsigned IOCTL_VT_DISALLOCATE; +extern unsigned IOCTL_VT_GETSTATE; +extern unsigned IOCTL_VT_RESIZE; +extern unsigned IOCTL_VT_RESIZEX; +extern unsigned IOCTL_VT_SENDSIG; +extern unsigned IOCTL_MTIOCGET; +extern unsigned IOCTL_MTIOCTOP; +extern unsigned IOCTL_SIOCADDRT; +extern unsigned IOCTL_SIOCDELRT; +extern unsigned IOCTL_SNDCTL_DSP_GETBLKSIZE; +extern unsigned IOCTL_SNDCTL_DSP_GETFMTS; +extern unsigned IOCTL_SNDCTL_DSP_NONBLOCK; +extern unsigned IOCTL_SNDCTL_DSP_POST; +extern unsigned IOCTL_SNDCTL_DSP_RESET; +extern unsigned IOCTL_SNDCTL_DSP_SETFMT; +extern unsigned IOCTL_SNDCTL_DSP_SETFRAGMENT; +extern unsigned IOCTL_SNDCTL_DSP_SPEED; +extern unsigned IOCTL_SNDCTL_DSP_STEREO; +extern unsigned IOCTL_SNDCTL_DSP_SUBDIVIDE; +extern unsigned IOCTL_SNDCTL_DSP_SYNC; +extern unsigned IOCTL_SNDCTL_FM_4OP_ENABLE; +extern unsigned IOCTL_SNDCTL_FM_LOAD_INSTR; +extern unsigned IOCTL_SNDCTL_MIDI_INFO; +extern unsigned IOCTL_SNDCTL_MIDI_PRETIME; +extern unsigned IOCTL_SNDCTL_SEQ_CTRLRATE; +extern unsigned IOCTL_SNDCTL_SEQ_GETINCOUNT; +extern unsigned IOCTL_SNDCTL_SEQ_GETOUTCOUNT; +extern unsigned IOCTL_SNDCTL_SEQ_NRMIDIS; +extern unsigned IOCTL_SNDCTL_SEQ_NRSYNTHS; +extern unsigned IOCTL_SNDCTL_SEQ_OUTOFBAND; +extern unsigned IOCTL_SNDCTL_SEQ_PANIC; +extern unsigned IOCTL_SNDCTL_SEQ_PERCMODE; +extern unsigned IOCTL_SNDCTL_SEQ_RESET; +extern unsigned IOCTL_SNDCTL_SEQ_RESETSAMPLES; +extern unsigned IOCTL_SNDCTL_SEQ_SYNC; +extern unsigned IOCTL_SNDCTL_SEQ_TESTMIDI; +extern unsigned IOCTL_SNDCTL_SEQ_THRESHOLD; +extern unsigned IOCTL_SNDCTL_SYNTH_INFO; +extern unsigned IOCTL_SNDCTL_SYNTH_MEMAVL; +extern unsigned IOCTL_SNDCTL_TMR_CONTINUE; +extern unsigned IOCTL_SNDCTL_TMR_METRONOME; +extern unsigned IOCTL_SNDCTL_TMR_SELECT; +extern unsigned IOCTL_SNDCTL_TMR_SOURCE; +extern unsigned IOCTL_SNDCTL_TMR_START; +extern unsigned IOCTL_SNDCTL_TMR_STOP; +extern unsigned IOCTL_SNDCTL_TMR_TEMPO; +extern unsigned IOCTL_SNDCTL_TMR_TIMEBASE; +extern unsigned IOCTL_SOUND_MIXER_READ_ALTPCM; +extern unsigned IOCTL_SOUND_MIXER_READ_BASS; +extern unsigned IOCTL_SOUND_MIXER_READ_CAPS; +extern unsigned IOCTL_SOUND_MIXER_READ_CD; +extern unsigned IOCTL_SOUND_MIXER_READ_DEVMASK; +extern unsigned IOCTL_SOUND_MIXER_READ_ENHANCE; +extern unsigned IOCTL_SOUND_MIXER_READ_IGAIN; +extern unsigned IOCTL_SOUND_MIXER_READ_IMIX; +extern unsigned IOCTL_SOUND_MIXER_READ_LINE1; +extern unsigned IOCTL_SOUND_MIXER_READ_LINE2; +extern unsigned IOCTL_SOUND_MIXER_READ_LINE3; +extern unsigned IOCTL_SOUND_MIXER_READ_LINE; +extern unsigned IOCTL_SOUND_MIXER_READ_LOUD; +extern unsigned IOCTL_SOUND_MIXER_READ_MIC; +extern unsigned IOCTL_SOUND_MIXER_READ_MUTE; +extern unsigned IOCTL_SOUND_MIXER_READ_OGAIN; +extern unsigned IOCTL_SOUND_MIXER_READ_PCM; +extern unsigned IOCTL_SOUND_MIXER_READ_RECLEV; +extern unsigned IOCTL_SOUND_MIXER_READ_RECMASK; +extern unsigned IOCTL_SOUND_MIXER_READ_RECSRC; +extern unsigned IOCTL_SOUND_MIXER_READ_SPEAKER; +extern unsigned IOCTL_SOUND_MIXER_READ_STEREODEVS; +extern unsigned IOCTL_SOUND_MIXER_READ_SYNTH; +extern unsigned IOCTL_SOUND_MIXER_READ_TREBLE; +extern unsigned IOCTL_SOUND_MIXER_READ_VOLUME; +extern unsigned IOCTL_SOUND_MIXER_WRITE_ALTPCM; +extern unsigned IOCTL_SOUND_MIXER_WRITE_BASS; +extern unsigned IOCTL_SOUND_MIXER_WRITE_CD; +extern unsigned IOCTL_SOUND_MIXER_WRITE_ENHANCE; +extern unsigned IOCTL_SOUND_MIXER_WRITE_IGAIN; +extern unsigned IOCTL_SOUND_MIXER_WRITE_IMIX; +extern unsigned IOCTL_SOUND_MIXER_WRITE_LINE1; +extern unsigned IOCTL_SOUND_MIXER_WRITE_LINE2; +extern unsigned IOCTL_SOUND_MIXER_WRITE_LINE3; +extern unsigned IOCTL_SOUND_MIXER_WRITE_LINE; +extern unsigned IOCTL_SOUND_MIXER_WRITE_LOUD; +extern unsigned IOCTL_SOUND_MIXER_WRITE_MIC; +extern unsigned IOCTL_SOUND_MIXER_WRITE_MUTE; +extern unsigned IOCTL_SOUND_MIXER_WRITE_OGAIN; +extern unsigned IOCTL_SOUND_MIXER_WRITE_PCM; +extern unsigned IOCTL_SOUND_MIXER_WRITE_RECLEV; +extern unsigned IOCTL_SOUND_MIXER_WRITE_RECSRC; +extern unsigned IOCTL_SOUND_MIXER_WRITE_SPEAKER; +extern unsigned IOCTL_SOUND_MIXER_WRITE_SYNTH; +extern unsigned IOCTL_SOUND_MIXER_WRITE_TREBLE; +extern unsigned IOCTL_SOUND_MIXER_WRITE_VOLUME; +extern unsigned IOCTL_SOUND_PCM_READ_BITS; +extern unsigned IOCTL_SOUND_PCM_READ_CHANNELS; +extern unsigned IOCTL_SOUND_PCM_READ_FILTER; +extern unsigned IOCTL_SOUND_PCM_READ_RATE; +extern unsigned IOCTL_SOUND_PCM_WRITE_CHANNELS; +extern unsigned IOCTL_SOUND_PCM_WRITE_FILTER; +extern unsigned IOCTL_VT_ACTIVATE; +extern unsigned IOCTL_VT_GETMODE; +extern unsigned IOCTL_VT_OPENQRY; +extern unsigned IOCTL_VT_RELDISP; +extern unsigned IOCTL_VT_SETMODE; +extern unsigned IOCTL_VT_WAITACTIVE; +#endif // SANITIZER_LINUX + +#if SANITIZER_LINUX && !SANITIZER_ANDROID +extern unsigned IOCTL_EQL_EMANCIPATE; +extern unsigned IOCTL_EQL_ENSLAVE; +extern unsigned IOCTL_EQL_GETMASTRCFG; +extern unsigned IOCTL_EQL_GETSLAVECFG; +extern unsigned IOCTL_EQL_SETMASTRCFG; +extern unsigned IOCTL_EQL_SETSLAVECFG; +extern unsigned IOCTL_EVIOCGKEYCODE_V2; +extern unsigned IOCTL_EVIOCGPROP; +extern unsigned IOCTL_EVIOCSKEYCODE_V2; +extern unsigned IOCTL_FS_IOC_GETFLAGS; +extern unsigned IOCTL_FS_IOC_GETVERSION; +extern unsigned IOCTL_FS_IOC_SETFLAGS; +extern unsigned IOCTL_FS_IOC_SETVERSION; +extern unsigned IOCTL_GIO_CMAP; +extern unsigned IOCTL_GIO_FONT; +extern unsigned IOCTL_GIO_UNIMAP; +extern unsigned IOCTL_GIO_UNISCRNMAP; +extern unsigned IOCTL_KDADDIO; +extern unsigned IOCTL_KDDELIO; +extern unsigned IOCTL_KDGETKEYCODE; +extern unsigned IOCTL_KDGKBDIACR; +extern unsigned IOCTL_KDGKBENT; +extern unsigned IOCTL_KDGKBLED; +extern unsigned IOCTL_KDGKBMETA; +extern unsigned IOCTL_KDGKBSENT; +extern unsigned IOCTL_KDMAPDISP; +extern unsigned IOCTL_KDSETKEYCODE; +extern unsigned IOCTL_KDSIGACCEPT; +extern unsigned IOCTL_KDSKBDIACR; +extern unsigned IOCTL_KDSKBENT; +extern unsigned IOCTL_KDSKBLED; +extern unsigned IOCTL_KDSKBMETA; +extern unsigned IOCTL_KDSKBSENT; +extern unsigned IOCTL_KDUNMAPDISP; +extern unsigned IOCTL_LPABORT; +extern unsigned IOCTL_LPABORTOPEN; +extern unsigned IOCTL_LPCAREFUL; +extern unsigned IOCTL_LPCHAR; +extern unsigned IOCTL_LPGETIRQ; +extern unsigned IOCTL_LPGETSTATUS; +extern unsigned IOCTL_LPRESET; +extern unsigned IOCTL_LPSETIRQ; +extern unsigned IOCTL_LPTIME; +extern unsigned IOCTL_LPWAIT; +extern unsigned IOCTL_MTIOCGETCONFIG; +extern unsigned IOCTL_MTIOCSETCONFIG; +extern unsigned IOCTL_PIO_CMAP; +extern unsigned IOCTL_PIO_FONT; +extern unsigned IOCTL_PIO_UNIMAP; +extern unsigned IOCTL_PIO_UNIMAPCLR; +extern unsigned IOCTL_PIO_UNISCRNMAP; +extern unsigned IOCTL_SCSI_IOCTL_GET_IDLUN; +extern unsigned IOCTL_SCSI_IOCTL_PROBE_HOST; +extern unsigned IOCTL_SCSI_IOCTL_TAGGED_DISABLE; +extern unsigned IOCTL_SCSI_IOCTL_TAGGED_ENABLE; +extern unsigned IOCTL_SIOCAIPXITFCRT; +extern unsigned IOCTL_SIOCAIPXPRISLT; +extern unsigned IOCTL_SIOCAX25ADDUID; +extern unsigned IOCTL_SIOCAX25DELUID; +extern unsigned IOCTL_SIOCAX25GETPARMS; +extern unsigned IOCTL_SIOCAX25GETUID; +extern unsigned IOCTL_SIOCAX25NOUID; +extern unsigned IOCTL_SIOCAX25SETPARMS; +extern unsigned IOCTL_SIOCDEVPLIP; +extern unsigned IOCTL_SIOCIPXCFGDATA; +extern unsigned IOCTL_SIOCNRDECOBS; +extern unsigned IOCTL_SIOCNRGETPARMS; +extern unsigned IOCTL_SIOCNRRTCTL; +extern unsigned IOCTL_SIOCNRSETPARMS; +extern unsigned IOCTL_SNDCTL_DSP_GETISPACE; +extern unsigned IOCTL_SNDCTL_DSP_GETOSPACE; +extern unsigned IOCTL_TIOCGSERIAL; +extern unsigned IOCTL_TIOCSERGETMULTI; +extern unsigned IOCTL_TIOCSERSETMULTI; +extern unsigned IOCTL_TIOCSSERIAL; +extern unsigned IOCTL_GIO_SCRNMAP; +extern unsigned IOCTL_KDDISABIO; +extern unsigned IOCTL_KDENABIO; +extern unsigned IOCTL_KDGETLED; +extern unsigned IOCTL_KDGETMODE; +extern unsigned IOCTL_KDGKBMODE; +extern unsigned IOCTL_KDGKBTYPE; +extern unsigned IOCTL_KDMKTONE; +extern unsigned IOCTL_KDSETLED; +extern unsigned IOCTL_KDSETMODE; +extern unsigned IOCTL_KDSKBMODE; +extern unsigned IOCTL_KIOCSOUND; +extern unsigned IOCTL_PIO_SCRNMAP; +#endif + +extern const int si_SEGV_MAPERR; +extern const int si_SEGV_ACCERR; +} // namespace __sanitizer + +#define CHECK_TYPE_SIZE(TYPE) \ + COMPILER_CHECK(sizeof(__sanitizer_##TYPE) == sizeof(TYPE)) + +#define CHECK_SIZE_AND_OFFSET(CLASS, MEMBER) \ + COMPILER_CHECK(sizeof(((__sanitizer_##CLASS *)NULL)->MEMBER) == \ + sizeof(((CLASS *)NULL)->MEMBER)); \ + COMPILER_CHECK(offsetof(__sanitizer_##CLASS, MEMBER) == \ + offsetof(CLASS, MEMBER)) + +// For sigaction, which is a function and struct at the same time, +// and thus requires explicit "struct" in sizeof() expression. +#define CHECK_STRUCT_SIZE_AND_OFFSET(CLASS, MEMBER) \ + COMPILER_CHECK(sizeof(((struct __sanitizer_##CLASS *)NULL)->MEMBER) == \ + sizeof(((struct CLASS *)NULL)->MEMBER)); \ + COMPILER_CHECK(offsetof(struct __sanitizer_##CLASS, MEMBER) == \ + offsetof(struct CLASS, MEMBER)) + +#define SIGACTION_SYMNAME sigaction + +#endif // SANITIZER_LINUX || SANITIZER_MAC + +#endif diff --git a/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_platform_limits_solaris.cpp b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_platform_limits_solaris.cpp new file mode 100644 index 0000000000..f1391a16bf --- /dev/null +++ b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_platform_limits_solaris.cpp @@ -0,0 +1,368 @@ +//===-- sanitizer_platform_limits_solaris.cpp -----------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file is a part of Sanitizer common code. +// +// Sizes and layouts of platform-specific Solaris data structures. +//===----------------------------------------------------------------------===// + +#include "sanitizer_platform.h" + +#if SANITIZER_SOLARIS +#include <arpa/inet.h> +#include <dirent.h> +#include <glob.h> +#include <grp.h> +#include <ifaddrs.h> +#include <limits.h> +#include <link.h> +#include <net/if.h> +#include <net/route.h> +#include <netdb.h> +#error #include <netinet/ip_mroute.h> +#include <poll.h> +#include <pthread.h> +#include <pwd.h> +#error #include <rpc/xdr.h> +#include <semaphore.h> +#include <signal.h> +#include <stddef.h> +#include <sys/ethernet.h> +#include <sys/filio.h> +#include <sys/ipc.h> +#include <sys/mman.h> +#include <sys/mount.h> +#include <sys/mtio.h> +#error #include <sys/ptyvar.h> +#include <sys/resource.h> +#include <sys/shm.h> +#include <sys/socket.h> +#include <sys/sockio.h> +#include <sys/stat.h> +#include <sys/statfs.h> +#include <sys/statvfs.h> +#include <sys/time.h> +#include <sys/timeb.h> +#include <sys/times.h> +#include <sys/types.h> +#include <sys/utsname.h> +#include <termios.h> +#include <time.h> +#include <utmp.h> +#include <utmpx.h> +#include <wchar.h> +#include <wordexp.h> + +// Include these after system headers to avoid name clashes and ambiguities. +#include "sanitizer_internal_defs.h" +#include "sanitizer_platform_limits_solaris.h" + +namespace __sanitizer { + unsigned struct_utsname_sz = sizeof(struct utsname); + unsigned struct_stat_sz = sizeof(struct stat); + unsigned struct_stat64_sz = sizeof(struct stat64); + unsigned struct_rusage_sz = sizeof(struct rusage); + unsigned struct_tm_sz = sizeof(struct tm); + unsigned struct_passwd_sz = sizeof(struct passwd); + unsigned struct_group_sz = sizeof(struct group); + unsigned siginfo_t_sz = sizeof(siginfo_t); + unsigned struct_sigaction_sz = sizeof(struct sigaction); + unsigned struct_stack_t_sz = sizeof(stack_t); + unsigned struct_itimerval_sz = sizeof(struct itimerval); + unsigned pthread_t_sz = sizeof(pthread_t); + unsigned pthread_mutex_t_sz = sizeof(pthread_mutex_t); + unsigned pthread_cond_t_sz = sizeof(pthread_cond_t); + unsigned pid_t_sz = sizeof(pid_t); + unsigned timeval_sz = sizeof(timeval); + unsigned uid_t_sz = sizeof(uid_t); + unsigned gid_t_sz = sizeof(gid_t); + unsigned mbstate_t_sz = sizeof(mbstate_t); + unsigned sigset_t_sz = sizeof(sigset_t); + unsigned struct_timezone_sz = sizeof(struct timezone); + unsigned struct_tms_sz = sizeof(struct tms); + unsigned struct_sigevent_sz = sizeof(struct sigevent); + unsigned struct_sched_param_sz = sizeof(struct sched_param); + unsigned struct_statfs_sz = sizeof(struct statfs); + unsigned struct_sockaddr_sz = sizeof(struct sockaddr); + unsigned ucontext_t_sz(void *ctx) { return sizeof(ucontext_t); } + unsigned struct_timespec_sz = sizeof(struct timespec); +#if SANITIZER_SOLARIS32 + unsigned struct_statvfs64_sz = sizeof(struct statvfs64); +#endif + unsigned struct_statvfs_sz = sizeof(struct statvfs); + + const uptr sig_ign = (uptr)SIG_IGN; + const uptr sig_dfl = (uptr)SIG_DFL; + const uptr sig_err = (uptr)SIG_ERR; + const uptr sa_siginfo = (uptr)SA_SIGINFO; + + int shmctl_ipc_stat = (int)IPC_STAT; + + unsigned struct_utmp_sz = sizeof(struct utmp); + unsigned struct_utmpx_sz = sizeof(struct utmpx); + + int map_fixed = MAP_FIXED; + + int af_inet = (int)AF_INET; + int af_inet6 = (int)AF_INET6; + + uptr __sanitizer_in_addr_sz(int af) { + if (af == AF_INET) + return sizeof(struct in_addr); + else if (af == AF_INET6) + return sizeof(struct in6_addr); + else + return 0; + } + + unsigned struct_ElfW_Phdr_sz = sizeof(ElfW(Phdr)); + + int glob_nomatch = GLOB_NOMATCH; + const int wordexp_wrde_dooffs = WRDE_DOOFFS; + + unsigned path_max = PATH_MAX; + + // ioctl arguments + unsigned struct_ifreq_sz = sizeof(struct ifreq); + unsigned struct_termios_sz = sizeof(struct termios); + unsigned struct_winsize_sz = sizeof(struct winsize); + + unsigned struct_sioc_sg_req_sz = sizeof(struct sioc_sg_req); + unsigned struct_sioc_vif_req_sz = sizeof(struct sioc_vif_req); + + const unsigned IOCTL_NOT_PRESENT = 0; + + unsigned IOCTL_FIOASYNC = FIOASYNC; + unsigned IOCTL_FIOCLEX = FIOCLEX; + unsigned IOCTL_FIOGETOWN = FIOGETOWN; + unsigned IOCTL_FIONBIO = FIONBIO; + unsigned IOCTL_FIONCLEX = FIONCLEX; + unsigned IOCTL_FIOSETOWN = FIOSETOWN; + unsigned IOCTL_SIOCADDMULTI = SIOCADDMULTI; + unsigned IOCTL_SIOCATMARK = SIOCATMARK; + unsigned IOCTL_SIOCDELMULTI = SIOCDELMULTI; + unsigned IOCTL_SIOCGIFADDR = SIOCGIFADDR; + unsigned IOCTL_SIOCGIFBRDADDR = SIOCGIFBRDADDR; + unsigned IOCTL_SIOCGIFCONF = SIOCGIFCONF; + unsigned IOCTL_SIOCGIFDSTADDR = SIOCGIFDSTADDR; + unsigned IOCTL_SIOCGIFFLAGS = SIOCGIFFLAGS; + unsigned IOCTL_SIOCGIFMETRIC = SIOCGIFMETRIC; + unsigned IOCTL_SIOCGIFMTU = SIOCGIFMTU; + unsigned IOCTL_SIOCGIFNETMASK = SIOCGIFNETMASK; + unsigned IOCTL_SIOCGPGRP = SIOCGPGRP; + unsigned IOCTL_SIOCSIFADDR = SIOCSIFADDR; + unsigned IOCTL_SIOCSIFBRDADDR = SIOCSIFBRDADDR; + unsigned IOCTL_SIOCSIFDSTADDR = SIOCSIFDSTADDR; + unsigned IOCTL_SIOCSIFFLAGS = SIOCSIFFLAGS; + unsigned IOCTL_SIOCSIFMETRIC = SIOCSIFMETRIC; + unsigned IOCTL_SIOCSIFMTU = SIOCSIFMTU; + unsigned IOCTL_SIOCSIFNETMASK = SIOCSIFNETMASK; + unsigned IOCTL_SIOCSPGRP = SIOCSPGRP; + unsigned IOCTL_TIOCEXCL = TIOCEXCL; + unsigned IOCTL_TIOCGETD = TIOCGETD; + unsigned IOCTL_TIOCGPGRP = TIOCGPGRP; + unsigned IOCTL_TIOCGWINSZ = TIOCGWINSZ; + unsigned IOCTL_TIOCMBIC = TIOCMBIC; + unsigned IOCTL_TIOCMBIS = TIOCMBIS; + unsigned IOCTL_TIOCMGET = TIOCMGET; + unsigned IOCTL_TIOCMSET = TIOCMSET; + unsigned IOCTL_TIOCNOTTY = TIOCNOTTY; + unsigned IOCTL_TIOCNXCL = TIOCNXCL; + unsigned IOCTL_TIOCOUTQ = TIOCOUTQ; + unsigned IOCTL_TIOCPKT = TIOCPKT; + unsigned IOCTL_TIOCSCTTY = TIOCSCTTY; + unsigned IOCTL_TIOCSETD = TIOCSETD; + unsigned IOCTL_TIOCSPGRP = TIOCSPGRP; + unsigned IOCTL_TIOCSTI = TIOCSTI; + unsigned IOCTL_TIOCSWINSZ = TIOCSWINSZ; + + unsigned IOCTL_MTIOCGET = MTIOCGET; + unsigned IOCTL_MTIOCTOP = MTIOCTOP; + + const int si_SEGV_MAPERR = SEGV_MAPERR; + const int si_SEGV_ACCERR = SEGV_ACCERR; +} // namespace __sanitizer + +using namespace __sanitizer; + +COMPILER_CHECK(sizeof(__sanitizer_pthread_attr_t) >= sizeof(pthread_attr_t)); + +COMPILER_CHECK(sizeof(socklen_t) == sizeof(unsigned)); +CHECK_TYPE_SIZE(pthread_key_t); + +// There are more undocumented fields in dl_phdr_info that we are not interested +// in. +COMPILER_CHECK(sizeof(__sanitizer_dl_phdr_info) <= sizeof(dl_phdr_info)); +CHECK_SIZE_AND_OFFSET(dl_phdr_info, dlpi_addr); +CHECK_SIZE_AND_OFFSET(dl_phdr_info, dlpi_name); +CHECK_SIZE_AND_OFFSET(dl_phdr_info, dlpi_phdr); +CHECK_SIZE_AND_OFFSET(dl_phdr_info, dlpi_phnum); + +// There are additional fields we are not interested in. +COMPILER_CHECK(sizeof(__sanitizer_glob_t) <= sizeof(glob_t)); +CHECK_SIZE_AND_OFFSET(glob_t, gl_pathc); +CHECK_SIZE_AND_OFFSET(glob_t, gl_pathv); +CHECK_SIZE_AND_OFFSET(glob_t, gl_offs); + +CHECK_TYPE_SIZE(addrinfo); +CHECK_SIZE_AND_OFFSET(addrinfo, ai_flags); +CHECK_SIZE_AND_OFFSET(addrinfo, ai_family); +CHECK_SIZE_AND_OFFSET(addrinfo, ai_socktype); +CHECK_SIZE_AND_OFFSET(addrinfo, ai_protocol); +CHECK_SIZE_AND_OFFSET(addrinfo, ai_protocol); +CHECK_SIZE_AND_OFFSET(addrinfo, ai_addrlen); +CHECK_SIZE_AND_OFFSET(addrinfo, ai_canonname); +CHECK_SIZE_AND_OFFSET(addrinfo, ai_addr); + +CHECK_TYPE_SIZE(hostent); +CHECK_SIZE_AND_OFFSET(hostent, h_name); +CHECK_SIZE_AND_OFFSET(hostent, h_aliases); +CHECK_SIZE_AND_OFFSET(hostent, h_addrtype); +CHECK_SIZE_AND_OFFSET(hostent, h_length); +CHECK_SIZE_AND_OFFSET(hostent, h_addr_list); + +CHECK_TYPE_SIZE(iovec); +CHECK_SIZE_AND_OFFSET(iovec, iov_base); +CHECK_SIZE_AND_OFFSET(iovec, iov_len); + +CHECK_TYPE_SIZE(msghdr); +CHECK_SIZE_AND_OFFSET(msghdr, msg_name); +CHECK_SIZE_AND_OFFSET(msghdr, msg_namelen); +CHECK_SIZE_AND_OFFSET(msghdr, msg_iov); +CHECK_SIZE_AND_OFFSET(msghdr, msg_iovlen); +CHECK_SIZE_AND_OFFSET(msghdr, msg_control); +CHECK_SIZE_AND_OFFSET(msghdr, msg_controllen); +CHECK_SIZE_AND_OFFSET(msghdr, msg_flags); + +CHECK_TYPE_SIZE(cmsghdr); +CHECK_SIZE_AND_OFFSET(cmsghdr, cmsg_len); +CHECK_SIZE_AND_OFFSET(cmsghdr, cmsg_level); +CHECK_SIZE_AND_OFFSET(cmsghdr, cmsg_type); + +COMPILER_CHECK(sizeof(__sanitizer_dirent) <= sizeof(dirent)); +CHECK_SIZE_AND_OFFSET(dirent, d_ino); +CHECK_SIZE_AND_OFFSET(dirent, d_off); +CHECK_SIZE_AND_OFFSET(dirent, d_reclen); + +#if SANITIZER_SOLARIS32 +COMPILER_CHECK(sizeof(__sanitizer_dirent64) <= sizeof(dirent64)); +CHECK_SIZE_AND_OFFSET(dirent64, d_ino); +CHECK_SIZE_AND_OFFSET(dirent64, d_off); +CHECK_SIZE_AND_OFFSET(dirent64, d_reclen); +#endif + +CHECK_TYPE_SIZE(ifconf); +CHECK_SIZE_AND_OFFSET(ifconf, ifc_len); +CHECK_SIZE_AND_OFFSET(ifconf, ifc_ifcu); + +CHECK_TYPE_SIZE(pollfd); +CHECK_SIZE_AND_OFFSET(pollfd, fd); +CHECK_SIZE_AND_OFFSET(pollfd, events); +CHECK_SIZE_AND_OFFSET(pollfd, revents); + +CHECK_TYPE_SIZE(nfds_t); + +CHECK_TYPE_SIZE(sigset_t); + +COMPILER_CHECK(sizeof(__sanitizer_sigaction) == sizeof(struct sigaction)); +// Can't write checks for sa_handler and sa_sigaction due to them being +// preprocessor macros. +CHECK_STRUCT_SIZE_AND_OFFSET(sigaction, sa_mask); +CHECK_STRUCT_SIZE_AND_OFFSET(sigaction, sa_flags); + +CHECK_TYPE_SIZE(wordexp_t); +CHECK_SIZE_AND_OFFSET(wordexp_t, we_wordc); +CHECK_SIZE_AND_OFFSET(wordexp_t, we_wordv); +CHECK_SIZE_AND_OFFSET(wordexp_t, we_offs); + +CHECK_TYPE_SIZE(tm); +CHECK_SIZE_AND_OFFSET(tm, tm_sec); +CHECK_SIZE_AND_OFFSET(tm, tm_min); +CHECK_SIZE_AND_OFFSET(tm, tm_hour); +CHECK_SIZE_AND_OFFSET(tm, tm_mday); +CHECK_SIZE_AND_OFFSET(tm, tm_mon); +CHECK_SIZE_AND_OFFSET(tm, tm_year); +CHECK_SIZE_AND_OFFSET(tm, tm_wday); +CHECK_SIZE_AND_OFFSET(tm, tm_yday); +CHECK_SIZE_AND_OFFSET(tm, tm_isdst); + +CHECK_TYPE_SIZE(ether_addr); + +CHECK_TYPE_SIZE(ipc_perm); +CHECK_SIZE_AND_OFFSET(ipc_perm, key); +CHECK_SIZE_AND_OFFSET(ipc_perm, seq); +CHECK_SIZE_AND_OFFSET(ipc_perm, uid); +CHECK_SIZE_AND_OFFSET(ipc_perm, gid); +CHECK_SIZE_AND_OFFSET(ipc_perm, cuid); +CHECK_SIZE_AND_OFFSET(ipc_perm, cgid); +CHECK_SIZE_AND_OFFSET(ipc_perm, mode); + +CHECK_TYPE_SIZE(shmid_ds); +CHECK_SIZE_AND_OFFSET(shmid_ds, shm_perm); +CHECK_SIZE_AND_OFFSET(shmid_ds, shm_segsz); +CHECK_SIZE_AND_OFFSET(shmid_ds, shm_atime); +CHECK_SIZE_AND_OFFSET(shmid_ds, shm_dtime); +CHECK_SIZE_AND_OFFSET(shmid_ds, shm_ctime); +CHECK_SIZE_AND_OFFSET(shmid_ds, shm_cpid); +CHECK_SIZE_AND_OFFSET(shmid_ds, shm_lpid); +CHECK_SIZE_AND_OFFSET(shmid_ds, shm_nattch); + +CHECK_TYPE_SIZE(clock_t); + +CHECK_TYPE_SIZE(ifaddrs); +CHECK_SIZE_AND_OFFSET(ifaddrs, ifa_next); +CHECK_SIZE_AND_OFFSET(ifaddrs, ifa_name); +CHECK_SIZE_AND_OFFSET(ifaddrs, ifa_addr); +CHECK_SIZE_AND_OFFSET(ifaddrs, ifa_netmask); +// Compare against the union, because we can't reach into the union in a +// compliant way. +#ifdef ifa_dstaddr +#undef ifa_dstaddr +#endif +COMPILER_CHECK(sizeof(((__sanitizer_ifaddrs *)nullptr)->ifa_dstaddr) == + sizeof(((ifaddrs *)nullptr)->ifa_ifu)); +COMPILER_CHECK(offsetof(__sanitizer_ifaddrs, ifa_dstaddr) == + offsetof(ifaddrs, ifa_ifu)); +CHECK_SIZE_AND_OFFSET(ifaddrs, ifa_data); + +CHECK_TYPE_SIZE(timeb); +CHECK_SIZE_AND_OFFSET(timeb, time); +CHECK_SIZE_AND_OFFSET(timeb, millitm); +CHECK_SIZE_AND_OFFSET(timeb, timezone); +CHECK_SIZE_AND_OFFSET(timeb, dstflag); + +CHECK_TYPE_SIZE(passwd); +CHECK_SIZE_AND_OFFSET(passwd, pw_name); +CHECK_SIZE_AND_OFFSET(passwd, pw_passwd); +CHECK_SIZE_AND_OFFSET(passwd, pw_uid); +CHECK_SIZE_AND_OFFSET(passwd, pw_gid); +CHECK_SIZE_AND_OFFSET(passwd, pw_dir); +CHECK_SIZE_AND_OFFSET(passwd, pw_shell); + +CHECK_SIZE_AND_OFFSET(passwd, pw_gecos); + +CHECK_TYPE_SIZE(group); +CHECK_SIZE_AND_OFFSET(group, gr_name); +CHECK_SIZE_AND_OFFSET(group, gr_passwd); +CHECK_SIZE_AND_OFFSET(group, gr_gid); +CHECK_SIZE_AND_OFFSET(group, gr_mem); + +CHECK_TYPE_SIZE(XDR); +CHECK_SIZE_AND_OFFSET(XDR, x_op); +CHECK_SIZE_AND_OFFSET(XDR, x_ops); +CHECK_SIZE_AND_OFFSET(XDR, x_public); +CHECK_SIZE_AND_OFFSET(XDR, x_private); +CHECK_SIZE_AND_OFFSET(XDR, x_base); +CHECK_SIZE_AND_OFFSET(XDR, x_handy); +COMPILER_CHECK(__sanitizer_XDR_ENCODE == XDR_ENCODE); +COMPILER_CHECK(__sanitizer_XDR_DECODE == XDR_DECODE); +COMPILER_CHECK(__sanitizer_XDR_FREE == XDR_FREE); + +CHECK_TYPE_SIZE(sem_t); + +#endif // SANITIZER_SOLARIS diff --git a/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_platform_limits_solaris.h b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_platform_limits_solaris.h new file mode 100644 index 0000000000..84a8126516 --- /dev/null +++ b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_platform_limits_solaris.h @@ -0,0 +1,496 @@ +//===-- sanitizer_platform_limits_solaris.h -------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file is a part of Sanitizer common code. +// +// Sizes and layouts of platform-specific Solaris data structures. +//===----------------------------------------------------------------------===// + +#ifndef SANITIZER_PLATFORM_LIMITS_SOLARIS_H +#define SANITIZER_PLATFORM_LIMITS_SOLARIS_H + +#if SANITIZER_SOLARIS + +#include "sanitizer_internal_defs.h" +#include "sanitizer_platform.h" + +namespace __sanitizer { +extern unsigned struct_utsname_sz; +extern unsigned struct_stat_sz; +extern unsigned struct_stat64_sz; +extern unsigned struct_rusage_sz; +extern unsigned siginfo_t_sz; +extern unsigned struct_itimerval_sz; +extern unsigned pthread_t_sz; +extern unsigned pthread_mutex_t_sz; +extern unsigned pthread_cond_t_sz; +extern unsigned pid_t_sz; +extern unsigned timeval_sz; +extern unsigned uid_t_sz; +extern unsigned gid_t_sz; +extern unsigned mbstate_t_sz; +extern unsigned struct_timezone_sz; +extern unsigned struct_tms_sz; +extern unsigned struct_itimerspec_sz; +extern unsigned struct_sigevent_sz; +extern unsigned struct_stack_t_sz; +extern unsigned struct_sched_param_sz; +extern unsigned struct_statfs64_sz; +extern unsigned struct_statfs_sz; +extern unsigned struct_sockaddr_sz; +unsigned ucontext_t_sz(void *ctx); + +extern unsigned struct_timespec_sz; +extern unsigned struct_rlimit_sz; +extern unsigned struct_utimbuf_sz; + +struct __sanitizer_sem_t { + //u64 data[6]; + u32 sem_count; + u16 sem_type; + u16 sem_magic; + u64 sem_pad1[3]; + u64 sem_pad2[2]; +}; + +struct __sanitizer_ipc_perm { + unsigned int uid; // uid_t + unsigned int gid; // gid_t + unsigned int cuid; // uid_t + unsigned int cgid; // gid_t + unsigned int mode; // mode_t + unsigned int seq; // uint_t + int key; // key_t +#if !defined(_LP64) + int pad[4]; +#endif +}; + +struct __sanitizer_shmid_ds { + __sanitizer_ipc_perm shm_perm; + unsigned long shm_segsz; // size_t + unsigned long shm_flags; // uintptr_t + unsigned short shm_lkcnt; // ushort_t + int shm_lpid; // pid_t + int shm_cpid; // pid_t + unsigned long shm_nattch; // shmatt_t + unsigned long shm_cnattch; // ulong_t +#if defined(_LP64) + long shm_atime; // time_t + long shm_dtime; + long shm_ctime; + void *shm_amp; + u64 shm_gransize; // uint64_t + u64 shm_allocated; // uint64_t + u64 shm_pad4[1]; // int64_t +#else + long shm_atime; // time_t + int shm_pad1; // int32_t + long shm_dtime; // time_t + int shm_pad2; // int32_t + long shm_ctime; // time_t + void *shm_amp; + u64 shm_gransize; // uint64_t + u64 shm_allocated; // uint64_t +#endif +}; + +extern unsigned struct_statvfs_sz; +#if SANITIZER_SOLARIS32 +extern unsigned struct_statvfs64_sz; +#endif + +struct __sanitizer_iovec { + void *iov_base; + uptr iov_len; +}; + +struct __sanitizer_ifaddrs { + struct __sanitizer_ifaddrs *ifa_next; + char *ifa_name; + u64 ifa_flags; // uint64_t + void *ifa_addr; // (struct sockaddr *) + void *ifa_netmask; // (struct sockaddr *) + // This is a union on Linux. +# ifdef ifa_dstaddr +# undef ifa_dstaddr +# endif + void *ifa_dstaddr; // (struct sockaddr *) + void *ifa_data; +}; + +typedef unsigned __sanitizer_pthread_key_t; + +struct __sanitizer_XDR { + int x_op; + void *x_ops; + uptr x_public; + uptr x_private; + uptr x_base; + unsigned x_handy; +}; + +const int __sanitizer_XDR_ENCODE = 0; +const int __sanitizer_XDR_DECODE = 1; +const int __sanitizer_XDR_FREE = 2; + +struct __sanitizer_passwd { + char *pw_name; + char *pw_passwd; + unsigned int pw_uid; // uid_t + unsigned int pw_gid; // gid_t + char *pw_age; + char *pw_comment; + char *pw_gecos; + char *pw_dir; + char *pw_shell; +}; + +struct __sanitizer_group { + char *gr_name; + char *gr_passwd; + int gr_gid; + char **gr_mem; +}; + +typedef long __sanitizer_time_t; + +typedef long __sanitizer_suseconds_t; + +struct __sanitizer_timeval { + __sanitizer_time_t tv_sec; + __sanitizer_suseconds_t tv_usec; +}; + +struct __sanitizer_itimerval { + struct __sanitizer_timeval it_interval; + struct __sanitizer_timeval it_value; +}; + +struct __sanitizer_timeb { + __sanitizer_time_t time; + unsigned short millitm; + short timezone; + short dstflag; +}; + +struct __sanitizer_ether_addr { + u8 octet[6]; +}; + +struct __sanitizer_tm { + int tm_sec; + int tm_min; + int tm_hour; + int tm_mday; + int tm_mon; + int tm_year; + int tm_wday; + int tm_yday; + int tm_isdst; +}; + +struct __sanitizer_msghdr { + void *msg_name; + unsigned msg_namelen; + struct __sanitizer_iovec *msg_iov; + unsigned msg_iovlen; + void *msg_control; + unsigned msg_controllen; + int msg_flags; +}; +struct __sanitizer_cmsghdr { + unsigned cmsg_len; + int cmsg_level; + int cmsg_type; +}; + +#if SANITIZER_SOLARIS && (defined(_LP64) || _FILE_OFFSET_BITS == 64) +struct __sanitizer_dirent { + unsigned long long d_ino; + long long d_off; + unsigned short d_reclen; + // more fields that we don't care about +}; +#else +struct __sanitizer_dirent { + unsigned long d_ino; + long d_off; + unsigned short d_reclen; + // more fields that we don't care about +}; +#endif + +struct __sanitizer_dirent64 { + unsigned long long d_ino; + unsigned long long d_off; + unsigned short d_reclen; + // more fields that we don't care about +}; + +typedef long __sanitizer_clock_t; +typedef int __sanitizer_clockid_t; + +// This thing depends on the platform. We are only interested in the upper +// limit. Verified with a compiler assert in .cpp. +union __sanitizer_pthread_attr_t { + char size[128]; + void *align; +}; + +struct __sanitizer_sigset_t { + // uint32_t * 4 + unsigned int __bits[4]; +}; + +struct __sanitizer_siginfo { + // The size is determined by looking at sizeof of real siginfo_t on linux. + u64 opaque[128 / sizeof(u64)]; +}; + +using __sanitizer_sighandler_ptr = void (*)(int sig); +using __sanitizer_sigactionhandler_ptr = + void (*)(int sig, __sanitizer_siginfo *siginfo, void *uctx); + +struct __sanitizer_sigaction { + int sa_flags; + union { + __sanitizer_sigactionhandler_ptr sigaction; + __sanitizer_sighandler_ptr handler; + }; + __sanitizer_sigset_t sa_mask; +#if !defined(_LP64) + int sa_resv[2]; +#endif +}; + +struct __sanitizer_kernel_sigset_t { + u8 sig[8]; +}; + +struct __sanitizer_kernel_sigaction_t { + union { + void (*handler)(int signo); + void (*sigaction)(int signo, __sanitizer_siginfo *info, void *ctx); + }; + unsigned long sa_flags; + void (*sa_restorer)(void); + __sanitizer_kernel_sigset_t sa_mask; +}; + +extern const uptr sig_ign; +extern const uptr sig_dfl; +extern const uptr sig_err; +extern const uptr sa_siginfo; + +extern int af_inet; +extern int af_inet6; +uptr __sanitizer_in_addr_sz(int af); + +struct __sanitizer_dl_phdr_info { + uptr dlpi_addr; + const char *dlpi_name; + const void *dlpi_phdr; + short dlpi_phnum; +}; + +extern unsigned struct_ElfW_Phdr_sz; + +struct __sanitizer_addrinfo { + int ai_flags; + int ai_family; + int ai_socktype; + int ai_protocol; +#if defined(__sparcv9) + int _ai_pad; +#endif + unsigned ai_addrlen; + char *ai_canonname; + void *ai_addr; + struct __sanitizer_addrinfo *ai_next; +}; + +struct __sanitizer_hostent { + char *h_name; + char **h_aliases; + int h_addrtype; + int h_length; + char **h_addr_list; +}; + +struct __sanitizer_pollfd { + int fd; + short events; + short revents; +}; + +typedef unsigned long __sanitizer_nfds_t; + +struct __sanitizer_glob_t { + uptr gl_pathc; + char **gl_pathv; + uptr gl_offs; + char **gl_pathp; + int gl_pathn; +}; + +extern int glob_nomatch; +extern int glob_altdirfunc; +extern const int wordexp_wrde_dooffs; + +extern unsigned path_max; + +struct __sanitizer_wordexp_t { + uptr we_wordc; + char **we_wordv; + uptr we_offs; + char **we_wordp; + int we_wordn; +}; + +typedef void __sanitizer_FILE; +#define SANITIZER_HAS_STRUCT_FILE 0 + +// This simplifies generic code +#define struct_shminfo_sz -1 +#define struct_shm_info_sz -1 +#define shmctl_shm_stat -1 +#define shmctl_ipc_info -1 +#define shmctl_shm_info -1 + +extern int shmctl_ipc_stat; + +extern unsigned struct_utmp_sz; +extern unsigned struct_utmpx_sz; + +extern int map_fixed; + +// ioctl arguments +struct __sanitizer_ifconf { + int ifc_len; + union { + void *ifcu_req; + } ifc_ifcu; +}; + +// <sys/ioccom.h> +#define IOC_NRBITS 8 +#define IOC_TYPEBITS 8 +#define IOC_SIZEBITS 12 +#define IOC_DIRBITS 4 +#undef IOC_NONE +#define IOC_NONE 2U // IOC_VOID +#define IOC_READ 4U // IOC_OUT +#define IOC_WRITE 8U // IOC_IN + +#define IOC_NRMASK ((1 << IOC_NRBITS) - 1) +#define IOC_TYPEMASK ((1 << IOC_TYPEBITS) - 1) +#define IOC_SIZEMASK ((1 << IOC_SIZEBITS) - 1) +#define IOC_DIRMASK ((1 << IOC_DIRBITS) - 1) +#define IOC_NRSHIFT 0 +#define IOC_TYPESHIFT (IOC_NRSHIFT + IOC_NRBITS) +#define IOC_SIZESHIFT (IOC_TYPESHIFT + IOC_TYPEBITS) +#define IOC_DIRSHIFT (IOC_SIZESHIFT + IOC_SIZEBITS) + +#define IOC_DIR(nr) (((nr) >> IOC_DIRSHIFT) & IOC_DIRMASK) +#define IOC_TYPE(nr) (((nr) >> IOC_TYPESHIFT) & IOC_TYPEMASK) +#define IOC_NR(nr) (((nr) >> IOC_NRSHIFT) & IOC_NRMASK) + +#if defined(__sparc__) +// In sparc the 14 bits SIZE field overlaps with the +// least significant bit of DIR, so either IOC_READ or +// IOC_WRITE shall be 1 in order to get a non-zero SIZE. +#define IOC_SIZE(nr) \ + ((((((nr) >> 29) & 0x7) & (4U | 2U)) == 0) ? 0 : (((nr) >> 16) & 0x3fff)) +#else +#define IOC_SIZE(nr) (((nr) >> IOC_SIZESHIFT) & IOC_SIZEMASK) +#endif + +extern unsigned struct_ifreq_sz; +extern unsigned struct_termios_sz; +extern unsigned struct_winsize_sz; + +extern unsigned struct_sioc_sg_req_sz; +extern unsigned struct_sioc_vif_req_sz; + +// ioctl request identifiers + +// A special value to mark ioctls that are not present on the target platform, +// when it can not be determined without including any system headers. +extern const unsigned IOCTL_NOT_PRESENT; + +extern unsigned IOCTL_FIOASYNC; +extern unsigned IOCTL_FIOCLEX; +extern unsigned IOCTL_FIOGETOWN; +extern unsigned IOCTL_FIONBIO; +extern unsigned IOCTL_FIONCLEX; +extern unsigned IOCTL_FIOSETOWN; +extern unsigned IOCTL_SIOCADDMULTI; +extern unsigned IOCTL_SIOCATMARK; +extern unsigned IOCTL_SIOCDELMULTI; +extern unsigned IOCTL_SIOCGIFADDR; +extern unsigned IOCTL_SIOCGIFBRDADDR; +extern unsigned IOCTL_SIOCGIFCONF; +extern unsigned IOCTL_SIOCGIFDSTADDR; +extern unsigned IOCTL_SIOCGIFFLAGS; +extern unsigned IOCTL_SIOCGIFMETRIC; +extern unsigned IOCTL_SIOCGIFMTU; +extern unsigned IOCTL_SIOCGIFNETMASK; +extern unsigned IOCTL_SIOCGPGRP; +extern unsigned IOCTL_SIOCSIFADDR; +extern unsigned IOCTL_SIOCSIFBRDADDR; +extern unsigned IOCTL_SIOCSIFDSTADDR; +extern unsigned IOCTL_SIOCSIFFLAGS; +extern unsigned IOCTL_SIOCSIFMETRIC; +extern unsigned IOCTL_SIOCSIFMTU; +extern unsigned IOCTL_SIOCSIFNETMASK; +extern unsigned IOCTL_SIOCSPGRP; +extern unsigned IOCTL_TIOCEXCL; +extern unsigned IOCTL_TIOCGETD; +extern unsigned IOCTL_TIOCGPGRP; +extern unsigned IOCTL_TIOCGWINSZ; +extern unsigned IOCTL_TIOCMBIC; +extern unsigned IOCTL_TIOCMBIS; +extern unsigned IOCTL_TIOCMGET; +extern unsigned IOCTL_TIOCMSET; +extern unsigned IOCTL_TIOCNOTTY; +extern unsigned IOCTL_TIOCNXCL; +extern unsigned IOCTL_TIOCOUTQ; +extern unsigned IOCTL_TIOCPKT; +extern unsigned IOCTL_TIOCSCTTY; +extern unsigned IOCTL_TIOCSETD; +extern unsigned IOCTL_TIOCSPGRP; +extern unsigned IOCTL_TIOCSTI; +extern unsigned IOCTL_TIOCSWINSZ; +extern unsigned IOCTL_MTIOCGET; +extern unsigned IOCTL_MTIOCTOP; + +extern const int si_SEGV_MAPERR; +extern const int si_SEGV_ACCERR; +} // namespace __sanitizer + +#define CHECK_TYPE_SIZE(TYPE) \ + COMPILER_CHECK(sizeof(__sanitizer_##TYPE) == sizeof(TYPE)) + +#define CHECK_SIZE_AND_OFFSET(CLASS, MEMBER) \ + COMPILER_CHECK(sizeof(((__sanitizer_##CLASS *) NULL)->MEMBER) == \ + sizeof(((CLASS *) NULL)->MEMBER)); \ + COMPILER_CHECK(offsetof(__sanitizer_##CLASS, MEMBER) == \ + offsetof(CLASS, MEMBER)) + +// For sigaction, which is a function and struct at the same time, +// and thus requires explicit "struct" in sizeof() expression. +#define CHECK_STRUCT_SIZE_AND_OFFSET(CLASS, MEMBER) \ + COMPILER_CHECK(sizeof(((struct __sanitizer_##CLASS *) NULL)->MEMBER) == \ + sizeof(((struct CLASS *) NULL)->MEMBER)); \ + COMPILER_CHECK(offsetof(struct __sanitizer_##CLASS, MEMBER) == \ + offsetof(struct CLASS, MEMBER)) + +#endif // SANITIZER_SOLARIS + +#endif diff --git a/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_posix.cpp b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_posix.cpp new file mode 100644 index 0000000000..f8457a6aac --- /dev/null +++ b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_posix.cpp @@ -0,0 +1,400 @@ +//===-- sanitizer_posix.cpp -----------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file is shared between AddressSanitizer and ThreadSanitizer +// run-time libraries and implements POSIX-specific functions from +// sanitizer_posix.h. +//===----------------------------------------------------------------------===// + +#include "sanitizer_platform.h" + +#if SANITIZER_POSIX + +#include "sanitizer_common.h" +#include "sanitizer_file.h" +#include "sanitizer_flags.h" +#include "sanitizer_libc.h" +#include "sanitizer_posix.h" +#include "sanitizer_procmaps.h" + +#include <errno.h> +#include <fcntl.h> +#include <signal.h> +#include <sys/mman.h> + +#if SANITIZER_FREEBSD +// The MAP_NORESERVE define has been removed in FreeBSD 11.x, and even before +// that, it was never implemented. So just define it to zero. +#undef MAP_NORESERVE +#define MAP_NORESERVE 0 +#endif + +namespace __sanitizer { + +// ------------- sanitizer_common.h +uptr GetMmapGranularity() { + return GetPageSize(); +} + +void *MmapOrDie(uptr size, const char *mem_type, bool raw_report) { + size = RoundUpTo(size, GetPageSizeCached()); + uptr res = MmapNamed(nullptr, size, PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANON, mem_type); + int reserrno; + if (UNLIKELY(internal_iserror(res, &reserrno))) + ReportMmapFailureAndDie(size, mem_type, "allocate", reserrno, raw_report); + IncreaseTotalMmap(size); + return (void *)res; +} + +void UnmapOrDie(void *addr, uptr size) { + if (!addr || !size) return; + uptr res = internal_munmap(addr, size); + if (UNLIKELY(internal_iserror(res))) { + Report("ERROR: %s failed to deallocate 0x%zx (%zd) bytes at address %p\n", + SanitizerToolName, size, size, addr); + CHECK("unable to unmap" && 0); + } + DecreaseTotalMmap(size); +} + +void *MmapOrDieOnFatalError(uptr size, const char *mem_type) { + size = RoundUpTo(size, GetPageSizeCached()); + uptr res = MmapNamed(nullptr, size, PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANON, mem_type); + int reserrno; + if (UNLIKELY(internal_iserror(res, &reserrno))) { + if (reserrno == ENOMEM) + return nullptr; + ReportMmapFailureAndDie(size, mem_type, "allocate", reserrno); + } + IncreaseTotalMmap(size); + return (void *)res; +} + +// We want to map a chunk of address space aligned to 'alignment'. +// We do it by mapping a bit more and then unmapping redundant pieces. +// We probably can do it with fewer syscalls in some OS-dependent way. +void *MmapAlignedOrDieOnFatalError(uptr size, uptr alignment, + const char *mem_type) { + CHECK(IsPowerOfTwo(size)); + CHECK(IsPowerOfTwo(alignment)); + uptr map_size = size + alignment; + uptr map_res = (uptr)MmapOrDieOnFatalError(map_size, mem_type); + if (UNLIKELY(!map_res)) + return nullptr; + uptr map_end = map_res + map_size; + uptr res = map_res; + if (!IsAligned(res, alignment)) { + res = (map_res + alignment - 1) & ~(alignment - 1); + UnmapOrDie((void*)map_res, res - map_res); + } + uptr end = res + size; + if (end != map_end) + UnmapOrDie((void*)end, map_end - end); + return (void*)res; +} + +void *MmapNoReserveOrDie(uptr size, const char *mem_type) { + size = RoundUpTo(size, GetPageSizeCached()); + uptr p = MmapNamed(nullptr, size, PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANON | MAP_NORESERVE, mem_type); + int reserrno; + if (UNLIKELY(internal_iserror(p, &reserrno))) + ReportMmapFailureAndDie(size, mem_type, "allocate noreserve", reserrno); + IncreaseTotalMmap(size); + return (void *)p; +} + +static void *MmapFixedImpl(uptr fixed_addr, uptr size, bool tolerate_enomem, + const char *name) { + size = RoundUpTo(size, GetPageSizeCached()); + fixed_addr = RoundDownTo(fixed_addr, GetPageSizeCached()); + uptr p = MmapNamed((void *)fixed_addr, size, PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANON | MAP_FIXED, name); + int reserrno; + if (UNLIKELY(internal_iserror(p, &reserrno))) { + if (tolerate_enomem && reserrno == ENOMEM) + return nullptr; + char mem_type[40]; + internal_snprintf(mem_type, sizeof(mem_type), "memory at address 0x%zx", + fixed_addr); + ReportMmapFailureAndDie(size, mem_type, "allocate", reserrno); + } + IncreaseTotalMmap(size); + return (void *)p; +} + +void *MmapFixedOrDie(uptr fixed_addr, uptr size, const char *name) { + return MmapFixedImpl(fixed_addr, size, false /*tolerate_enomem*/, name); +} + +void *MmapFixedOrDieOnFatalError(uptr fixed_addr, uptr size, const char *name) { + return MmapFixedImpl(fixed_addr, size, true /*tolerate_enomem*/, name); +} + +bool MprotectNoAccess(uptr addr, uptr size) { + return 0 == internal_mprotect((void*)addr, size, PROT_NONE); +} + +bool MprotectReadOnly(uptr addr, uptr size) { + return 0 == internal_mprotect((void *)addr, size, PROT_READ); +} + +#if !SANITIZER_MAC +void MprotectMallocZones(void *addr, int prot) {} +#endif + +fd_t OpenFile(const char *filename, FileAccessMode mode, error_t *errno_p) { + if (ShouldMockFailureToOpen(filename)) + return kInvalidFd; + int flags; + switch (mode) { + case RdOnly: flags = O_RDONLY; break; + case WrOnly: flags = O_WRONLY | O_CREAT | O_TRUNC; break; + case RdWr: flags = O_RDWR | O_CREAT; break; + } + fd_t res = internal_open(filename, flags, 0660); + if (internal_iserror(res, errno_p)) + return kInvalidFd; + return ReserveStandardFds(res); +} + +void CloseFile(fd_t fd) { + internal_close(fd); +} + +bool ReadFromFile(fd_t fd, void *buff, uptr buff_size, uptr *bytes_read, + error_t *error_p) { + uptr res = internal_read(fd, buff, buff_size); + if (internal_iserror(res, error_p)) + return false; + if (bytes_read) + *bytes_read = res; + return true; +} + +bool WriteToFile(fd_t fd, const void *buff, uptr buff_size, uptr *bytes_written, + error_t *error_p) { + uptr res = internal_write(fd, buff, buff_size); + if (internal_iserror(res, error_p)) + return false; + if (bytes_written) + *bytes_written = res; + return true; +} + +void *MapFileToMemory(const char *file_name, uptr *buff_size) { + fd_t fd = OpenFile(file_name, RdOnly); + CHECK(fd != kInvalidFd); + uptr fsize = internal_filesize(fd); + CHECK_NE(fsize, (uptr)-1); + CHECK_GT(fsize, 0); + *buff_size = RoundUpTo(fsize, GetPageSizeCached()); + uptr map = internal_mmap(nullptr, *buff_size, PROT_READ, MAP_PRIVATE, fd, 0); + return internal_iserror(map) ? nullptr : (void *)map; +} + +void *MapWritableFileToMemory(void *addr, uptr size, fd_t fd, OFF_T offset) { + uptr flags = MAP_SHARED; + if (addr) flags |= MAP_FIXED; + uptr p = internal_mmap(addr, size, PROT_READ | PROT_WRITE, flags, fd, offset); + int mmap_errno = 0; + if (internal_iserror(p, &mmap_errno)) { + Printf("could not map writable file (%d, %lld, %zu): %zd, errno: %d\n", + fd, (long long)offset, size, p, mmap_errno); + return nullptr; + } + return (void *)p; +} + +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) { + MemoryMappingLayout proc_maps(/*cache_enabled*/true); + if (proc_maps.Error()) + return true; // and hope for the best + MemoryMappedSegment segment; + while (proc_maps.Next(&segment)) { + if (segment.start == segment.end) continue; // Empty range. + CHECK_NE(0, segment.end); + if (!IntervalsAreSeparate(segment.start, segment.end - 1, range_start, + range_end)) + return false; + } + return true; +} + +#if !SANITIZER_MAC +void DumpProcessMap() { + MemoryMappingLayout proc_maps(/*cache_enabled*/true); + const sptr kBufSize = 4095; + char *filename = (char*)MmapOrDie(kBufSize, __func__); + MemoryMappedSegment segment(filename, kBufSize); + Report("Process memory map follows:\n"); + while (proc_maps.Next(&segment)) { + Printf("\t%p-%p\t%s\n", (void *)segment.start, (void *)segment.end, + segment.filename); + } + Report("End of process memory map.\n"); + UnmapOrDie(filename, kBufSize); +} +#endif + +const char *GetPwd() { + return GetEnv("PWD"); +} + +bool IsPathSeparator(const char c) { + return c == '/'; +} + +bool IsAbsolutePath(const char *path) { + return path != nullptr && IsPathSeparator(path[0]); +} + +void ReportFile::Write(const char *buffer, uptr length) { + SpinMutexLock l(mu); + ReopenIfNecessary(); + internal_write(fd, buffer, length); +} + +bool GetCodeRangeForFile(const char *module, uptr *start, uptr *end) { + MemoryMappingLayout proc_maps(/*cache_enabled*/false); + InternalMmapVector<char> buff(kMaxPathLength); + MemoryMappedSegment segment(buff.data(), buff.size()); + while (proc_maps.Next(&segment)) { + if (segment.IsExecutable() && + internal_strcmp(module, segment.filename) == 0) { + *start = segment.start; + *end = segment.end; + return true; + } + } + return false; +} + +uptr SignalContext::GetAddress() const { + auto si = static_cast<const siginfo_t *>(siginfo); + return (uptr)si->si_addr; +} + +bool SignalContext::IsMemoryAccess() const { + auto si = static_cast<const siginfo_t *>(siginfo); + return si->si_signo == SIGSEGV || si->si_signo == SIGBUS; +} + +int SignalContext::GetType() const { + return static_cast<const siginfo_t *>(siginfo)->si_signo; +} + +const char *SignalContext::Describe() const { + switch (GetType()) { + case SIGFPE: + return "FPE"; + case SIGILL: + return "ILL"; + case SIGABRT: + return "ABRT"; + case SIGSEGV: + return "SEGV"; + case SIGBUS: + return "BUS"; + case SIGTRAP: + return "TRAP"; + } + return "UNKNOWN SIGNAL"; +} + +fd_t ReserveStandardFds(fd_t fd) { + CHECK_GE(fd, 0); + if (fd > 2) + return fd; + bool used[3]; + internal_memset(used, 0, sizeof(used)); + while (fd <= 2) { + used[fd] = true; + fd = internal_dup(fd); + } + for (int i = 0; i <= 2; ++i) + if (used[i]) + internal_close(i); + return fd; +} + +bool ShouldMockFailureToOpen(const char *path) { + return common_flags()->test_only_emulate_no_memorymap && + internal_strncmp(path, "/proc/", 6) == 0; +} + +#if SANITIZER_LINUX && !SANITIZER_ANDROID && !SANITIZER_GO +int GetNamedMappingFd(const char *name, uptr size, int *flags) { + if (!common_flags()->decorate_proc_maps || !name) + return -1; + char shmname[200]; + CHECK(internal_strlen(name) < sizeof(shmname) - 10); + internal_snprintf(shmname, sizeof(shmname), "/dev/shm/%zu [%s]", + internal_getpid(), name); + int o_cloexec = 0; +#if defined(O_CLOEXEC) + o_cloexec = O_CLOEXEC; +#endif + int fd = ReserveStandardFds( + internal_open(shmname, O_RDWR | O_CREAT | O_TRUNC | o_cloexec, S_IRWXU)); + CHECK_GE(fd, 0); + int res = internal_ftruncate(fd, size); +#if !defined(O_CLOEXEC) + res = fcntl(fd, F_SETFD, FD_CLOEXEC); + CHECK_EQ(0, res); +#endif + CHECK_EQ(0, res); + res = internal_unlink(shmname); + CHECK_EQ(0, res); + *flags &= ~(MAP_ANON | MAP_ANONYMOUS); + return fd; +} +#else +int GetNamedMappingFd(const char *name, uptr size, int *flags) { + return -1; +} +#endif + +#if SANITIZER_ANDROID +#define PR_SET_VMA 0x53564d41 +#define PR_SET_VMA_ANON_NAME 0 +void DecorateMapping(uptr addr, uptr size, const char *name) { + if (!common_flags()->decorate_proc_maps || !name) + return; + internal_prctl(PR_SET_VMA, PR_SET_VMA_ANON_NAME, addr, size, (uptr)name); +} +#else +void DecorateMapping(uptr addr, uptr size, const char *name) { +} +#endif + +uptr MmapNamed(void *addr, uptr length, int prot, int flags, const char *name) { + int fd = GetNamedMappingFd(name, length, &flags); + uptr res = internal_mmap(addr, length, prot, flags, fd, 0); + if (!internal_iserror(res)) + DecorateMapping(res, length, name); + return res; +} + + +} // namespace __sanitizer + +#endif // SANITIZER_POSIX diff --git a/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_posix.h b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_posix.h new file mode 100644 index 0000000000..f91e26e74b --- /dev/null +++ b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_posix.h @@ -0,0 +1,128 @@ +//===-- sanitizer_posix.h -------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file is shared between AddressSanitizer and ThreadSanitizer +// run-time libraries and declares some useful POSIX-specific functions. +//===----------------------------------------------------------------------===// +#ifndef SANITIZER_POSIX_H +#define SANITIZER_POSIX_H + +// ----------- ATTENTION ------------- +// This header should NOT include any other headers from sanitizer runtime. +#include "sanitizer_internal_defs.h" +#include "sanitizer_platform_limits_freebsd.h" +#include "sanitizer_platform_limits_netbsd.h" +#include "sanitizer_platform_limits_posix.h" +#include "sanitizer_platform_limits_solaris.h" + +#if SANITIZER_POSIX + +namespace __sanitizer { + +// I/O +// Don't use directly, use __sanitizer::OpenFile() instead. +uptr internal_open(const char *filename, int flags); +uptr internal_open(const char *filename, int flags, u32 mode); +uptr internal_close(fd_t fd); + +uptr internal_read(fd_t fd, void *buf, uptr count); +uptr internal_write(fd_t fd, const void *buf, uptr count); + +// Memory +uptr internal_mmap(void *addr, uptr length, int prot, int flags, + int fd, u64 offset); +uptr internal_munmap(void *addr, uptr length); +#if SANITIZER_LINUX +uptr internal_mremap(void *old_address, uptr old_size, uptr new_size, int flags, + void *new_address); +#endif +int internal_mprotect(void *addr, uptr length, int prot); +int internal_madvise(uptr addr, uptr length, int advice); + +// OS +uptr internal_filesize(fd_t fd); // -1 on error. +uptr internal_stat(const char *path, void *buf); +uptr internal_lstat(const char *path, void *buf); +uptr internal_fstat(fd_t fd, void *buf); +uptr internal_dup(int oldfd); +uptr internal_dup2(int oldfd, int newfd); +uptr internal_readlink(const char *path, char *buf, uptr bufsize); +uptr internal_unlink(const char *path); +uptr internal_rename(const char *oldpath, const char *newpath); +uptr internal_lseek(fd_t fd, OFF_T offset, int whence); + +#if SANITIZER_NETBSD +uptr internal_ptrace(int request, int pid, void *addr, int data); +#else +uptr internal_ptrace(int request, int pid, void *addr, void *data); +#endif +uptr internal_waitpid(int pid, int *status, int options); + +int internal_fork(); +fd_t internal_spawn(const char *argv[], const char *envp[], pid_t *pid); + +int internal_sysctl(const int *name, unsigned int namelen, void *oldp, + uptr *oldlenp, const void *newp, uptr newlen); +int internal_sysctlbyname(const char *sname, void *oldp, uptr *oldlenp, + const void *newp, uptr newlen); + +// These functions call appropriate pthread_ functions directly, bypassing +// the interceptor. They are weak and may not be present in some tools. +SANITIZER_WEAK_ATTRIBUTE +int real_pthread_create(void *th, void *attr, void *(*callback)(void *), + void *param); +SANITIZER_WEAK_ATTRIBUTE +int real_pthread_join(void *th, void **ret); + +#define DEFINE_REAL_PTHREAD_FUNCTIONS \ + namespace __sanitizer { \ + int real_pthread_create(void *th, void *attr, void *(*callback)(void *), \ + void *param) { \ + return REAL(pthread_create)(th, attr, callback, param); \ + } \ + int real_pthread_join(void *th, void **ret) { \ + return REAL(pthread_join(th, ret)); \ + } \ + } // namespace __sanitizer + +int my_pthread_attr_getstack(void *attr, void **addr, uptr *size); + +// A routine named real_sigaction() must be implemented by each sanitizer in +// order for internal_sigaction() to bypass interceptors. +int internal_sigaction(int signum, const void *act, void *oldact); +void internal_sigfillset(__sanitizer_sigset_t *set); +void internal_sigemptyset(__sanitizer_sigset_t *set); +bool internal_sigismember(__sanitizer_sigset_t *set, int signum); + +uptr internal_execve(const char *filename, char *const argv[], + char *const envp[]); + +bool IsStateDetached(int state); + +// Move the fd out of {0, 1, 2} range. +fd_t ReserveStandardFds(fd_t fd); + +bool ShouldMockFailureToOpen(const char *path); + +// Create a non-file mapping with a given /proc/self/maps name. +uptr MmapNamed(void *addr, uptr length, int prot, int flags, const char *name); + +// Platforms should implement at most one of these. +// 1. Provide a pre-decorated file descriptor to use instead of an anonymous +// mapping. +int GetNamedMappingFd(const char *name, uptr size, int *flags); +// 2. Add name to an existing anonymous mapping. The caller must keep *name +// alive at least as long as the mapping exists. +void DecorateMapping(uptr addr, uptr size, const char *name); + + +} // namespace __sanitizer + +#endif // SANITIZER_POSIX + +#endif // SANITIZER_POSIX_H diff --git a/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_posix_libcdep.cpp b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_posix_libcdep.cpp new file mode 100644 index 0000000000..eed02ce4f6 --- /dev/null +++ b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_posix_libcdep.cpp @@ -0,0 +1,503 @@ +//===-- sanitizer_posix_libcdep.cpp ---------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file is shared between AddressSanitizer and ThreadSanitizer +// run-time libraries and implements libc-dependent POSIX-specific functions +// from sanitizer_libc.h. +//===----------------------------------------------------------------------===// + +#include "sanitizer_platform.h" + +#if SANITIZER_POSIX + +#include "sanitizer_common.h" +#include "sanitizer_flags.h" +#include "sanitizer_platform_limits_netbsd.h" +#include "sanitizer_platform_limits_posix.h" +#include "sanitizer_platform_limits_solaris.h" +#include "sanitizer_posix.h" +#include "sanitizer_procmaps.h" + +#include <errno.h> +#include <fcntl.h> +#include <pthread.h> +#include <signal.h> +#include <stdlib.h> +#include <sys/mman.h> +#include <sys/resource.h> +#include <sys/stat.h> +#include <sys/time.h> +#include <sys/types.h> +#include <sys/wait.h> +#include <unistd.h> + +#if SANITIZER_FREEBSD +// The MAP_NORESERVE define has been removed in FreeBSD 11.x, and even before +// that, it was never implemented. So just define it to zero. +#undef MAP_NORESERVE +#define MAP_NORESERVE 0 +#endif + +typedef void (*sa_sigaction_t)(int, siginfo_t *, void *); + +namespace __sanitizer { + +u32 GetUid() { + return getuid(); +} + +uptr GetThreadSelf() { + return (uptr)pthread_self(); +} + +void ReleaseMemoryPagesToOS(uptr beg, uptr end) { + uptr page_size = GetPageSizeCached(); + uptr beg_aligned = RoundUpTo(beg, page_size); + uptr end_aligned = RoundDownTo(end, page_size); + if (beg_aligned < end_aligned) + internal_madvise(beg_aligned, end_aligned - beg_aligned, + SANITIZER_MADVISE_DONTNEED); +} + +void SetShadowRegionHugePageMode(uptr addr, uptr size) { +#ifdef MADV_NOHUGEPAGE // May not be defined on old systems. + if (common_flags()->no_huge_pages_for_shadow) + internal_madvise(addr, size, MADV_NOHUGEPAGE); + else + internal_madvise(addr, size, MADV_HUGEPAGE); +#endif // MADV_NOHUGEPAGE +} + +bool DontDumpShadowMemory(uptr addr, uptr length) { +#if defined(MADV_DONTDUMP) + return internal_madvise(addr, length, MADV_DONTDUMP) == 0; +#elif defined(MADV_NOCORE) + return internal_madvise(addr, length, MADV_NOCORE) == 0; +#else + return true; +#endif // MADV_DONTDUMP +} + +static rlim_t getlim(int res) { + rlimit rlim; + CHECK_EQ(0, getrlimit(res, &rlim)); + return rlim.rlim_cur; +} + +static void setlim(int res, rlim_t lim) { + struct rlimit rlim; + if (getrlimit(res, const_cast<struct rlimit *>(&rlim))) { + Report("ERROR: %s getrlimit() failed %d\n", SanitizerToolName, errno); + Die(); + } + rlim.rlim_cur = lim; + if (setrlimit(res, const_cast<struct rlimit *>(&rlim))) { + Report("ERROR: %s setrlimit() failed %d\n", SanitizerToolName, errno); + Die(); + } +} + +void DisableCoreDumperIfNecessary() { + if (common_flags()->disable_coredump) { + setlim(RLIMIT_CORE, 0); + } +} + +bool StackSizeIsUnlimited() { + rlim_t stack_size = getlim(RLIMIT_STACK); + return (stack_size == RLIM_INFINITY); +} + +void SetStackSizeLimitInBytes(uptr limit) { + setlim(RLIMIT_STACK, (rlim_t)limit); + CHECK(!StackSizeIsUnlimited()); +} + +bool AddressSpaceIsUnlimited() { + rlim_t as_size = getlim(RLIMIT_AS); + return (as_size == RLIM_INFINITY); +} + +void SetAddressSpaceUnlimited() { + setlim(RLIMIT_AS, RLIM_INFINITY); + CHECK(AddressSpaceIsUnlimited()); +} + +void Abort() { +#if !SANITIZER_GO + // If we are handling SIGABRT, unhandle it first. + // TODO(vitalybuka): Check if handler belongs to sanitizer. + if (GetHandleSignalMode(SIGABRT) != kHandleSignalNo) { + struct sigaction sigact; + internal_memset(&sigact, 0, sizeof(sigact)); + sigact.sa_handler = SIG_DFL; + internal_sigaction(SIGABRT, &sigact, nullptr); + } +#endif + + abort(); +} + +int Atexit(void (*function)(void)) { +#if !SANITIZER_GO + return atexit(function); +#else + return 0; +#endif +} + +bool CreateDir(const char *pathname) { return mkdir(pathname, 0755) == 0; } + +bool SupportsColoredOutput(fd_t fd) { + return isatty(fd) != 0; +} + +#if !SANITIZER_GO +// TODO(glider): different tools may require different altstack size. +static uptr GetAltStackSize() { + // Note: since GLIBC_2.31, SIGSTKSZ may be a function call, so this may be + // more costly that you think. However GetAltStackSize is only call 2-3 times + // per thread so don't cache the evaluation. + return SIGSTKSZ * 4; +} + +void SetAlternateSignalStack() { + stack_t altstack, oldstack; + CHECK_EQ(0, sigaltstack(nullptr, &oldstack)); + // If the alternate stack is already in place, do nothing. + // Android always sets an alternate stack, but it's too small for us. + if (!SANITIZER_ANDROID && !(oldstack.ss_flags & SS_DISABLE)) return; + // TODO(glider): the mapped stack should have the MAP_STACK flag in the + // future. It is not required by man 2 sigaltstack now (they're using + // malloc()). + altstack.ss_size = GetAltStackSize(); + altstack.ss_sp = (char *)MmapOrDie(altstack.ss_size, __func__); + altstack.ss_flags = 0; + CHECK_EQ(0, sigaltstack(&altstack, nullptr)); +} + +void UnsetAlternateSignalStack() { + stack_t altstack, oldstack; + altstack.ss_sp = nullptr; + altstack.ss_flags = SS_DISABLE; + altstack.ss_size = GetAltStackSize(); // Some sane value required on Darwin. + CHECK_EQ(0, sigaltstack(&altstack, &oldstack)); + UnmapOrDie(oldstack.ss_sp, oldstack.ss_size); +} + +static void MaybeInstallSigaction(int signum, + SignalHandlerType handler) { + if (GetHandleSignalMode(signum) == kHandleSignalNo) return; + + struct sigaction sigact; + internal_memset(&sigact, 0, sizeof(sigact)); + sigact.sa_sigaction = (sa_sigaction_t)handler; + // Do not block the signal from being received in that signal's handler. + // Clients are responsible for handling this correctly. + sigact.sa_flags = SA_SIGINFO | SA_NODEFER; + if (common_flags()->use_sigaltstack) sigact.sa_flags |= SA_ONSTACK; + CHECK_EQ(0, internal_sigaction(signum, &sigact, nullptr)); + VReport(1, "Installed the sigaction for signal %d\n", signum); +} + +void InstallDeadlySignalHandlers(SignalHandlerType handler) { + // Set the alternate signal stack for the main thread. + // This will cause SetAlternateSignalStack to be called twice, but the stack + // will be actually set only once. + if (common_flags()->use_sigaltstack) SetAlternateSignalStack(); + MaybeInstallSigaction(SIGSEGV, handler); + MaybeInstallSigaction(SIGBUS, handler); + MaybeInstallSigaction(SIGABRT, handler); + MaybeInstallSigaction(SIGFPE, handler); + MaybeInstallSigaction(SIGILL, handler); + MaybeInstallSigaction(SIGTRAP, handler); +} + +bool SignalContext::IsStackOverflow() const { + // Access at a reasonable offset above SP, or slightly below it (to account + // for x86_64 or PowerPC redzone, ARM push of multiple registers, etc) is + // probably a stack overflow. +#ifdef __s390__ + // On s390, the fault address in siginfo points to start of the page, not + // to the precise word that was accessed. Mask off the low bits of sp to + // take it into account. + bool IsStackAccess = addr >= (sp & ~0xFFF) && addr < sp + 0xFFFF; +#else + // Let's accept up to a page size away from top of stack. Things like stack + // probing can trigger accesses with such large offsets. + bool IsStackAccess = addr + GetPageSizeCached() > sp && addr < sp + 0xFFFF; +#endif + +#if __powerpc__ + // Large stack frames can be allocated with e.g. + // lis r0,-10000 + // stdux r1,r1,r0 # store sp to [sp-10000] and update sp by -10000 + // If the store faults then sp will not have been updated, so test above + // will not work, because the fault address will be more than just "slightly" + // below sp. + if (!IsStackAccess && IsAccessibleMemoryRange(pc, 4)) { + u32 inst = *(unsigned *)pc; + u32 ra = (inst >> 16) & 0x1F; + u32 opcd = inst >> 26; + u32 xo = (inst >> 1) & 0x3FF; + // Check for store-with-update to sp. The instructions we accept are: + // stbu rs,d(ra) stbux rs,ra,rb + // sthu rs,d(ra) sthux rs,ra,rb + // stwu rs,d(ra) stwux rs,ra,rb + // stdu rs,ds(ra) stdux rs,ra,rb + // where ra is r1 (the stack pointer). + if (ra == 1 && + (opcd == 39 || opcd == 45 || opcd == 37 || opcd == 62 || + (opcd == 31 && (xo == 247 || xo == 439 || xo == 183 || xo == 181)))) + IsStackAccess = true; + } +#endif // __powerpc__ + + // We also check si_code to filter out SEGV caused by something else other + // then hitting the guard page or unmapped memory, like, for example, + // unaligned memory access. + auto si = static_cast<const siginfo_t *>(siginfo); + return IsStackAccess && + (si->si_code == si_SEGV_MAPERR || si->si_code == si_SEGV_ACCERR); +} + +#endif // SANITIZER_GO + +bool IsAccessibleMemoryRange(uptr beg, uptr size) { + uptr page_size = GetPageSizeCached(); + // Checking too large memory ranges is slow. + CHECK_LT(size, page_size * 10); + int sock_pair[2]; + if (pipe(sock_pair)) + return false; + uptr bytes_written = + internal_write(sock_pair[1], reinterpret_cast<void *>(beg), size); + int write_errno; + bool result; + if (internal_iserror(bytes_written, &write_errno)) { + CHECK_EQ(EFAULT, write_errno); + result = false; + } else { + result = (bytes_written == size); + } + internal_close(sock_pair[0]); + internal_close(sock_pair[1]); + return result; +} + +void PlatformPrepareForSandboxing(__sanitizer_sandbox_arguments *args) { + // Some kinds of sandboxes may forbid filesystem access, so we won't be able + // to read the file mappings from /proc/self/maps. Luckily, neither the + // process will be able to load additional libraries, so it's fine to use the + // cached mappings. + MemoryMappingLayout::CacheMemoryMappings(); +} + +static bool MmapFixed(uptr fixed_addr, uptr size, int additional_flags, + const char *name) { + size = RoundUpTo(size, GetPageSizeCached()); + fixed_addr = RoundDownTo(fixed_addr, GetPageSizeCached()); + uptr p = + MmapNamed((void *)fixed_addr, size, PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_FIXED | additional_flags | MAP_ANON, name); + int reserrno; + if (internal_iserror(p, &reserrno)) { + Report("ERROR: %s failed to " + "allocate 0x%zx (%zd) bytes at address %zx (errno: %d)\n", + SanitizerToolName, size, size, fixed_addr, reserrno); + return false; + } + IncreaseTotalMmap(size); + return true; +} + +bool MmapFixedNoReserve(uptr fixed_addr, uptr size, const char *name) { + return MmapFixed(fixed_addr, size, MAP_NORESERVE, name); +} + +bool MmapFixedSuperNoReserve(uptr fixed_addr, uptr size, const char *name) { +#if SANITIZER_FREEBSD + if (common_flags()->no_huge_pages_for_shadow) + return MmapFixedNoReserve(fixed_addr, size, name); + // MAP_NORESERVE is implicit with FreeBSD + return MmapFixed(fixed_addr, size, MAP_ALIGNED_SUPER, name); +#else + bool r = MmapFixedNoReserve(fixed_addr, size, name); + if (r) + SetShadowRegionHugePageMode(fixed_addr, size); + return r; +#endif +} + +uptr ReservedAddressRange::Init(uptr size, const char *name, uptr fixed_addr) { + base_ = fixed_addr ? MmapFixedNoAccess(fixed_addr, size, name) + : MmapNoAccess(size); + size_ = size; + name_ = name; + (void)os_handle_; // unsupported + return reinterpret_cast<uptr>(base_); +} + +// Uses fixed_addr for now. +// Will use offset instead once we've implemented this function for real. +uptr ReservedAddressRange::Map(uptr fixed_addr, uptr size, const char *name) { + return reinterpret_cast<uptr>( + MmapFixedOrDieOnFatalError(fixed_addr, size, name)); +} + +uptr ReservedAddressRange::MapOrDie(uptr fixed_addr, uptr size, + const char *name) { + return reinterpret_cast<uptr>(MmapFixedOrDie(fixed_addr, size, name)); +} + +void ReservedAddressRange::Unmap(uptr addr, uptr size) { + CHECK_LE(size, size_); + if (addr == reinterpret_cast<uptr>(base_)) + // If we unmap the whole range, just null out the base. + base_ = (size == size_) ? nullptr : reinterpret_cast<void*>(addr + size); + else + CHECK_EQ(addr + size, reinterpret_cast<uptr>(base_) + size_); + size_ -= size; + UnmapOrDie(reinterpret_cast<void*>(addr), size); +} + +void *MmapFixedNoAccess(uptr fixed_addr, uptr size, const char *name) { + return (void *)MmapNamed((void *)fixed_addr, size, PROT_NONE, + MAP_PRIVATE | MAP_FIXED | MAP_NORESERVE | MAP_ANON, + name); +} + +void *MmapNoAccess(uptr size) { + unsigned flags = MAP_PRIVATE | MAP_ANON | MAP_NORESERVE; + return (void *)internal_mmap(nullptr, size, PROT_NONE, flags, -1, 0); +} + +// This function is defined elsewhere if we intercepted pthread_attr_getstack. +extern "C" { +SANITIZER_WEAK_ATTRIBUTE int +real_pthread_attr_getstack(void *attr, void **addr, size_t *size); +} // extern "C" + +int my_pthread_attr_getstack(void *attr, void **addr, uptr *size) { +#if !SANITIZER_GO && !SANITIZER_MAC + if (&real_pthread_attr_getstack) + return real_pthread_attr_getstack((pthread_attr_t *)attr, addr, + (size_t *)size); +#endif + return pthread_attr_getstack((pthread_attr_t *)attr, addr, (size_t *)size); +} + +#if !SANITIZER_GO +void AdjustStackSize(void *attr_) { + pthread_attr_t *attr = (pthread_attr_t *)attr_; + uptr stackaddr = 0; + uptr stacksize = 0; + my_pthread_attr_getstack(attr, (void**)&stackaddr, &stacksize); + // GLibC will return (0 - stacksize) as the stack address in the case when + // stacksize is set, but stackaddr is not. + bool stack_set = (stackaddr != 0) && (stackaddr + stacksize != 0); + // We place a lot of tool data into TLS, account for that. + const uptr minstacksize = GetTlsSize() + 128*1024; + if (stacksize < minstacksize) { + if (!stack_set) { + if (stacksize != 0) { + VPrintf(1, "Sanitizer: increasing stacksize %zu->%zu\n", stacksize, + minstacksize); + pthread_attr_setstacksize(attr, minstacksize); + } + } else { + Printf("Sanitizer: pre-allocated stack size is insufficient: " + "%zu < %zu\n", stacksize, minstacksize); + Printf("Sanitizer: pthread_create is likely to fail.\n"); + } + } +} +#endif // !SANITIZER_GO + +pid_t StartSubprocess(const char *program, const char *const argv[], + const char *const envp[], fd_t stdin_fd, fd_t stdout_fd, + fd_t stderr_fd) { + auto file_closer = at_scope_exit([&] { + if (stdin_fd != kInvalidFd) { + internal_close(stdin_fd); + } + if (stdout_fd != kInvalidFd) { + internal_close(stdout_fd); + } + if (stderr_fd != kInvalidFd) { + internal_close(stderr_fd); + } + }); + + int pid = internal_fork(); + + if (pid < 0) { + int rverrno; + if (internal_iserror(pid, &rverrno)) { + Report("WARNING: failed to fork (errno %d)\n", rverrno); + } + return pid; + } + + if (pid == 0) { + // Child subprocess + if (stdin_fd != kInvalidFd) { + internal_close(STDIN_FILENO); + internal_dup2(stdin_fd, STDIN_FILENO); + internal_close(stdin_fd); + } + if (stdout_fd != kInvalidFd) { + internal_close(STDOUT_FILENO); + internal_dup2(stdout_fd, STDOUT_FILENO); + internal_close(stdout_fd); + } + if (stderr_fd != kInvalidFd) { + internal_close(STDERR_FILENO); + internal_dup2(stderr_fd, STDERR_FILENO); + internal_close(stderr_fd); + } + + for (int fd = sysconf(_SC_OPEN_MAX); fd > 2; fd--) internal_close(fd); + + internal_execve(program, const_cast<char **>(&argv[0]), + const_cast<char *const *>(envp)); + internal__exit(1); + } + + return pid; +} + +bool IsProcessRunning(pid_t pid) { + int process_status; + uptr waitpid_status = internal_waitpid(pid, &process_status, WNOHANG); + int local_errno; + if (internal_iserror(waitpid_status, &local_errno)) { + VReport(1, "Waiting on the process failed (errno %d).\n", local_errno); + return false; + } + return waitpid_status == 0; +} + +int WaitForProcess(pid_t pid) { + int process_status; + uptr waitpid_status = internal_waitpid(pid, &process_status, 0); + int local_errno; + if (internal_iserror(waitpid_status, &local_errno)) { + VReport(1, "Waiting on the process failed (errno %d).\n", local_errno); + return -1; + } + return process_status; +} + +bool IsStateDetached(int state) { + return state == PTHREAD_CREATE_DETACHED; +} + +} // namespace __sanitizer + +#endif // SANITIZER_POSIX diff --git a/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_printf.cpp b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_printf.cpp new file mode 100644 index 0000000000..3a9e366d2d --- /dev/null +++ b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_printf.cpp @@ -0,0 +1,361 @@ +//===-- sanitizer_printf.cpp ----------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// 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_flags.h" +#include "sanitizer_libc.h" + +#include <stdio.h> +#include <stdarg.h> + +#if SANITIZER_WINDOWS && defined(_MSC_VER) && _MSC_VER < 1800 && \ + !defined(va_copy) +# define va_copy(dst, src) ((dst) = (src)) +#endif + +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 or spaces, depending +// on the value of |pad_with_zero|. +static int AppendNumber(char **buff, const char *buff_end, u64 absolute_value, + u8 base, u8 minimal_num_length, bool pad_with_zero, + bool negative, bool uppercase) { + uptr const kMaxLen = 30; + RAW_CHECK(base == 10 || base == 16); + RAW_CHECK(base == 10 || !negative); + RAW_CHECK(absolute_value || !negative); + RAW_CHECK(minimal_num_length < kMaxLen); + int result = 0; + if (negative && minimal_num_length) + --minimal_num_length; + if (negative && pad_with_zero) + result += AppendChar(buff, buff_end, '-'); + uptr num_buffer[kMaxLen]; + int pos = 0; + do { + RAW_CHECK_MSG((uptr)pos < kMaxLen, "AppendNumber buffer overflow"); + num_buffer[pos++] = absolute_value % base; + absolute_value /= base; + } while (absolute_value > 0); + if (pos < minimal_num_length) { + // Make sure compiler doesn't insert call to memset here. + internal_memset(&num_buffer[pos], 0, + sizeof(num_buffer[0]) * (minimal_num_length - pos)); + pos = minimal_num_length; + } + RAW_CHECK(pos > 0); + pos--; + for (; pos >= 0 && num_buffer[pos] == 0; pos--) { + char c = (pad_with_zero || pos == 0) ? '0' : ' '; + result += AppendChar(buff, buff_end, c); + } + if (negative && !pad_with_zero) result += AppendChar(buff, buff_end, '-'); + for (; pos >= 0; pos--) { + char digit = static_cast<char>(num_buffer[pos]); + digit = (digit < 10) ? '0' + digit : (uppercase ? 'A' : 'a') + digit - 10; + result += AppendChar(buff, buff_end, digit); + } + return result; +} + +static int AppendUnsigned(char **buff, const char *buff_end, u64 num, u8 base, + u8 minimal_num_length, bool pad_with_zero, + bool uppercase) { + return AppendNumber(buff, buff_end, num, base, minimal_num_length, + pad_with_zero, false /* negative */, uppercase); +} + +static int AppendSignedDecimal(char **buff, const char *buff_end, s64 num, + u8 minimal_num_length, bool pad_with_zero) { + bool negative = (num < 0); + return AppendNumber(buff, buff_end, (u64)(negative ? -num : num), 10, + minimal_num_length, pad_with_zero, negative, + false /* uppercase */); +} + + +// Use the fact that explicitly requesting 0 width (%0s) results in UB and +// interpret width == 0 as "no width requested": +// width == 0 - no width requested +// width < 0 - left-justify s within and pad it to -width chars, if necessary +// width > 0 - right-justify s, not implemented yet +static int AppendString(char **buff, const char *buff_end, int width, + int max_chars, const char *s) { + if (!s) + s = "<null>"; + int result = 0; + for (; *s; s++) { + if (max_chars >= 0 && result >= max_chars) + break; + result += AppendChar(buff, buff_end, *s); + } + // Only the left justified strings are supported. + while (width < -result) + result += AppendChar(buff, buff_end, ' '); + return result; +} + +static int AppendPointer(char **buff, const char *buff_end, u64 ptr_value) { + int result = 0; + result += AppendString(buff, buff_end, 0, -1, "0x"); + result += AppendUnsigned(buff, buff_end, ptr_value, 16, + SANITIZER_POINTER_FORMAT_LENGTH, + true /* pad_with_zero */, false /* uppercase */); + return result; +} + +int VSNPrintf(char *buff, int buff_length, + const char *format, va_list args) { + static const char *kPrintfFormatsHelp = + "Supported Printf formats: %([0-9]*)?(z|l|ll)?{d,u,x,X}; %p; " + "%[-]([0-9]*)?(\\.\\*)?s; %c\nProvided format: "; + 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 left_justified = *cur == '-'; + if (left_justified) + cur++; + bool have_width = (*cur >= '0' && *cur <= '9'); + bool pad_with_zero = (*cur == '0'); + int width = 0; + if (have_width) { + while (*cur >= '0' && *cur <= '9') { + width = width * 10 + *cur++ - '0'; + } + } + bool have_precision = (cur[0] == '.' && cur[1] == '*'); + int precision = -1; + if (have_precision) { + cur += 2; + precision = va_arg(args, int); + } + bool have_z = (*cur == 'z'); + cur += have_z; + bool have_l = cur[0] == 'l' && cur[1] != 'l'; + cur += have_l; + bool have_ll = cur[0] == 'l' && cur[1] == 'l'; + cur += have_ll * 2; + const bool have_length = have_z || have_l || have_ll; + const bool have_flags = have_width || have_length; + // At the moment only %s supports precision and left-justification. + CHECK(!((precision >= 0 || left_justified) && *cur != 's')); + switch (*cur) { + case 'd': { + s64 dval = have_ll ? va_arg(args, s64) + : have_z ? va_arg(args, sptr) + : have_l ? va_arg(args, long) + : va_arg(args, int); + result += AppendSignedDecimal(&buff, buff_end, dval, width, + pad_with_zero); + break; + } + case 'u': + case 'x': + case 'X': { + u64 uval = have_ll ? va_arg(args, u64) + : have_z ? va_arg(args, uptr) + : have_l ? va_arg(args, unsigned long) + : va_arg(args, unsigned); + bool uppercase = (*cur == 'X'); + result += AppendUnsigned(&buff, buff_end, uval, (*cur == 'u') ? 10 : 16, + width, pad_with_zero, uppercase); + break; + } + case 'p': { + RAW_CHECK_VA(!have_flags, kPrintfFormatsHelp, format); + result += AppendPointer(&buff, buff_end, va_arg(args, uptr)); + break; + } + case 's': { + RAW_CHECK_VA(!have_length, kPrintfFormatsHelp, format); + // Only left-justified width is supported. + CHECK(!have_width || left_justified); + result += AppendString(&buff, buff_end, left_justified ? -width : width, + precision, va_arg(args, char*)); + break; + } + case 'c': { + RAW_CHECK_VA(!have_flags, kPrintfFormatsHelp, format); + result += AppendChar(&buff, buff_end, va_arg(args, int)); + break; + } + case '%' : { + RAW_CHECK_VA(!have_flags, kPrintfFormatsHelp, format); + result += AppendChar(&buff, buff_end, '%'); + break; + } + default: { + RAW_CHECK_VA(false, kPrintfFormatsHelp, format); + } + } + } + RAW_CHECK(buff <= buff_end); + AppendChar(&buff, buff_end + 1, '\0'); + return result; +} + +static void (*PrintfAndReportCallback)(const char *); +void SetPrintfAndReportCallback(void (*callback)(const char *)) { + PrintfAndReportCallback = callback; +} + +// Can be overriden in frontend. +#if SANITIZER_GO && defined(TSAN_EXTERNAL_HOOKS) +// Implementation must be defined in frontend. +extern "C" void __sanitizer_on_print(const char *str); +#else +SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_on_print, const char *str) { + (void)str; +} +#endif + +static void CallPrintfAndReportCallback(const char *str) { + __sanitizer_on_print(str); + if (PrintfAndReportCallback) + PrintfAndReportCallback(str); +} + +static void NOINLINE SharedPrintfCodeNoBuffer(bool append_pid, + char *local_buffer, + int buffer_size, + const char *format, + va_list args) { + va_list args2; + va_copy(args2, args); + InternalMmapVector<char> v; + int needed_length = 0; + char *buffer = local_buffer; + // First try to print a message using a local buffer, and then fall back to + // mmaped buffer. + for (int use_mmap = 0;; use_mmap++) { + if (use_mmap) { + va_end(args); + va_copy(args, args2); + v.resize(needed_length + 1); + buffer_size = v.capacity(); + v.resize(buffer_size); + buffer = &v[0]; + } + needed_length = 0; + // Fuchsia's logging infrastructure always keeps track of the logging + // process, thread, and timestamp, so never prepend such information. + if (!SANITIZER_FUCHSIA && append_pid) { + int pid = internal_getpid(); + const char *exe_name = GetProcessName(); + if (common_flags()->log_exe_name && exe_name) { + needed_length += internal_snprintf(buffer, buffer_size, + "==%s", exe_name); + if (needed_length >= buffer_size) + continue; + } + needed_length += internal_snprintf( + buffer + needed_length, buffer_size - needed_length, "==%d==", pid); + if (needed_length >= buffer_size) + continue; + } + needed_length += VSNPrintf(buffer + needed_length, + buffer_size - needed_length, format, args); + if (needed_length >= buffer_size) + continue; + // If the message fit into the buffer, print it and exit. + break; + } + RawWrite(buffer); + + // Remove color sequences from the message. + RemoveANSIEscapeSequencesFromString(buffer); + CallPrintfAndReportCallback(buffer); + LogMessageOnPrintf(buffer); + + va_end(args2); +} + +static void NOINLINE SharedPrintfCode(bool append_pid, const char *format, + va_list args) { + // |local_buffer| is small enough not to overflow the stack and/or violate + // the stack limit enforced by TSan (-Wframe-larger-than=512). On the other + // hand, the bigger the buffer is, the more the chance the error report will + // fit into it. + char local_buffer[400]; + SharedPrintfCodeNoBuffer(append_pid, local_buffer, ARRAY_SIZE(local_buffer), + format, args); +} + +void Printf(const char *format, ...) { + va_list args; + va_start(args, format); + SharedPrintfCode(false, format, args); + va_end(args); +} + +// Like Printf, but prints the current PID before the output string. +void Report(const char *format, ...) { + va_list args; + va_start(args, format); + SharedPrintfCode(true, format, args); + va_end(args); +} + +// 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; +} + +void InternalScopedString::append(const char *format, ...) { + uptr prev_len = length(); + + while (true) { + buffer_.resize(buffer_.capacity()); + + va_list args; + va_start(args, format); + uptr sz = VSNPrintf(buffer_.data() + prev_len, buffer_.size() - prev_len, + format, args); + va_end(args); + if (sz < buffer_.size() - prev_len) { + buffer_.resize(prev_len + sz + 1); + break; + } + + buffer_.reserve(buffer_.capacity() * 2); + } + CHECK_EQ(buffer_[length()], '\0'); +} + +} // namespace __sanitizer diff --git a/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_procmaps.h b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_procmaps.h new file mode 100644 index 0000000000..055af366ef --- /dev/null +++ b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_procmaps.h @@ -0,0 +1,110 @@ +//===-- sanitizer_procmaps.h ------------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file is shared between AddressSanitizer and ThreadSanitizer. +// +// Information about the process mappings. +//===----------------------------------------------------------------------===// +#ifndef SANITIZER_PROCMAPS_H +#define SANITIZER_PROCMAPS_H + +#include "sanitizer_platform.h" + +#if SANITIZER_LINUX || SANITIZER_FREEBSD || SANITIZER_NETBSD || \ + SANITIZER_MAC || SANITIZER_SOLARIS || \ + SANITIZER_FUCHSIA + +#include "sanitizer_common.h" +#include "sanitizer_internal_defs.h" +#include "sanitizer_fuchsia.h" +#include "sanitizer_linux.h" +#include "sanitizer_mac.h" +#include "sanitizer_mutex.h" + +namespace __sanitizer { + +// Memory protection masks. +static const uptr kProtectionRead = 1; +static const uptr kProtectionWrite = 2; +static const uptr kProtectionExecute = 4; +static const uptr kProtectionShared = 8; + +struct MemoryMappedSegmentData; + +class MemoryMappedSegment { + public: + explicit MemoryMappedSegment(char *buff = nullptr, uptr size = 0) + : filename(buff), filename_size(size), data_(nullptr) {} + ~MemoryMappedSegment() {} + + bool IsReadable() const { return protection & kProtectionRead; } + bool IsWritable() const { return protection & kProtectionWrite; } + bool IsExecutable() const { return protection & kProtectionExecute; } + bool IsShared() const { return protection & kProtectionShared; } + + void AddAddressRanges(LoadedModule *module); + + uptr start; + uptr end; + uptr offset; + char *filename; // owned by caller + uptr filename_size; + uptr protection; + ModuleArch arch; + u8 uuid[kModuleUUIDSize]; + + private: + friend class MemoryMappingLayout; + + // This field is assigned and owned by MemoryMappingLayout if needed + MemoryMappedSegmentData *data_; +}; + +class MemoryMappingLayoutBase { + public: + virtual bool Next(MemoryMappedSegment *segment) { UNIMPLEMENTED(); } + virtual bool Error() const { UNIMPLEMENTED(); }; + virtual void Reset() { UNIMPLEMENTED(); } + + protected: + ~MemoryMappingLayoutBase() {} +}; + +class MemoryMappingLayout final : public MemoryMappingLayoutBase { + public: + explicit MemoryMappingLayout(bool cache_enabled); + ~MemoryMappingLayout(); + virtual bool Next(MemoryMappedSegment *segment) override; + virtual bool Error() const override; + virtual void Reset() override; + // In some cases, e.g. when running under a sandbox on Linux, ASan is unable + // to obtain the memory mappings. It should fall back to pre-cached data + // instead of aborting. + static void CacheMemoryMappings(); + + // Adds all mapped objects into a vector. + void DumpListOfModules(InternalMmapVectorNoCtor<LoadedModule> *modules); + + private: + void LoadFromCache(); + + MemoryMappingLayoutData data_; +}; + +// Returns code range for the specified module. +bool GetCodeRangeForFile(const char *module, uptr *start, uptr *end); + +bool IsDecimal(char c); +uptr ParseDecimal(const char **p); +bool IsHex(char c); +uptr ParseHex(const char **p); + +} // namespace __sanitizer + +#endif +#endif // SANITIZER_PROCMAPS_H diff --git a/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_procmaps_bsd.cpp b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_procmaps_bsd.cpp new file mode 100644 index 0000000000..1f489b71ad --- /dev/null +++ b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_procmaps_bsd.cpp @@ -0,0 +1,112 @@ +//===-- sanitizer_procmaps_bsd.cpp ----------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// Information about the process mappings +// (FreeBSD and NetBSD-specific parts). +//===----------------------------------------------------------------------===// + +#include "sanitizer_platform.h" +#if SANITIZER_FREEBSD || SANITIZER_NETBSD +#include "sanitizer_common.h" +#if SANITIZER_FREEBSD +#include "sanitizer_freebsd.h" +#endif +#include "sanitizer_procmaps.h" + +// clang-format off +#include <sys/types.h> +#include <sys/sysctl.h> +// clang-format on +#include <unistd.h> +#if SANITIZER_FREEBSD +#include <sys/user.h> +#endif + +#include <limits.h> + +// Fix 'kinfo_vmentry' definition on FreeBSD prior v9.2 in 32-bit mode. +#if SANITIZER_FREEBSD && (SANITIZER_WORDSIZE == 32) +#include <osreldate.h> +#if __FreeBSD_version <= 902001 // v9.2 +#define kinfo_vmentry xkinfo_vmentry +#endif +#endif + +namespace __sanitizer { + +void ReadProcMaps(ProcSelfMapsBuff *proc_maps) { + const int Mib[] = { +#if SANITIZER_FREEBSD + CTL_KERN, + KERN_PROC, + KERN_PROC_VMMAP, + getpid() +#elif SANITIZER_NETBSD + CTL_VM, + VM_PROC, + VM_PROC_MAP, + getpid(), + sizeof(struct kinfo_vmentry) +#else +#error "not supported" +#endif + }; + + uptr Size = 0; + int Err = internal_sysctl(Mib, ARRAY_SIZE(Mib), NULL, &Size, NULL, 0); + CHECK_EQ(Err, 0); + CHECK_GT(Size, 0); + + size_t MmapedSize = Size * 4 / 3; + void *VmMap = MmapOrDie(MmapedSize, "ReadProcMaps()"); + Size = MmapedSize; + Err = internal_sysctl(Mib, ARRAY_SIZE(Mib), VmMap, &Size, NULL, 0); + CHECK_EQ(Err, 0); + proc_maps->data = (char *)VmMap; + proc_maps->mmaped_size = MmapedSize; + proc_maps->len = Size; +} + +bool MemoryMappingLayout::Next(MemoryMappedSegment *segment) { + CHECK(!Error()); // can not fail + char *last = data_.proc_self_maps.data + data_.proc_self_maps.len; + if (data_.current >= last) + return false; + const struct kinfo_vmentry *VmEntry = + (const struct kinfo_vmentry *)data_.current; + + segment->start = (uptr)VmEntry->kve_start; + segment->end = (uptr)VmEntry->kve_end; + segment->offset = (uptr)VmEntry->kve_offset; + + segment->protection = 0; + if ((VmEntry->kve_protection & KVME_PROT_READ) != 0) + segment->protection |= kProtectionRead; + if ((VmEntry->kve_protection & KVME_PROT_WRITE) != 0) + segment->protection |= kProtectionWrite; + if ((VmEntry->kve_protection & KVME_PROT_EXEC) != 0) + segment->protection |= kProtectionExecute; + + if (segment->filename != NULL && segment->filename_size > 0) { + internal_snprintf(segment->filename, + Min(segment->filename_size, (uptr)PATH_MAX), "%s", + VmEntry->kve_path); + } + +#if SANITIZER_FREEBSD + data_.current += VmEntry->kve_structsize; +#else + data_.current += sizeof(*VmEntry); +#endif + + return true; +} + +} // namespace __sanitizer + +#endif diff --git a/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_procmaps_common.cpp b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_procmaps_common.cpp new file mode 100644 index 0000000000..eb351b0f06 --- /dev/null +++ b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_procmaps_common.cpp @@ -0,0 +1,190 @@ +//===-- sanitizer_procmaps_common.cpp -------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// Information about the process mappings (common parts). +//===----------------------------------------------------------------------===// + +#include "sanitizer_platform.h" + +#if SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD || \ + SANITIZER_SOLARIS + +#include "sanitizer_common.h" +#include "sanitizer_placement_new.h" +#include "sanitizer_procmaps.h" + +namespace __sanitizer { + +static ProcSelfMapsBuff cached_proc_self_maps; +static StaticSpinMutex cache_lock; + +static int TranslateDigit(char c) { + if (c >= '0' && c <= '9') + return c - '0'; + if (c >= 'a' && c <= 'f') + return c - 'a' + 10; + if (c >= 'A' && c <= 'F') + return c - 'A' + 10; + return -1; +} + +// Parse a number and promote 'p' up to the first non-digit character. +static uptr ParseNumber(const char **p, int base) { + uptr n = 0; + int d; + CHECK(base >= 2 && base <= 16); + while ((d = TranslateDigit(**p)) >= 0 && d < base) { + n = n * base + d; + (*p)++; + } + return n; +} + +bool IsDecimal(char c) { + int d = TranslateDigit(c); + return d >= 0 && d < 10; +} + +uptr ParseDecimal(const char **p) { + return ParseNumber(p, 10); +} + +bool IsHex(char c) { + int d = TranslateDigit(c); + return d >= 0 && d < 16; +} + +uptr ParseHex(const char **p) { + return ParseNumber(p, 16); +} + +void MemoryMappedSegment::AddAddressRanges(LoadedModule *module) { + // data_ should be unused on this platform + CHECK(!data_); + module->addAddressRange(start, end, IsExecutable(), IsWritable()); +} + +MemoryMappingLayout::MemoryMappingLayout(bool cache_enabled) { + // FIXME: in the future we may want to cache the mappings on demand only. + if (cache_enabled) + CacheMemoryMappings(); + + // Read maps after the cache update to capture the maps/unmaps happening in + // the process of updating. + ReadProcMaps(&data_.proc_self_maps); + if (cache_enabled && data_.proc_self_maps.mmaped_size == 0) + LoadFromCache(); + + Reset(); +} + +bool MemoryMappingLayout::Error() const { + return data_.current == nullptr; +} + +MemoryMappingLayout::~MemoryMappingLayout() { + // Only unmap the buffer if it is different from the cached one. Otherwise + // it will be unmapped when the cache is refreshed. + if (data_.proc_self_maps.data != cached_proc_self_maps.data) + UnmapOrDie(data_.proc_self_maps.data, data_.proc_self_maps.mmaped_size); +} + +void MemoryMappingLayout::Reset() { + data_.current = data_.proc_self_maps.data; +} + +// static +void MemoryMappingLayout::CacheMemoryMappings() { + ProcSelfMapsBuff new_proc_self_maps; + ReadProcMaps(&new_proc_self_maps); + // Don't invalidate the cache if the mappings are unavailable. + if (new_proc_self_maps.mmaped_size == 0) + return; + SpinMutexLock l(&cache_lock); + if (cached_proc_self_maps.mmaped_size) + UnmapOrDie(cached_proc_self_maps.data, cached_proc_self_maps.mmaped_size); + cached_proc_self_maps = new_proc_self_maps; +} + +void MemoryMappingLayout::LoadFromCache() { + SpinMutexLock l(&cache_lock); + if (cached_proc_self_maps.data) + data_.proc_self_maps = cached_proc_self_maps; +} + +void MemoryMappingLayout::DumpListOfModules( + InternalMmapVectorNoCtor<LoadedModule> *modules) { + Reset(); + InternalMmapVector<char> module_name(kMaxPathLength); + MemoryMappedSegment segment(module_name.data(), module_name.size()); + for (uptr i = 0; Next(&segment); i++) { + const char *cur_name = segment.filename; + if (cur_name[0] == '\0') + continue; + // Don't subtract 'cur_beg' from 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. + uptr base_address = (i ? segment.start : 0) - segment.offset; + LoadedModule cur_module; + cur_module.set(cur_name, base_address); + segment.AddAddressRanges(&cur_module); + modules->push_back(cur_module); + } +} + +void GetMemoryProfile(fill_profile_f cb, uptr *stats) { + char *smaps = nullptr; + uptr smaps_cap = 0; + uptr smaps_len = 0; + if (!ReadFileToBuffer("/proc/self/smaps", &smaps, &smaps_cap, &smaps_len)) + return; + ParseUnixMemoryProfile(cb, stats, smaps, smaps_len); + UnmapOrDie(smaps, smaps_cap); +} + +void ParseUnixMemoryProfile(fill_profile_f cb, uptr *stats, char *smaps, + uptr smaps_len) { + uptr start = 0; + bool file = false; + const char *pos = smaps; + char *end = smaps + smaps_len; + if (smaps_len < 2) + return; + // The following parsing can crash on almost every line + // in the case of malformed/truncated input. + // Fixing that is hard b/c e.g. ParseDecimal does not + // even accept end of the buffer and assumes well-formed input. + // So instead we patch end of the input a bit, + // it does not affect well-formed complete inputs. + *--end = 0; + *--end = '\n'; + while (pos < end) { + if (IsHex(pos[0])) { + start = ParseHex(&pos); + for (; *pos != '/' && *pos > '\n'; pos++) {} + file = *pos == '/'; + } else if (internal_strncmp(pos, "Rss:", 4) == 0) { + while (pos < end && !IsDecimal(*pos)) pos++; + uptr rss = ParseDecimal(&pos) * 1024; + cb(start, rss, file, stats); + } + while (*pos++ != '\n') {} + } +} + +} // namespace __sanitizer + +#endif diff --git a/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_procmaps_fuchsia.cpp b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_procmaps_fuchsia.cpp new file mode 100644 index 0000000000..815de7e6c7 --- /dev/null +++ b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_procmaps_fuchsia.cpp @@ -0,0 +1,80 @@ +//===-- sanitizer_procmaps_fuchsia.cpp +//----------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// Information about the process mappings (Fuchsia-specific parts). +//===----------------------------------------------------------------------===// + +#include "sanitizer_platform.h" +#if SANITIZER_FUCHSIA +#error #include <zircon/process.h> +#error #include <zircon/syscalls.h> + +#include "sanitizer_common.h" +#include "sanitizer_procmaps.h" + +namespace __sanitizer { + +// The cache flag is ignored on Fuchsia because a process can always get this +// information via its process-self handle. +MemoryMappingLayout::MemoryMappingLayout(bool) { Reset(); } + +void MemoryMappingLayout::Reset() { + data_.data.clear(); + data_.current = 0; + + size_t count; + zx_status_t status = _zx_object_get_info( + _zx_process_self(), ZX_INFO_PROCESS_MAPS, nullptr, 0, nullptr, &count); + if (status != ZX_OK) { + return; + } + + size_t filled; + do { + data_.data.resize(count); + status = _zx_object_get_info( + _zx_process_self(), ZX_INFO_PROCESS_MAPS, data_.data.data(), + count * sizeof(zx_info_maps_t), &filled, &count); + if (status != ZX_OK) { + data_.data.clear(); + return; + } + } while (filled < count); +} + +MemoryMappingLayout::~MemoryMappingLayout() {} + +bool MemoryMappingLayout::Error() const { return data_.data.empty(); } + +bool MemoryMappingLayout::Next(MemoryMappedSegment *segment) { + while (data_.current < data_.data.size()) { + const auto &entry = data_.data[data_.current++]; + if (entry.type == ZX_INFO_MAPS_TYPE_MAPPING) { + segment->start = entry.base; + segment->end = entry.base + entry.size; + segment->offset = entry.u.mapping.vmo_offset; + const auto flags = entry.u.mapping.mmu_flags; + segment->protection = + ((flags & ZX_VM_PERM_READ) ? kProtectionRead : 0) | + ((flags & ZX_VM_PERM_WRITE) ? kProtectionWrite : 0) | + ((flags & ZX_VM_PERM_EXECUTE) ? kProtectionExecute : 0); + if (segment->filename && segment->filename_size > 0) { + uptr len = Min(sizeof(entry.name), segment->filename_size) - 1; + internal_strncpy(segment->filename, entry.name, len); + segment->filename[len] = 0; + } + return true; + } + } + return false; +} + +} // namespace __sanitizer + +#endif // SANITIZER_FUCHSIA diff --git a/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_procmaps_linux.cpp b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_procmaps_linux.cpp new file mode 100644 index 0000000000..c7af57355b --- /dev/null +++ b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_procmaps_linux.cpp @@ -0,0 +1,81 @@ +//===-- sanitizer_procmaps_linux.cpp --------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// Information about the process mappings (Linux-specific parts). +//===----------------------------------------------------------------------===// + +#include "sanitizer_platform.h" +#if SANITIZER_LINUX +#include "sanitizer_common.h" +#include "sanitizer_procmaps.h" + +namespace __sanitizer { + +void ReadProcMaps(ProcSelfMapsBuff *proc_maps) { + if (!ReadFileToBuffer("/proc/self/maps", &proc_maps->data, + &proc_maps->mmaped_size, &proc_maps->len)) { + proc_maps->data = nullptr; + proc_maps->mmaped_size = 0; + proc_maps->len = 0; + } +} + +static bool IsOneOf(char c, char c1, char c2) { + return c == c1 || c == c2; +} + +bool MemoryMappingLayout::Next(MemoryMappedSegment *segment) { + if (Error()) return false; // simulate empty maps + char *last = data_.proc_self_maps.data + data_.proc_self_maps.len; + if (data_.current >= last) return false; + char *next_line = + (char *)internal_memchr(data_.current, '\n', last - data_.current); + if (next_line == 0) + next_line = last; + // Example: 08048000-08056000 r-xp 00000000 03:0c 64593 /foo/bar + segment->start = ParseHex(&data_.current); + CHECK_EQ(*data_.current++, '-'); + segment->end = ParseHex(&data_.current); + CHECK_EQ(*data_.current++, ' '); + CHECK(IsOneOf(*data_.current, '-', 'r')); + segment->protection = 0; + if (*data_.current++ == 'r') segment->protection |= kProtectionRead; + CHECK(IsOneOf(*data_.current, '-', 'w')); + if (*data_.current++ == 'w') segment->protection |= kProtectionWrite; + CHECK(IsOneOf(*data_.current, '-', 'x')); + if (*data_.current++ == 'x') segment->protection |= kProtectionExecute; + CHECK(IsOneOf(*data_.current, 's', 'p')); + if (*data_.current++ == 's') segment->protection |= kProtectionShared; + CHECK_EQ(*data_.current++, ' '); + segment->offset = ParseHex(&data_.current); + CHECK_EQ(*data_.current++, ' '); + ParseHex(&data_.current); + CHECK_EQ(*data_.current++, ':'); + ParseHex(&data_.current); + CHECK_EQ(*data_.current++, ' '); + while (IsDecimal(*data_.current)) data_.current++; + // Qemu may lack the trailing space. + // https://github.com/google/sanitizers/issues/160 + // CHECK_EQ(*data_.current++, ' '); + // Skip spaces. + while (data_.current < next_line && *data_.current == ' ') data_.current++; + // Fill in the filename. + if (segment->filename) { + uptr len = + Min((uptr)(next_line - data_.current), segment->filename_size - 1); + internal_strncpy(segment->filename, data_.current, len); + segment->filename[len] = 0; + } + + data_.current = next_line + 1; + return true; +} + +} // namespace __sanitizer + +#endif // SANITIZER_LINUX diff --git a/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_procmaps_mac.cpp b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_procmaps_mac.cpp new file mode 100644 index 0000000000..62b2e5e032 --- /dev/null +++ b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_procmaps_mac.cpp @@ -0,0 +1,379 @@ +//===-- sanitizer_procmaps_mac.cpp ----------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// Information about the process mappings (Mac-specific parts). +//===----------------------------------------------------------------------===// + +#include "sanitizer_platform.h" +#if SANITIZER_MAC +#include "sanitizer_common.h" +#include "sanitizer_placement_new.h" +#include "sanitizer_procmaps.h" + +#include <mach-o/dyld.h> +#include <mach-o/loader.h> +#include <mach/mach.h> + +// These are not available in older macOS SDKs. +#ifndef CPU_SUBTYPE_X86_64_H +#define CPU_SUBTYPE_X86_64_H ((cpu_subtype_t)8) /* Haswell */ +#endif +#ifndef CPU_SUBTYPE_ARM_V7S +#define CPU_SUBTYPE_ARM_V7S ((cpu_subtype_t)11) /* Swift */ +#endif +#ifndef CPU_SUBTYPE_ARM_V7K +#define CPU_SUBTYPE_ARM_V7K ((cpu_subtype_t)12) +#endif +#ifndef CPU_TYPE_ARM64 +#define CPU_TYPE_ARM64 (CPU_TYPE_ARM | CPU_ARCH_ABI64) +#endif + +namespace __sanitizer { + +// Contains information used to iterate through sections. +struct MemoryMappedSegmentData { + char name[kMaxSegName]; + uptr nsects; + const char *current_load_cmd_addr; + u32 lc_type; + uptr base_virt_addr; + uptr addr_mask; +}; + +template <typename Section> +static void NextSectionLoad(LoadedModule *module, MemoryMappedSegmentData *data, + bool isWritable) { + const Section *sc = (const Section *)data->current_load_cmd_addr; + data->current_load_cmd_addr += sizeof(Section); + + uptr sec_start = (sc->addr & data->addr_mask) + data->base_virt_addr; + uptr sec_end = sec_start + sc->size; + module->addAddressRange(sec_start, sec_end, /*executable=*/false, isWritable, + sc->sectname); +} + +void MemoryMappedSegment::AddAddressRanges(LoadedModule *module) { + // Don't iterate over sections when the caller hasn't set up the + // data pointer, when there are no sections, or when the segment + // is executable. Avoid iterating over executable sections because + // it will confuse libignore, and because the extra granularity + // of information is not needed by any sanitizers. + if (!data_ || !data_->nsects || IsExecutable()) { + module->addAddressRange(start, end, IsExecutable(), IsWritable(), + data_ ? data_->name : nullptr); + return; + } + + do { + if (data_->lc_type == LC_SEGMENT) { + NextSectionLoad<struct section>(module, data_, IsWritable()); +#ifdef MH_MAGIC_64 + } else if (data_->lc_type == LC_SEGMENT_64) { + NextSectionLoad<struct section_64>(module, data_, IsWritable()); +#endif + } + } while (--data_->nsects); +} + +MemoryMappingLayout::MemoryMappingLayout(bool cache_enabled) { + Reset(); +} + +MemoryMappingLayout::~MemoryMappingLayout() { +} + +bool MemoryMappingLayout::Error() const { + return false; +} + +// 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 MemoryMappingLayout::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 MemoryMappingLayout + // state. + data_.current_image = _dyld_image_count(); + data_.current_load_cmd_count = -1; + data_.current_load_cmd_addr = 0; + data_.current_magic = 0; + data_.current_filetype = 0; + data_.current_arch = kModuleArchUnknown; + internal_memset(data_.current_uuid, 0, kModuleUUIDSize); +} + +// The dyld load address should be unchanged throughout process execution, +// and it is expensive to compute once many libraries have been loaded, +// so cache it here and do not reset. +static mach_header *dyld_hdr = 0; +static const char kDyldPath[] = "/usr/lib/dyld"; +static const int kDyldImageIdx = -1; + +// static +void MemoryMappingLayout::CacheMemoryMappings() { + // No-op on Mac for now. +} + +void MemoryMappingLayout::LoadFromCache() { + // No-op on Mac for now. +} + +// _dyld_get_image_header() and related APIs don't report dyld itself. +// We work around this by manually recursing through the memory map +// until we hit a Mach header matching dyld instead. These recurse +// calls are expensive, but the first memory map generation occurs +// early in the process, when dyld is one of the only images loaded, +// so it will be hit after only a few iterations. +static mach_header *get_dyld_image_header() { + vm_address_t address = 0; + + while (true) { + vm_size_t size = 0; + unsigned depth = 1; + struct vm_region_submap_info_64 info; + mach_msg_type_number_t count = VM_REGION_SUBMAP_INFO_COUNT_64; + kern_return_t err = + vm_region_recurse_64(mach_task_self(), &address, &size, &depth, + (vm_region_info_t)&info, &count); + if (err != KERN_SUCCESS) return nullptr; + + if (size >= sizeof(mach_header) && info.protection & kProtectionRead) { + mach_header *hdr = (mach_header *)address; + if ((hdr->magic == MH_MAGIC || hdr->magic == MH_MAGIC_64) && + hdr->filetype == MH_DYLINKER) { + return hdr; + } + } + address += size; + } +} + +const mach_header *get_dyld_hdr() { + if (!dyld_hdr) dyld_hdr = get_dyld_image_header(); + + return dyld_hdr; +} + +// Next and NextSegmentLoad were inspired by base/sysinfo.cc in +// Google Perftools, https://github.com/gperftools/gperftools. + +// 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> +static bool NextSegmentLoad(MemoryMappedSegment *segment, + MemoryMappedSegmentData *seg_data, + MemoryMappingLayoutData *layout_data) { + const char *lc = layout_data->current_load_cmd_addr; + layout_data->current_load_cmd_addr += ((const load_command *)lc)->cmdsize; + if (((const load_command *)lc)->cmd == kLCSegment) { + const SegmentCommand* sc = (const SegmentCommand *)lc; + uptr base_virt_addr, addr_mask; + if (layout_data->current_image == kDyldImageIdx) { + base_virt_addr = (uptr)get_dyld_hdr(); + // vmaddr is masked with 0xfffff because on macOS versions < 10.12, + // it contains an absolute address rather than an offset for dyld. + // To make matters even more complicated, this absolute address + // isn't actually the absolute segment address, but the offset portion + // of the address is accurate when combined with the dyld base address, + // and the mask will give just this offset. + addr_mask = 0xfffff; + } else { + base_virt_addr = + (uptr)_dyld_get_image_vmaddr_slide(layout_data->current_image); + addr_mask = ~0; + } + + segment->start = (sc->vmaddr & addr_mask) + base_virt_addr; + segment->end = segment->start + sc->vmsize; + // Most callers don't need section information, so only fill this struct + // when required. + if (seg_data) { + seg_data->nsects = sc->nsects; + seg_data->current_load_cmd_addr = + (const char *)lc + sizeof(SegmentCommand); + seg_data->lc_type = kLCSegment; + seg_data->base_virt_addr = base_virt_addr; + seg_data->addr_mask = addr_mask; + internal_strncpy(seg_data->name, sc->segname, + ARRAY_SIZE(seg_data->name)); + } + + // Return the initial protection. + segment->protection = sc->initprot; + segment->offset = (layout_data->current_filetype == + /*MH_EXECUTE*/ 0x2) + ? sc->vmaddr + : sc->fileoff; + if (segment->filename) { + const char *src = (layout_data->current_image == kDyldImageIdx) + ? kDyldPath + : _dyld_get_image_name(layout_data->current_image); + internal_strncpy(segment->filename, src, segment->filename_size); + } + segment->arch = layout_data->current_arch; + internal_memcpy(segment->uuid, layout_data->current_uuid, kModuleUUIDSize); + return true; + } + return false; +} + +ModuleArch ModuleArchFromCpuType(cpu_type_t cputype, cpu_subtype_t cpusubtype) { + cpusubtype = cpusubtype & ~CPU_SUBTYPE_MASK; + switch (cputype) { + case CPU_TYPE_I386: + return kModuleArchI386; + case CPU_TYPE_X86_64: + if (cpusubtype == CPU_SUBTYPE_X86_64_ALL) return kModuleArchX86_64; + if (cpusubtype == CPU_SUBTYPE_X86_64_H) return kModuleArchX86_64H; + CHECK(0 && "Invalid subtype of x86_64"); + return kModuleArchUnknown; + case CPU_TYPE_ARM: + if (cpusubtype == CPU_SUBTYPE_ARM_V6) return kModuleArchARMV6; + if (cpusubtype == CPU_SUBTYPE_ARM_V7) return kModuleArchARMV7; + if (cpusubtype == CPU_SUBTYPE_ARM_V7S) return kModuleArchARMV7S; + if (cpusubtype == CPU_SUBTYPE_ARM_V7K) return kModuleArchARMV7K; + CHECK(0 && "Invalid subtype of ARM"); + return kModuleArchUnknown; + case CPU_TYPE_ARM64: + return kModuleArchARM64; + default: + CHECK(0 && "Invalid CPU type"); + return kModuleArchUnknown; + } +} + +static const load_command *NextCommand(const load_command *lc) { + return (const load_command *)((const char *)lc + lc->cmdsize); +} + +static void FindUUID(const load_command *first_lc, u8 *uuid_output) { + for (const load_command *lc = first_lc; lc->cmd != 0; lc = NextCommand(lc)) { + if (lc->cmd != LC_UUID) continue; + + const uuid_command *uuid_lc = (const uuid_command *)lc; + const uint8_t *uuid = &uuid_lc->uuid[0]; + internal_memcpy(uuid_output, uuid, kModuleUUIDSize); + return; + } +} + +static bool IsModuleInstrumented(const load_command *first_lc) { + for (const load_command *lc = first_lc; lc->cmd != 0; lc = NextCommand(lc)) { + if (lc->cmd != LC_LOAD_DYLIB) continue; + + const dylib_command *dylib_lc = (const dylib_command *)lc; + uint32_t dylib_name_offset = dylib_lc->dylib.name.offset; + const char *dylib_name = ((const char *)dylib_lc) + dylib_name_offset; + dylib_name = StripModuleName(dylib_name); + if (dylib_name != 0 && (internal_strstr(dylib_name, "libclang_rt."))) { + return true; + } + } + return false; +} + +bool MemoryMappingLayout::Next(MemoryMappedSegment *segment) { + for (; data_.current_image >= kDyldImageIdx; data_.current_image--) { + const mach_header *hdr = (data_.current_image == kDyldImageIdx) + ? get_dyld_hdr() + : _dyld_get_image_header(data_.current_image); + if (!hdr) continue; + if (data_.current_load_cmd_count < 0) { + // Set up for this image; + data_.current_load_cmd_count = hdr->ncmds; + data_.current_magic = hdr->magic; + data_.current_filetype = hdr->filetype; + data_.current_arch = ModuleArchFromCpuType(hdr->cputype, hdr->cpusubtype); + switch (data_.current_magic) { +#ifdef MH_MAGIC_64 + case MH_MAGIC_64: { + data_.current_load_cmd_addr = + (const char *)hdr + sizeof(mach_header_64); + break; + } +#endif + case MH_MAGIC: { + data_.current_load_cmd_addr = (const char *)hdr + sizeof(mach_header); + break; + } + default: { + continue; + } + } + FindUUID((const load_command *)data_.current_load_cmd_addr, + data_.current_uuid); + data_.current_instrumented = IsModuleInstrumented( + (const load_command *)data_.current_load_cmd_addr); + } + + for (; data_.current_load_cmd_count >= 0; data_.current_load_cmd_count--) { + switch (data_.current_magic) { + // data_.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>( + segment, segment->data_, &data_)) + return true; + break; + } +#endif + case MH_MAGIC: { + if (NextSegmentLoad<LC_SEGMENT, struct segment_command>( + segment, segment->data_, &data_)) + 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; +} + +void MemoryMappingLayout::DumpListOfModules( + InternalMmapVectorNoCtor<LoadedModule> *modules) { + Reset(); + InternalMmapVector<char> module_name(kMaxPathLength); + MemoryMappedSegment segment(module_name.data(), module_name.size()); + MemoryMappedSegmentData data; + segment.data_ = &data; + while (Next(&segment)) { + if (segment.filename[0] == '\0') continue; + LoadedModule *cur_module = nullptr; + if (!modules->empty() && + 0 == internal_strcmp(segment.filename, modules->back().full_name())) { + cur_module = &modules->back(); + } else { + modules->push_back(LoadedModule()); + cur_module = &modules->back(); + cur_module->set(segment.filename, segment.start, segment.arch, + segment.uuid, data_.current_instrumented); + } + segment.AddAddressRanges(cur_module); + } +} + +} // namespace __sanitizer + +#endif // SANITIZER_MAC diff --git a/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_procmaps_solaris.cpp b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_procmaps_solaris.cpp new file mode 100644 index 0000000000..e16c4e938c --- /dev/null +++ b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_procmaps_solaris.cpp @@ -0,0 +1,76 @@ +//===-- sanitizer_procmaps_solaris.cpp ------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// Information about the process mappings (Solaris-specific parts). +//===----------------------------------------------------------------------===// + +// Before Solaris 11.4, <procfs.h> doesn't work in a largefile environment. +#undef _FILE_OFFSET_BITS +#include "sanitizer_platform.h" +#if SANITIZER_SOLARIS +#include "sanitizer_common.h" +#include "sanitizer_procmaps.h" + +#include <procfs.h> +#include <limits.h> + +namespace __sanitizer { + +void ReadProcMaps(ProcSelfMapsBuff *proc_maps) { + if (!ReadFileToBuffer("/proc/self/xmap", &proc_maps->data, + &proc_maps->mmaped_size, &proc_maps->len)) { + proc_maps->data = nullptr; + proc_maps->mmaped_size = 0; + proc_maps->len = 0; + } +} + +bool MemoryMappingLayout::Next(MemoryMappedSegment *segment) { + if (Error()) return false; // simulate empty maps + char *last = data_.proc_self_maps.data + data_.proc_self_maps.len; + if (data_.current >= last) return false; + + prxmap_t *xmapentry = + const_cast<prxmap_t *>(reinterpret_cast<const prxmap_t *>(data_.current)); + + segment->start = (uptr)xmapentry->pr_vaddr; + segment->end = (uptr)(xmapentry->pr_vaddr + xmapentry->pr_size); + segment->offset = (uptr)xmapentry->pr_offset; + + segment->protection = 0; + if ((xmapentry->pr_mflags & MA_READ) != 0) + segment->protection |= kProtectionRead; + if ((xmapentry->pr_mflags & MA_WRITE) != 0) + segment->protection |= kProtectionWrite; + if ((xmapentry->pr_mflags & MA_EXEC) != 0) + segment->protection |= kProtectionExecute; + + if (segment->filename != NULL && segment->filename_size > 0) { + char proc_path[PATH_MAX + 1]; + + internal_snprintf(proc_path, sizeof(proc_path), "/proc/self/path/%s", + xmapentry->pr_mapname); + ssize_t sz = internal_readlink(proc_path, segment->filename, + segment->filename_size - 1); + + // If readlink failed, the map is anonymous. + if (sz == -1) { + segment->filename[0] = '\0'; + } else if ((size_t)sz < segment->filename_size) + // readlink doesn't NUL-terminate. + segment->filename[sz] = '\0'; + } + + data_.current += sizeof(prxmap_t); + + return true; +} + +} // namespace __sanitizer + +#endif // SANITIZER_SOLARIS diff --git a/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_ptrauth.h b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_ptrauth.h new file mode 100644 index 0000000000..cb1e5366f9 --- /dev/null +++ b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_ptrauth.h @@ -0,0 +1,41 @@ +//===-- sanitizer_ptrauth.h -------------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef SANITIZER_PTRAUTH_H +#define SANITIZER_PTRAUTH_H + +#if __has_feature(ptrauth_calls) +#error #include <ptrauth.h> +#elif defined(__ARM_FEATURE_PAC_DEFAULT) && !defined(__APPLE__) +inline unsigned long ptrauth_strip(void* __value, unsigned int __key) { + // On the stack the link register is protected with Pointer + // Authentication Code when compiled with -mbranch-protection. + // Let's stripping the PAC unconditionally because xpaclri is in + // the NOP space so will do nothing when it is not enabled or not available. + unsigned long ret; + asm volatile( + "mov x30, %1\n\t" + "hint #7\n\t" // xpaclri + "mov %0, x30\n\t" + : "=r"(ret) + : "r"(__value) + : "x30"); + return ret; +} +#define ptrauth_auth_data(__value, __old_key, __old_data) __value +#define ptrauth_string_discriminator(__string) ((int)0) +#else +// Copied from <ptrauth.h> +#define ptrauth_strip(__value, __key) __value +#define ptrauth_auth_data(__value, __old_key, __old_data) __value +#define ptrauth_string_discriminator(__string) ((int)0) +#endif + +#define STRIP_PAC_PC(pc) ((uptr)ptrauth_strip(pc, 0)) + +#endif // SANITIZER_PTRAUTH_H diff --git a/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_quarantine.h b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_quarantine.h new file mode 100644 index 0000000000..4aa6054851 --- /dev/null +++ b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_quarantine.h @@ -0,0 +1,318 @@ +//===-- sanitizer_quarantine.h ----------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// Memory quarantine for AddressSanitizer and potentially other tools. +// Quarantine caches some specified amount of memory in per-thread caches, +// then evicts to global FIFO queue. When the queue reaches specified threshold, +// oldest memory is recycled. +// +//===----------------------------------------------------------------------===// + +#ifndef SANITIZER_QUARANTINE_H +#define SANITIZER_QUARANTINE_H + +#include "sanitizer_internal_defs.h" +#include "sanitizer_mutex.h" +#include "sanitizer_list.h" + +namespace __sanitizer { + +template<typename Node> class QuarantineCache; + +struct QuarantineBatch { + static const uptr kSize = 1021; + QuarantineBatch *next; + uptr size; + uptr count; + void *batch[kSize]; + + void init(void *ptr, uptr size) { + count = 1; + batch[0] = ptr; + this->size = size + sizeof(QuarantineBatch); // Account for the batch size. + } + + // The total size of quarantined nodes recorded in this batch. + uptr quarantined_size() const { + return size - sizeof(QuarantineBatch); + } + + void push_back(void *ptr, uptr size) { + CHECK_LT(count, kSize); + batch[count++] = ptr; + this->size += size; + } + + bool can_merge(const QuarantineBatch* const from) const { + return count + from->count <= kSize; + } + + void merge(QuarantineBatch* const from) { + CHECK_LE(count + from->count, kSize); + CHECK_GE(size, sizeof(QuarantineBatch)); + + for (uptr i = 0; i < from->count; ++i) + batch[count + i] = from->batch[i]; + count += from->count; + size += from->quarantined_size(); + + from->count = 0; + from->size = sizeof(QuarantineBatch); + } +}; + +COMPILER_CHECK(sizeof(QuarantineBatch) <= (1 << 13)); // 8Kb. + +// The callback interface is: +// void Callback::Recycle(Node *ptr); +// void *cb.Allocate(uptr size); +// void cb.Deallocate(void *ptr); +template<typename Callback, typename Node> +class Quarantine { + public: + typedef QuarantineCache<Callback> Cache; + + explicit Quarantine(LinkerInitialized) + : cache_(LINKER_INITIALIZED) { + } + + void Init(uptr size, uptr cache_size) { + // Thread local quarantine size can be zero only when global quarantine size + // is zero (it allows us to perform just one atomic read per Put() call). + CHECK((size == 0 && cache_size == 0) || cache_size != 0); + + atomic_store_relaxed(&max_size_, size); + atomic_store_relaxed(&min_size_, size / 10 * 9); // 90% of max size. + atomic_store_relaxed(&max_cache_size_, cache_size); + + cache_mutex_.Init(); + recycle_mutex_.Init(); + } + + uptr GetSize() const { return atomic_load_relaxed(&max_size_); } + uptr GetCacheSize() const { + return atomic_load_relaxed(&max_cache_size_); + } + + void Put(Cache *c, Callback cb, Node *ptr, uptr size) { + uptr cache_size = GetCacheSize(); + if (cache_size) { + c->Enqueue(cb, ptr, size); + } else { + // GetCacheSize() == 0 only when GetSize() == 0 (see Init). + cb.Recycle(ptr); + } + // Check cache size anyway to accommodate for runtime cache_size change. + if (c->Size() > cache_size) + Drain(c, cb); + } + + void NOINLINE Drain(Cache *c, Callback cb) { + { + SpinMutexLock l(&cache_mutex_); + cache_.Transfer(c); + } + if (cache_.Size() > GetSize() && recycle_mutex_.TryLock()) + Recycle(atomic_load_relaxed(&min_size_), cb); + } + + void NOINLINE DrainAndRecycle(Cache *c, Callback cb) { + { + SpinMutexLock l(&cache_mutex_); + cache_.Transfer(c); + } + recycle_mutex_.Lock(); + Recycle(0, cb); + } + + void PrintStats() const { + // It assumes that the world is stopped, just as the allocator's PrintStats. + Printf("Quarantine limits: global: %zdMb; thread local: %zdKb\n", + GetSize() >> 20, GetCacheSize() >> 10); + cache_.PrintStats(); + } + + private: + // Read-only data. + char pad0_[kCacheLineSize]; + atomic_uintptr_t max_size_; + atomic_uintptr_t min_size_; + atomic_uintptr_t max_cache_size_; + char pad1_[kCacheLineSize]; + StaticSpinMutex cache_mutex_; + StaticSpinMutex recycle_mutex_; + Cache cache_; + char pad2_[kCacheLineSize]; + + void NOINLINE Recycle(uptr min_size, Callback cb) + SANITIZER_REQUIRES(recycle_mutex_) SANITIZER_RELEASE(recycle_mutex_) { + Cache tmp; + { + SpinMutexLock l(&cache_mutex_); + // Go over the batches and merge partially filled ones to + // save some memory, otherwise batches themselves (since the memory used + // by them is counted against quarantine limit) can overcome the actual + // user's quarantined chunks, which diminishes the purpose of the + // quarantine. + uptr cache_size = cache_.Size(); + uptr overhead_size = cache_.OverheadSize(); + CHECK_GE(cache_size, overhead_size); + // Do the merge only when overhead exceeds this predefined limit (might + // require some tuning). It saves us merge attempt when the batch list + // quarantine is unlikely to contain batches suitable for merge. + const uptr kOverheadThresholdPercents = 100; + if (cache_size > overhead_size && + overhead_size * (100 + kOverheadThresholdPercents) > + cache_size * kOverheadThresholdPercents) { + cache_.MergeBatches(&tmp); + } + // Extract enough chunks from the quarantine to get below the max + // quarantine size and leave some leeway for the newly quarantined chunks. + while (cache_.Size() > min_size) { + tmp.EnqueueBatch(cache_.DequeueBatch()); + } + } + recycle_mutex_.Unlock(); + DoRecycle(&tmp, cb); + } + + void NOINLINE DoRecycle(Cache *c, Callback cb) { + while (QuarantineBatch *b = c->DequeueBatch()) { + const uptr kPrefetch = 16; + CHECK(kPrefetch <= ARRAY_SIZE(b->batch)); + for (uptr i = 0; i < kPrefetch; i++) + PREFETCH(b->batch[i]); + for (uptr i = 0, count = b->count; i < count; i++) { + if (i + kPrefetch < count) + PREFETCH(b->batch[i + kPrefetch]); + cb.Recycle((Node*)b->batch[i]); + } + cb.Deallocate(b); + } + } +}; + +// Per-thread cache of memory blocks. +template<typename Callback> +class QuarantineCache { + public: + explicit QuarantineCache(LinkerInitialized) { + } + + QuarantineCache() + : size_() { + list_.clear(); + } + + // Total memory used, including internal accounting. + uptr Size() const { + return atomic_load_relaxed(&size_); + } + + // Memory used for internal accounting. + uptr OverheadSize() const { + return list_.size() * sizeof(QuarantineBatch); + } + + void Enqueue(Callback cb, void *ptr, uptr size) { + if (list_.empty() || list_.back()->count == QuarantineBatch::kSize) { + QuarantineBatch *b = (QuarantineBatch *)cb.Allocate(sizeof(*b)); + CHECK(b); + b->init(ptr, size); + EnqueueBatch(b); + } else { + list_.back()->push_back(ptr, size); + SizeAdd(size); + } + } + + void Transfer(QuarantineCache *from_cache) { + list_.append_back(&from_cache->list_); + SizeAdd(from_cache->Size()); + + atomic_store_relaxed(&from_cache->size_, 0); + } + + void EnqueueBatch(QuarantineBatch *b) { + list_.push_back(b); + SizeAdd(b->size); + } + + QuarantineBatch *DequeueBatch() { + if (list_.empty()) + return nullptr; + QuarantineBatch *b = list_.front(); + list_.pop_front(); + SizeSub(b->size); + return b; + } + + void MergeBatches(QuarantineCache *to_deallocate) { + uptr extracted_size = 0; + QuarantineBatch *current = list_.front(); + while (current && current->next) { + if (current->can_merge(current->next)) { + QuarantineBatch *extracted = current->next; + // Move all the chunks into the current batch. + current->merge(extracted); + CHECK_EQ(extracted->count, 0); + CHECK_EQ(extracted->size, sizeof(QuarantineBatch)); + // Remove the next batch from the list and account for its size. + list_.extract(current, extracted); + extracted_size += extracted->size; + // Add it to deallocation list. + to_deallocate->EnqueueBatch(extracted); + } else { + current = current->next; + } + } + SizeSub(extracted_size); + } + + void PrintStats() const { + uptr batch_count = 0; + uptr total_overhead_bytes = 0; + uptr total_bytes = 0; + uptr total_quarantine_chunks = 0; + for (List::ConstIterator it = list_.begin(); it != list_.end(); ++it) { + batch_count++; + total_bytes += (*it).size; + total_overhead_bytes += (*it).size - (*it).quarantined_size(); + total_quarantine_chunks += (*it).count; + } + uptr quarantine_chunks_capacity = batch_count * QuarantineBatch::kSize; + int chunks_usage_percent = quarantine_chunks_capacity == 0 ? + 0 : total_quarantine_chunks * 100 / quarantine_chunks_capacity; + uptr total_quarantined_bytes = total_bytes - total_overhead_bytes; + int memory_overhead_percent = total_quarantined_bytes == 0 ? + 0 : total_overhead_bytes * 100 / total_quarantined_bytes; + Printf("Global quarantine stats: batches: %zd; bytes: %zd (user: %zd); " + "chunks: %zd (capacity: %zd); %d%% chunks used; %d%% memory overhead" + "\n", + batch_count, total_bytes, total_quarantined_bytes, + total_quarantine_chunks, quarantine_chunks_capacity, + chunks_usage_percent, memory_overhead_percent); + } + + private: + typedef IntrusiveList<QuarantineBatch> List; + + List list_; + atomic_uintptr_t size_; + + void SizeAdd(uptr add) { + atomic_store_relaxed(&size_, Size() + add); + } + void SizeSub(uptr sub) { + atomic_store_relaxed(&size_, Size() - sub); + } +}; + +} // namespace __sanitizer + +#endif // SANITIZER_QUARANTINE_H diff --git a/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_report_decorator.h b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_report_decorator.h new file mode 100644 index 0000000000..d276c2cdd8 --- /dev/null +++ b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_report_decorator.h @@ -0,0 +1,48 @@ +//===-- sanitizer_report_decorator.h ----------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// Tags to decorate the sanitizer reports. +// Currently supported tags: +// * None. +// * ANSI color sequences. +// +//===----------------------------------------------------------------------===// + +#ifndef SANITIZER_REPORT_DECORATOR_H +#define SANITIZER_REPORT_DECORATOR_H + +#include "sanitizer_common.h" + +namespace __sanitizer { +class SanitizerCommonDecorator { + // FIXME: This is not portable. It assumes the special strings are printed to + // stdout, which is not the case on Windows (see SetConsoleTextAttribute()). + public: + SanitizerCommonDecorator() : ansi_(ColorizeReports()) {} + const char *Bold() const { return ansi_ ? "\033[1m" : ""; } + const char *Default() const { return ansi_ ? "\033[1m\033[0m" : ""; } + const char *Warning() const { return Red(); } + const char *Error() const { return Red(); } + const char *MemoryByte() const { return Magenta(); } + + protected: + const char *Black() const { return ansi_ ? "\033[1m\033[30m" : ""; } + const char *Red() const { return ansi_ ? "\033[1m\033[31m" : ""; } + const char *Green() const { return ansi_ ? "\033[1m\033[32m" : ""; } + const char *Yellow() const { return ansi_ ? "\033[1m\033[33m" : ""; } + const char *Blue() const { return ansi_ ? "\033[1m\033[34m" : ""; } + const char *Magenta() const { return ansi_ ? "\033[1m\033[35m" : ""; } + const char *Cyan() const { return ansi_ ? "\033[1m\033[36m" : ""; } + const char *White() const { return ansi_ ? "\033[1m\033[37m" : ""; } + private: + bool ansi_; +}; + +} // namespace __sanitizer + +#endif // SANITIZER_REPORT_DECORATOR_H diff --git a/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_ring_buffer.h b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_ring_buffer.h new file mode 100644 index 0000000000..2a46e933b7 --- /dev/null +++ b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_ring_buffer.h @@ -0,0 +1,161 @@ +//===-- sanitizer_ring_buffer.h ---------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// Simple ring buffer. +// +//===----------------------------------------------------------------------===// +#ifndef SANITIZER_RING_BUFFER_H +#define SANITIZER_RING_BUFFER_H + +#include "sanitizer_common.h" + +namespace __sanitizer { +// RingBuffer<T>: fixed-size ring buffer optimized for speed of push(). +// T should be a POD type and sizeof(T) should be divisible by sizeof(void*). +// At creation, all elements are zero. +template<class T> +class RingBuffer { + public: + COMPILER_CHECK(sizeof(T) % sizeof(void *) == 0); + static RingBuffer *New(uptr Size) { + void *Ptr = MmapOrDie(SizeInBytes(Size), "RingBuffer"); + RingBuffer *RB = reinterpret_cast<RingBuffer*>(Ptr); + uptr End = reinterpret_cast<uptr>(Ptr) + SizeInBytes(Size); + RB->last_ = RB->next_ = reinterpret_cast<T*>(End - sizeof(T)); + return RB; + } + void Delete() { + UnmapOrDie(this, SizeInBytes(size())); + } + uptr size() const { + return last_ + 1 - + reinterpret_cast<T *>(reinterpret_cast<uptr>(this) + + 2 * sizeof(T *)); + } + + static uptr SizeInBytes(uptr Size) { + return Size * sizeof(T) + 2 * sizeof(T*); + } + + uptr SizeInBytes() { return SizeInBytes(size()); } + + void push(T t) { + *next_ = t; + next_--; + // The condition below works only if sizeof(T) is divisible by sizeof(T*). + if (next_ <= reinterpret_cast<T*>(&next_)) + next_ = last_; + } + + T operator[](uptr Idx) const { + CHECK_LT(Idx, size()); + sptr IdxNext = Idx + 1; + if (IdxNext > last_ - next_) + IdxNext -= size(); + return next_[IdxNext]; + } + + private: + RingBuffer() {} + ~RingBuffer() {} + RingBuffer(const RingBuffer&) = delete; + + // Data layout: + // LNDDDDDDDD + // D: data elements. + // L: last_, always points to the last data element. + // N: next_, initially equals to last_, is decremented on every push, + // wraps around if it's less or equal than its own address. + T *last_; + T *next_; + T data_[1]; // flexible array. +}; + +// A ring buffer with externally provided storage that encodes its state in 8 +// bytes. Has significant constraints on size and alignment of storage. +// See a comment in hwasan/hwasan_thread_list.h for the motivation behind this. +#if SANITIZER_WORDSIZE == 64 +template <class T> +class CompactRingBuffer { + // Top byte of long_ stores the buffer size in pages. + // Lower bytes store the address of the next buffer element. + static constexpr int kPageSizeBits = 12; + static constexpr int kSizeShift = 56; + static constexpr uptr kNextMask = (1ULL << kSizeShift) - 1; + + uptr GetStorageSize() const { return (long_ >> kSizeShift) << kPageSizeBits; } + + void Init(void *storage, uptr size) { + CHECK_EQ(sizeof(CompactRingBuffer<T>), sizeof(void *)); + CHECK(IsPowerOfTwo(size)); + CHECK_GE(size, 1 << kPageSizeBits); + CHECK_LE(size, 128 << kPageSizeBits); + CHECK_EQ(size % 4096, 0); + CHECK_EQ(size % sizeof(T), 0); + CHECK_EQ((uptr)storage % (size * 2), 0); + long_ = (uptr)storage | ((size >> kPageSizeBits) << kSizeShift); + } + + void SetNext(const T *next) { + long_ = (long_ & ~kNextMask) | (uptr)next; + } + + public: + CompactRingBuffer(void *storage, uptr size) { + Init(storage, size); + } + + // A copy constructor of sorts. + CompactRingBuffer(const CompactRingBuffer &other, void *storage) { + uptr size = other.GetStorageSize(); + internal_memcpy(storage, other.StartOfStorage(), size); + Init(storage, size); + uptr Idx = other.Next() - (const T *)other.StartOfStorage(); + SetNext((const T *)storage + Idx); + } + + T *Next() const { return (T *)(long_ & kNextMask); } + + void *StartOfStorage() const { + return (void *)((uptr)Next() & ~(GetStorageSize() - 1)); + } + + void *EndOfStorage() const { + return (void *)((uptr)StartOfStorage() + GetStorageSize()); + } + + uptr size() const { return GetStorageSize() / sizeof(T); } + + void push(T t) { + T *next = Next(); + *next = t; + next++; + next = (T *)((uptr)next & ~GetStorageSize()); + SetNext(next); + } + + const T &operator[](uptr Idx) const { + CHECK_LT(Idx, size()); + const T *Begin = (const T *)StartOfStorage(); + sptr StorageIdx = Next() - Begin; + StorageIdx -= (sptr)(Idx + 1); + if (StorageIdx < 0) + StorageIdx += size(); + return Begin[StorageIdx]; + } + + public: + ~CompactRingBuffer() {} + CompactRingBuffer(const CompactRingBuffer &) = delete; + + uptr long_; +}; +#endif +} // namespace __sanitizer + +#endif // SANITIZER_RING_BUFFER_H diff --git a/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_signal_interceptors.inc b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_signal_interceptors.inc new file mode 100644 index 0000000000..475e577d99 --- /dev/null +++ b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_signal_interceptors.inc @@ -0,0 +1,97 @@ +//===-- sanitizer_signal_interceptors.inc -----------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// Signal interceptors for sanitizers. +// +//===----------------------------------------------------------------------===// + +#include "interception/interception.h" +#include "sanitizer_common.h" +#include "sanitizer_internal_defs.h" +#include "sanitizer_platform_interceptors.h" + +using namespace __sanitizer; + +#if SANITIZER_NETBSD +#define sigaction_symname __sigaction14 +#else +#define sigaction_symname sigaction +#endif + +#ifndef SIGNAL_INTERCEPTOR_SIGNAL_IMPL +#define SIGNAL_INTERCEPTOR_SIGNAL_IMPL(func, signum, handler) \ + { return REAL(func)(signum, handler); } +#endif + +#ifndef SIGNAL_INTERCEPTOR_SIGACTION_IMPL +# define SIGNAL_INTERCEPTOR_SIGACTION_IMPL(signum, act, oldact) \ + { \ + if (!REAL(sigaction_symname)) { \ + Printf( \ + "Warning: REAL(sigaction_symname) == nullptr. This may happen " \ + "if you link with ubsan statically. Sigaction will not work.\n"); \ + return -1; \ + } \ + return REAL(sigaction_symname)(signum, act, oldact); \ + } +#endif + +#if SANITIZER_INTERCEPT_BSD_SIGNAL +INTERCEPTOR(uptr, bsd_signal, int signum, uptr handler) { + if (GetHandleSignalMode(signum) == kHandleSignalExclusive) return 0; + SIGNAL_INTERCEPTOR_SIGNAL_IMPL(bsd_signal, signum, handler); +} +#define INIT_BSD_SIGNAL COMMON_INTERCEPT_FUNCTION(bsd_signal) +#else // SANITIZER_INTERCEPT_BSD_SIGNAL +#define INIT_BSD_SIGNAL +#endif // SANITIZER_INTERCEPT_BSD_SIGNAL + +#if SANITIZER_INTERCEPT_SIGNAL_AND_SIGACTION +INTERCEPTOR(uptr, signal, int signum, uptr handler) { + if (GetHandleSignalMode(signum) == kHandleSignalExclusive) + return (uptr) nullptr; + SIGNAL_INTERCEPTOR_SIGNAL_IMPL(signal, signum, handler); +} +#define INIT_SIGNAL COMMON_INTERCEPT_FUNCTION(signal) + +INTERCEPTOR(int, sigaction_symname, int signum, + const __sanitizer_sigaction *act, __sanitizer_sigaction *oldact) { + if (GetHandleSignalMode(signum) == kHandleSignalExclusive) { + if (!oldact) return 0; + act = nullptr; + } + SIGNAL_INTERCEPTOR_SIGACTION_IMPL(signum, act, oldact); +} +#define INIT_SIGACTION COMMON_INTERCEPT_FUNCTION(sigaction_symname) + +namespace __sanitizer { +int real_sigaction(int signum, const void *act, void *oldact) { + return REAL(sigaction_symname)(signum, (const __sanitizer_sigaction *)act, + (__sanitizer_sigaction *)oldact); +} +} // namespace __sanitizer +#else // SANITIZER_INTERCEPT_SIGNAL_AND_SIGACTION +#define INIT_SIGNAL +#define INIT_SIGACTION +// We need to have defined REAL(sigaction) on other systems. +namespace __sanitizer { +struct __sanitizer_sigaction; +} +DEFINE_REAL(int, sigaction, int signum, const __sanitizer_sigaction *act, + __sanitizer_sigaction *oldact) +#endif // SANITIZER_INTERCEPT_SIGNAL_AND_SIGACTION + +static void InitializeSignalInterceptors() { + static bool was_called_once; + CHECK(!was_called_once); + was_called_once = true; + + INIT_BSD_SIGNAL; + INIT_SIGNAL; + INIT_SIGACTION; +} diff --git a/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_solaris.cpp b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_solaris.cpp new file mode 100644 index 0000000000..62c40affc9 --- /dev/null +++ b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_solaris.cpp @@ -0,0 +1,230 @@ +//===-- sanitizer_solaris.cpp ---------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file is shared between various sanitizers' runtime libraries and +// implements Solaris-specific functions. +//===----------------------------------------------------------------------===// + +#include "sanitizer_platform.h" +#if SANITIZER_SOLARIS + +#include <stdio.h> + +#include "sanitizer_common.h" +#include "sanitizer_flags.h" +#include "sanitizer_internal_defs.h" +#include "sanitizer_libc.h" +#include "sanitizer_placement_new.h" +#include "sanitizer_platform_limits_posix.h" +#include "sanitizer_procmaps.h" + +#include <fcntl.h> +#include <pthread.h> +#include <sched.h> +#include <thread.h> +#include <synch.h> +#include <signal.h> +#include <sys/mman.h> +#include <sys/resource.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <dirent.h> +#include <unistd.h> +#include <errno.h> +#include <stdlib.h> + +namespace __sanitizer { + +//#include "sanitizer_syscall_generic.inc" + +#define _REAL(func) _ ## func +#define DECLARE__REAL(ret_type, func, ...) \ + extern "C" ret_type _REAL(func)(__VA_ARGS__) +#define DECLARE__REAL_AND_INTERNAL(ret_type, func, ...) \ + DECLARE__REAL(ret_type, func, __VA_ARGS__); \ + ret_type internal_ ## func(__VA_ARGS__) + +#if !defined(_LP64) && _FILE_OFFSET_BITS == 64 +#define _REAL64(func) _ ## func ## 64 +#else +#define _REAL64(func) _REAL(func) +#endif +#define DECLARE__REAL64(ret_type, func, ...) \ + extern "C" ret_type _REAL64(func)(__VA_ARGS__) +#define DECLARE__REAL_AND_INTERNAL64(ret_type, func, ...) \ + DECLARE__REAL64(ret_type, func, __VA_ARGS__); \ + ret_type internal_ ## func(__VA_ARGS__) + +// ---------------------- sanitizer_libc.h +DECLARE__REAL_AND_INTERNAL64(uptr, mmap, void *addr, uptr /*size_t*/ length, + int prot, int flags, int fd, OFF_T offset) { + return (uptr)_REAL64(mmap)(addr, length, prot, flags, fd, offset); +} + +DECLARE__REAL_AND_INTERNAL(uptr, munmap, void *addr, uptr length) { + return _REAL(munmap)(addr, length); +} + +DECLARE__REAL_AND_INTERNAL(int, mprotect, void *addr, uptr length, int prot) { + return _REAL(mprotect)(addr, length, prot); +} + +// Illumos' declaration of madvise cannot be made visible if _XOPEN_SOURCE +// is defined as g++ does on Solaris. +// +// This declaration is consistent with Solaris 11.4. Both Illumos and Solaris +// versions older than 11.4 declared madvise with a caddr_t as the first +// argument, but we don't currently support Solaris versions older than 11.4, +// and as mentioned above the declaration is not visible on Illumos so we can +// use any declaration we like on Illumos. +extern "C" int madvise(void *, size_t, int); + +int internal_madvise(uptr addr, uptr length, int advice) { + return madvise((void *)addr, length, advice); +} + +DECLARE__REAL_AND_INTERNAL(uptr, close, fd_t fd) { + return _REAL(close)(fd); +} + +extern "C" int _REAL64(open)(const char *, int, ...); + +uptr internal_open(const char *filename, int flags) { + return _REAL64(open)(filename, flags); +} + +uptr internal_open(const char *filename, int flags, u32 mode) { + return _REAL64(open)(filename, flags, mode); +} + +DECLARE__REAL_AND_INTERNAL(uptr, read, fd_t fd, void *buf, uptr count) { + return _REAL(read)(fd, buf, count); +} + +DECLARE__REAL_AND_INTERNAL(uptr, write, fd_t fd, const void *buf, uptr count) { + return _REAL(write)(fd, buf, count); +} + +// FIXME: There's only _ftruncate64 beginning with Solaris 11. +DECLARE__REAL_AND_INTERNAL(uptr, ftruncate, fd_t fd, uptr size) { + return ftruncate(fd, size); +} + +DECLARE__REAL_AND_INTERNAL64(uptr, stat, const char *path, void *buf) { + return _REAL64(stat)(path, (struct stat *)buf); +} + +DECLARE__REAL_AND_INTERNAL64(uptr, lstat, const char *path, void *buf) { + return _REAL64(lstat)(path, (struct stat *)buf); +} + +DECLARE__REAL_AND_INTERNAL64(uptr, fstat, fd_t fd, void *buf) { + return _REAL64(fstat)(fd, (struct stat *)buf); +} + +uptr internal_filesize(fd_t fd) { + struct stat st; + if (internal_fstat(fd, &st)) + return -1; + return (uptr)st.st_size; +} + +DECLARE__REAL_AND_INTERNAL(uptr, dup, int oldfd) { + return _REAL(dup)(oldfd); +} + +DECLARE__REAL_AND_INTERNAL(uptr, dup2, int oldfd, int newfd) { + return _REAL(dup2)(oldfd, newfd); +} + +DECLARE__REAL_AND_INTERNAL(uptr, readlink, const char *path, char *buf, + uptr bufsize) { + return _REAL(readlink)(path, buf, bufsize); +} + +DECLARE__REAL_AND_INTERNAL(uptr, unlink, const char *path) { + return _REAL(unlink)(path); +} + +DECLARE__REAL_AND_INTERNAL(uptr, rename, const char *oldpath, + const char *newpath) { + return _REAL(rename)(oldpath, newpath); +} + +DECLARE__REAL_AND_INTERNAL(uptr, sched_yield, void) { + return sched_yield(); +} + +DECLARE__REAL_AND_INTERNAL(void, usleep, u64 useconds) { + struct timespec ts; + ts.tv_sec = useconds / 1000000; + ts.tv_nsec = (useconds % 1000000) * 1000; + nanosleep(&ts, nullptr); +} + +DECLARE__REAL_AND_INTERNAL(uptr, execve, const char *filename, + char *const argv[], char *const envp[]) { + return _REAL(execve)(filename, argv, envp); +} + +DECLARE__REAL_AND_INTERNAL(uptr, waitpid, int pid, int *status, int options) { + return _REAL(waitpid)(pid, status, options); +} + +DECLARE__REAL_AND_INTERNAL(uptr, getpid, void) { + return _REAL(getpid)(); +} + +// FIXME: This might be wrong: _getdents doesn't take a struct linux_dirent *. +DECLARE__REAL_AND_INTERNAL64(uptr, getdents, fd_t fd, struct linux_dirent *dirp, + unsigned int count) { + return _REAL64(getdents)(fd, dirp, count); +} + +DECLARE__REAL_AND_INTERNAL64(uptr, lseek, fd_t fd, OFF_T offset, int whence) { + return _REAL64(lseek)(fd, offset, whence); +} + +// FIXME: This might be wrong: _sigfillset doesn't take a +// __sanitizer_sigset_t *. +DECLARE__REAL_AND_INTERNAL(void, sigfillset, __sanitizer_sigset_t *set) { + _REAL(sigfillset)(set); +} + +// FIXME: This might be wrong: _sigprocmask doesn't take __sanitizer_sigset_t *. +DECLARE__REAL_AND_INTERNAL(uptr, sigprocmask, int how, + __sanitizer_sigset_t *set, + __sanitizer_sigset_t *oldset) { + return _REAL(sigprocmask)(how, set, oldset); +} + +DECLARE__REAL_AND_INTERNAL(int, fork, void) { + // TODO(glider): this may call user's pthread_atfork() handlers which is bad. + return _REAL(fork)(); +} + +u64 NanoTime() { + return gethrtime(); +} + +uptr internal_clock_gettime(__sanitizer_clockid_t clk_id, void *tp) { + // FIXME: No internal variant. + return clock_gettime(clk_id, (timespec *)tp); +} + +// ----------------- sanitizer_common.h +void FutexWait(atomic_uint32_t *p, u32 cmp) { + // FIXME: implement actual blocking. + sched_yield(); +} + +void FutexWake(atomic_uint32_t *p, u32 count) {} + +} // namespace __sanitizer + +#endif // SANITIZER_SOLARIS diff --git a/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_stack_store.cpp b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_stack_store.cpp new file mode 100644 index 0000000000..148470943b --- /dev/null +++ b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_stack_store.cpp @@ -0,0 +1,379 @@ +//===-- sanitizer_stack_store.cpp -------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "sanitizer_stack_store.h" + +#include "sanitizer_atomic.h" +#include "sanitizer_common.h" +#include "sanitizer_internal_defs.h" +#include "sanitizer_leb128.h" +#include "sanitizer_lzw.h" +#include "sanitizer_placement_new.h" +#include "sanitizer_stacktrace.h" + +namespace __sanitizer { + +namespace { +struct StackTraceHeader { + static constexpr u32 kStackSizeBits = 8; + + u8 size; + u8 tag; + explicit StackTraceHeader(const StackTrace &trace) + : size(Min<uptr>(trace.size, (1u << 8) - 1)), tag(trace.tag) { + CHECK_EQ(trace.tag, static_cast<uptr>(tag)); + } + explicit StackTraceHeader(uptr h) + : size(h & ((1 << kStackSizeBits) - 1)), tag(h >> kStackSizeBits) {} + + uptr ToUptr() const { + return static_cast<uptr>(size) | (static_cast<uptr>(tag) << kStackSizeBits); + } +}; +} // namespace + +StackStore::Id StackStore::Store(const StackTrace &trace, uptr *pack) { + if (!trace.size && !trace.tag) + return 0; + StackTraceHeader h(trace); + uptr idx = 0; + *pack = 0; + uptr *stack_trace = Alloc(h.size + 1, &idx, pack); + *stack_trace = h.ToUptr(); + internal_memcpy(stack_trace + 1, trace.trace, h.size * sizeof(uptr)); + *pack += blocks_[GetBlockIdx(idx)].Stored(h.size + 1); + return OffsetToId(idx); +} + +StackTrace StackStore::Load(Id id) { + if (!id) + return {}; + uptr idx = IdToOffset(id); + uptr block_idx = GetBlockIdx(idx); + CHECK_LT(block_idx, ARRAY_SIZE(blocks_)); + const uptr *stack_trace = blocks_[block_idx].GetOrUnpack(this); + if (!stack_trace) + return {}; + stack_trace += GetInBlockIdx(idx); + StackTraceHeader h(*stack_trace); + return StackTrace(stack_trace + 1, h.size, h.tag); +} + +uptr StackStore::Allocated() const { + return atomic_load_relaxed(&allocated_) + sizeof(*this); +} + +uptr *StackStore::Alloc(uptr count, uptr *idx, uptr *pack) { + for (;;) { + // Optimisic lock-free allocation, essentially try to bump the + // total_frames_. + uptr start = atomic_fetch_add(&total_frames_, count, memory_order_relaxed); + uptr block_idx = GetBlockIdx(start); + uptr last_idx = GetBlockIdx(start + count - 1); + if (LIKELY(block_idx == last_idx)) { + // Fits into the a single block. + CHECK_LT(block_idx, ARRAY_SIZE(blocks_)); + *idx = start; + return blocks_[block_idx].GetOrCreate(this) + GetInBlockIdx(start); + } + + // Retry. We can't use range allocated in two different blocks. + CHECK_LE(count, kBlockSizeFrames); + uptr in_first = kBlockSizeFrames - GetInBlockIdx(start); + // Mark tail/head of these blocks as "stored".to avoid waiting before we can + // Pack(). + *pack += blocks_[block_idx].Stored(in_first); + *pack += blocks_[last_idx].Stored(count - in_first); + } +} + +void *StackStore::Map(uptr size, const char *mem_type) { + atomic_fetch_add(&allocated_, size, memory_order_relaxed); + return MmapNoReserveOrDie(size, mem_type); +} + +void StackStore::Unmap(void *addr, uptr size) { + atomic_fetch_sub(&allocated_, size, memory_order_relaxed); + UnmapOrDie(addr, size); +} + +uptr StackStore::Pack(Compression type) { + uptr res = 0; + for (BlockInfo &b : blocks_) res += b.Pack(type, this); + return res; +} + +void StackStore::LockAll() { + for (BlockInfo &b : blocks_) b.Lock(); +} + +void StackStore::UnlockAll() { + for (BlockInfo &b : blocks_) b.Unlock(); +} + +void StackStore::TestOnlyUnmap() { + for (BlockInfo &b : blocks_) b.TestOnlyUnmap(this); + internal_memset(this, 0, sizeof(*this)); +} + +uptr *StackStore::BlockInfo::Get() const { + // Idiomatic double-checked locking uses memory_order_acquire here. But + // relaxed is fine for us, justification is similar to + // TwoLevelMap::GetOrCreate. + return reinterpret_cast<uptr *>(atomic_load_relaxed(&data_)); +} + +uptr *StackStore::BlockInfo::Create(StackStore *store) { + SpinMutexLock l(&mtx_); + uptr *ptr = Get(); + if (!ptr) { + ptr = reinterpret_cast<uptr *>(store->Map(kBlockSizeBytes, "StackStore")); + atomic_store(&data_, reinterpret_cast<uptr>(ptr), memory_order_release); + } + return ptr; +} + +uptr *StackStore::BlockInfo::GetOrCreate(StackStore *store) { + uptr *ptr = Get(); + if (LIKELY(ptr)) + return ptr; + return Create(store); +} + +class SLeb128Encoder { + public: + SLeb128Encoder(u8 *begin, u8 *end) : begin(begin), end(end) {} + + bool operator==(const SLeb128Encoder &other) const { + return begin == other.begin; + } + + bool operator!=(const SLeb128Encoder &other) const { + return begin != other.begin; + } + + SLeb128Encoder &operator=(uptr v) { + sptr diff = v - previous; + begin = EncodeSLEB128(diff, begin, end); + previous = v; + return *this; + } + SLeb128Encoder &operator*() { return *this; } + SLeb128Encoder &operator++() { return *this; } + + u8 *base() const { return begin; } + + private: + u8 *begin; + u8 *end; + uptr previous = 0; +}; + +class SLeb128Decoder { + public: + SLeb128Decoder(const u8 *begin, const u8 *end) : begin(begin), end(end) {} + + bool operator==(const SLeb128Decoder &other) const { + return begin == other.begin; + } + + bool operator!=(const SLeb128Decoder &other) const { + return begin != other.begin; + } + + uptr operator*() { + sptr diff; + begin = DecodeSLEB128(begin, end, &diff); + previous += diff; + return previous; + } + SLeb128Decoder &operator++() { return *this; } + + SLeb128Decoder operator++(int) { return *this; } + + private: + const u8 *begin; + const u8 *end; + uptr previous = 0; +}; + +static u8 *CompressDelta(const uptr *from, const uptr *from_end, u8 *to, + u8 *to_end) { + SLeb128Encoder encoder(to, to_end); + for (; from != from_end; ++from, ++encoder) *encoder = *from; + return encoder.base(); +} + +static uptr *UncompressDelta(const u8 *from, const u8 *from_end, uptr *to, + uptr *to_end) { + SLeb128Decoder decoder(from, from_end); + SLeb128Decoder end(from_end, from_end); + for (; decoder != end; ++to, ++decoder) *to = *decoder; + CHECK_EQ(to, to_end); + return to; +} + +static u8 *CompressLzw(const uptr *from, const uptr *from_end, u8 *to, + u8 *to_end) { + SLeb128Encoder encoder(to, to_end); + encoder = LzwEncode<uptr>(from, from_end, encoder); + return encoder.base(); +} + +static uptr *UncompressLzw(const u8 *from, const u8 *from_end, uptr *to, + uptr *to_end) { + SLeb128Decoder decoder(from, from_end); + SLeb128Decoder end(from_end, from_end); + to = LzwDecode<uptr>(decoder, end, to); + CHECK_EQ(to, to_end); + return to; +} + +#if defined(_MSC_VER) && !defined(__clang__) +# pragma warning(push) +// Disable 'nonstandard extension used: zero-sized array in struct/union'. +# pragma warning(disable : 4200) +#endif +namespace { +struct PackedHeader { + uptr size; + StackStore::Compression type; + u8 data[]; +}; +} // namespace +#if defined(_MSC_VER) && !defined(__clang__) +# pragma warning(pop) +#endif + +uptr *StackStore::BlockInfo::GetOrUnpack(StackStore *store) { + SpinMutexLock l(&mtx_); + switch (state) { + case State::Storing: + state = State::Unpacked; + FALLTHROUGH; + case State::Unpacked: + return Get(); + case State::Packed: + break; + } + + u8 *ptr = reinterpret_cast<u8 *>(Get()); + CHECK_NE(nullptr, ptr); + const PackedHeader *header = reinterpret_cast<const PackedHeader *>(ptr); + CHECK_LE(header->size, kBlockSizeBytes); + CHECK_GE(header->size, sizeof(PackedHeader)); + + uptr packed_size_aligned = RoundUpTo(header->size, GetPageSizeCached()); + + uptr *unpacked = + reinterpret_cast<uptr *>(store->Map(kBlockSizeBytes, "StackStoreUnpack")); + + uptr *unpacked_end; + switch (header->type) { + case Compression::Delta: + unpacked_end = UncompressDelta(header->data, ptr + header->size, unpacked, + unpacked + kBlockSizeFrames); + break; + case Compression::LZW: + unpacked_end = UncompressLzw(header->data, ptr + header->size, unpacked, + unpacked + kBlockSizeFrames); + break; + default: + UNREACHABLE("Unexpected type"); + break; + } + + CHECK_EQ(kBlockSizeFrames, unpacked_end - unpacked); + + MprotectReadOnly(reinterpret_cast<uptr>(unpacked), kBlockSizeBytes); + atomic_store(&data_, reinterpret_cast<uptr>(unpacked), memory_order_release); + store->Unmap(ptr, packed_size_aligned); + + state = State::Unpacked; + return Get(); +} + +uptr StackStore::BlockInfo::Pack(Compression type, StackStore *store) { + if (type == Compression::None) + return 0; + + SpinMutexLock l(&mtx_); + switch (state) { + case State::Unpacked: + case State::Packed: + return 0; + case State::Storing: + break; + } + + uptr *ptr = Get(); + if (!ptr || !Stored(0)) + return 0; + + u8 *packed = + reinterpret_cast<u8 *>(store->Map(kBlockSizeBytes, "StackStorePack")); + PackedHeader *header = reinterpret_cast<PackedHeader *>(packed); + u8 *alloc_end = packed + kBlockSizeBytes; + + u8 *packed_end = nullptr; + switch (type) { + case Compression::Delta: + packed_end = + CompressDelta(ptr, ptr + kBlockSizeFrames, header->data, alloc_end); + break; + case Compression::LZW: + packed_end = + CompressLzw(ptr, ptr + kBlockSizeFrames, header->data, alloc_end); + break; + default: + UNREACHABLE("Unexpected type"); + break; + } + + header->type = type; + header->size = packed_end - packed; + + VPrintf(1, "Packed block of %zu KiB to %zu KiB\n", kBlockSizeBytes >> 10, + header->size >> 10); + + if (kBlockSizeBytes - header->size < kBlockSizeBytes / 8) { + VPrintf(1, "Undo and keep block unpacked\n"); + MprotectReadOnly(reinterpret_cast<uptr>(ptr), kBlockSizeBytes); + store->Unmap(packed, kBlockSizeBytes); + state = State::Unpacked; + return 0; + } + + uptr packed_size_aligned = RoundUpTo(header->size, GetPageSizeCached()); + store->Unmap(packed + packed_size_aligned, + kBlockSizeBytes - packed_size_aligned); + MprotectReadOnly(reinterpret_cast<uptr>(packed), packed_size_aligned); + + atomic_store(&data_, reinterpret_cast<uptr>(packed), memory_order_release); + store->Unmap(ptr, kBlockSizeBytes); + + state = State::Packed; + return kBlockSizeBytes - packed_size_aligned; +} + +void StackStore::BlockInfo::TestOnlyUnmap(StackStore *store) { + if (uptr *ptr = Get()) + store->Unmap(ptr, kBlockSizeBytes); +} + +bool StackStore::BlockInfo::Stored(uptr n) { + return n + atomic_fetch_add(&stored_, n, memory_order_release) == + kBlockSizeFrames; +} + +bool StackStore::BlockInfo::IsPacked() const { + SpinMutexLock l(&mtx_); + return state == State::Packed; +} + +} // namespace __sanitizer diff --git a/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_stack_store.h b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_stack_store.h new file mode 100644 index 0000000000..4f1a8caac6 --- /dev/null +++ b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_stack_store.h @@ -0,0 +1,121 @@ +//===-- sanitizer_stack_store.h ---------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef SANITIZER_STACK_STORE_H +#define SANITIZER_STACK_STORE_H + +#include "sanitizer_atomic.h" +#include "sanitizer_common.h" +#include "sanitizer_internal_defs.h" +#include "sanitizer_mutex.h" +#include "sanitizer_stacktrace.h" + +namespace __sanitizer { + +class StackStore { + static constexpr uptr kBlockSizeFrames = 0x100000; + static constexpr uptr kBlockCount = 0x1000; + static constexpr uptr kBlockSizeBytes = kBlockSizeFrames * sizeof(uptr); + + public: + enum class Compression : u8 { + None = 0, + Delta, + LZW, + }; + + constexpr StackStore() = default; + + using Id = u32; // Enough for 2^32 * sizeof(uptr) bytes of traces. + static_assert(u64(kBlockCount) * kBlockSizeFrames == 1ull << (sizeof(Id) * 8), + ""); + + Id Store(const StackTrace &trace, + uptr *pack /* number of blocks completed by this call */); + StackTrace Load(Id id); + uptr Allocated() const; + + // Packs all blocks which don't expect any more writes. A block is going to be + // packed once. As soon trace from that block was requested, it will unpack + // and stay unpacked after that. + // Returns the number of released bytes. + uptr Pack(Compression type); + + void LockAll(); + void UnlockAll(); + + void TestOnlyUnmap(); + + private: + friend class StackStoreTest; + static constexpr uptr GetBlockIdx(uptr frame_idx) { + return frame_idx / kBlockSizeFrames; + } + + static constexpr uptr GetInBlockIdx(uptr frame_idx) { + return frame_idx % kBlockSizeFrames; + } + + static constexpr uptr IdToOffset(Id id) { + CHECK_NE(id, 0); + return id - 1; // Avoid zero as id. + } + + static constexpr uptr OffsetToId(Id id) { + // This makes UINT32_MAX to 0 and it will be retrived as and empty stack. + // But this is not a problem as we will not be able to store anything after + // that anyway. + return id + 1; // Avoid zero as id. + } + + uptr *Alloc(uptr count, uptr *idx, uptr *pack); + + void *Map(uptr size, const char *mem_type); + void Unmap(void *addr, uptr size); + + // Total number of allocated frames. + atomic_uintptr_t total_frames_ = {}; + + // Tracks total allocated memory in bytes. + atomic_uintptr_t allocated_ = {}; + + // Each block will hold pointer to exactly kBlockSizeFrames. + class BlockInfo { + atomic_uintptr_t data_; + // Counter to track store progress to know when we can Pack() the block. + atomic_uint32_t stored_; + // Protects alloc of new blocks. + mutable StaticSpinMutex mtx_; + + enum class State : u8 { + Storing = 0, + Packed, + Unpacked, + }; + State state SANITIZER_GUARDED_BY(mtx_); + + uptr *Create(StackStore *store); + + public: + uptr *Get() const; + uptr *GetOrCreate(StackStore *store); + uptr *GetOrUnpack(StackStore *store); + uptr Pack(Compression type, StackStore *store); + void TestOnlyUnmap(StackStore *store); + bool Stored(uptr n); + bool IsPacked() const; + void Lock() SANITIZER_NO_THREAD_SAFETY_ANALYSIS { mtx_.Lock(); } + void Unlock() SANITIZER_NO_THREAD_SAFETY_ANALYSIS { mtx_.Unlock(); } + }; + + BlockInfo blocks_[kBlockCount] = {}; +}; + +} // namespace __sanitizer + +#endif // SANITIZER_STACK_STORE_H diff --git a/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_stackdepot.cpp b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_stackdepot.cpp new file mode 100644 index 0000000000..ac87fab3ea --- /dev/null +++ b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_stackdepot.cpp @@ -0,0 +1,245 @@ +//===-- sanitizer_stackdepot.cpp ------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file is shared between AddressSanitizer and ThreadSanitizer +// run-time libraries. +//===----------------------------------------------------------------------===// + +#include "sanitizer_stackdepot.h" + +#include "sanitizer_atomic.h" +#include "sanitizer_common.h" +#include "sanitizer_hash.h" +#include "sanitizer_mutex.h" +#include "sanitizer_stack_store.h" +#include "sanitizer_stackdepotbase.h" + +namespace __sanitizer { + +struct StackDepotNode { + using hash_type = u64; + hash_type stack_hash; + u32 link; + StackStore::Id store_id; + + static const u32 kTabSizeLog = SANITIZER_ANDROID ? 16 : 20; + + typedef StackTrace args_type; + bool eq(hash_type hash, const args_type &args) const { + return hash == stack_hash; + } + static uptr allocated(); + static hash_type hash(const args_type &args) { + MurMur2Hash64Builder H(args.size * sizeof(uptr)); + for (uptr i = 0; i < args.size; i++) H.add(args.trace[i]); + H.add(args.tag); + return H.get(); + } + static bool is_valid(const args_type &args) { + return args.size > 0 && args.trace; + } + void store(u32 id, const args_type &args, hash_type hash); + args_type load(u32 id) const; + static StackDepotHandle get_handle(u32 id); + + typedef StackDepotHandle handle_type; +}; + +static StackStore stackStore; + +// FIXME(dvyukov): this single reserved bit is used in TSan. +typedef StackDepotBase<StackDepotNode, 1, StackDepotNode::kTabSizeLog> + StackDepot; +static StackDepot theDepot; +// Keep mutable data out of frequently access nodes to improve caching +// efficiency. +static TwoLevelMap<atomic_uint32_t, StackDepot::kNodesSize1, + StackDepot::kNodesSize2> + useCounts; + +int StackDepotHandle::use_count() const { + return atomic_load_relaxed(&useCounts[id_]); +} + +void StackDepotHandle::inc_use_count_unsafe() { + atomic_fetch_add(&useCounts[id_], 1, memory_order_relaxed); +} + +uptr StackDepotNode::allocated() { + return stackStore.Allocated() + useCounts.MemoryUsage(); +} + +static void CompressStackStore() { + u64 start = MonotonicNanoTime(); + uptr diff = stackStore.Pack(static_cast<StackStore::Compression>( + Abs(common_flags()->compress_stack_depot))); + if (!diff) + return; + u64 finish = MonotonicNanoTime(); + uptr total_before = theDepot.GetStats().allocated + diff; + VPrintf(1, "%s: StackDepot released %zu KiB out of %zu KiB in %llu ms\n", + SanitizerToolName, diff >> 10, total_before >> 10, + (finish - start) / 1000000); +} + +namespace { + +class CompressThread { + public: + constexpr CompressThread() = default; + void NewWorkNotify(); + void Stop(); + void LockAndStop() SANITIZER_NO_THREAD_SAFETY_ANALYSIS; + void Unlock() SANITIZER_NO_THREAD_SAFETY_ANALYSIS; + + private: + enum class State { + NotStarted = 0, + Started, + Failed, + Stopped, + }; + + void Run(); + + bool WaitForWork() { + semaphore_.Wait(); + return atomic_load(&run_, memory_order_acquire); + } + + Semaphore semaphore_ = {}; + StaticSpinMutex mutex_ = {}; + State state_ SANITIZER_GUARDED_BY(mutex_) = State::NotStarted; + void *thread_ SANITIZER_GUARDED_BY(mutex_) = nullptr; + atomic_uint8_t run_ = {}; +}; + +static CompressThread compress_thread; + +void CompressThread::NewWorkNotify() { + int compress = common_flags()->compress_stack_depot; + if (!compress) + return; + if (compress > 0 /* for testing or debugging */) { + SpinMutexLock l(&mutex_); + if (state_ == State::NotStarted) { + atomic_store(&run_, 1, memory_order_release); + CHECK_EQ(nullptr, thread_); + thread_ = internal_start_thread( + [](void *arg) -> void * { + reinterpret_cast<CompressThread *>(arg)->Run(); + return nullptr; + }, + this); + state_ = thread_ ? State::Started : State::Failed; + } + if (state_ == State::Started) { + semaphore_.Post(); + return; + } + } + CompressStackStore(); +} + +void CompressThread::Run() { + VPrintf(1, "%s: StackDepot compression thread started\n", SanitizerToolName); + while (WaitForWork()) CompressStackStore(); + VPrintf(1, "%s: StackDepot compression thread stopped\n", SanitizerToolName); +} + +void CompressThread::Stop() { + void *t = nullptr; + { + SpinMutexLock l(&mutex_); + if (state_ != State::Started) + return; + state_ = State::Stopped; + CHECK_NE(nullptr, thread_); + t = thread_; + thread_ = nullptr; + } + atomic_store(&run_, 0, memory_order_release); + semaphore_.Post(); + internal_join_thread(t); +} + +void CompressThread::LockAndStop() { + mutex_.Lock(); + if (state_ != State::Started) + return; + CHECK_NE(nullptr, thread_); + + atomic_store(&run_, 0, memory_order_release); + semaphore_.Post(); + internal_join_thread(thread_); + // Allow to restart after Unlock() if needed. + state_ = State::NotStarted; + thread_ = nullptr; +} + +void CompressThread::Unlock() { mutex_.Unlock(); } + +} // namespace + +void StackDepotNode::store(u32 id, const args_type &args, hash_type hash) { + stack_hash = hash; + uptr pack = 0; + store_id = stackStore.Store(args, &pack); + if (LIKELY(!pack)) + return; + compress_thread.NewWorkNotify(); +} + +StackDepotNode::args_type StackDepotNode::load(u32 id) const { + if (!store_id) + return {}; + return stackStore.Load(store_id); +} + +StackDepotStats StackDepotGetStats() { return theDepot.GetStats(); } + +u32 StackDepotPut(StackTrace stack) { return theDepot.Put(stack); } + +StackDepotHandle StackDepotPut_WithHandle(StackTrace stack) { + return StackDepotNode::get_handle(theDepot.Put(stack)); +} + +StackTrace StackDepotGet(u32 id) { + return theDepot.Get(id); +} + +void StackDepotLockAll() { + theDepot.LockAll(); + compress_thread.LockAndStop(); + stackStore.LockAll(); +} + +void StackDepotUnlockAll() { + stackStore.UnlockAll(); + compress_thread.Unlock(); + theDepot.UnlockAll(); +} + +void StackDepotPrintAll() { +#if !SANITIZER_GO + theDepot.PrintAll(); +#endif +} + +void StackDepotStopBackgroundThread() { compress_thread.Stop(); } + +StackDepotHandle StackDepotNode::get_handle(u32 id) { + return StackDepotHandle(&theDepot.nodes[id], id); +} + +void StackDepotTestOnlyUnmap() { + theDepot.TestOnlyUnmap(); + stackStore.TestOnlyUnmap(); +} + +} // namespace __sanitizer diff --git a/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_stackdepot.h b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_stackdepot.h new file mode 100644 index 0000000000..cca6fd5346 --- /dev/null +++ b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_stackdepot.h @@ -0,0 +1,51 @@ +//===-- sanitizer_stackdepot.h ----------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file is shared between AddressSanitizer and ThreadSanitizer +// run-time libraries. +//===----------------------------------------------------------------------===// + +#ifndef SANITIZER_STACKDEPOT_H +#define SANITIZER_STACKDEPOT_H + +#include "sanitizer_common.h" +#include "sanitizer_internal_defs.h" +#include "sanitizer_stacktrace.h" + +namespace __sanitizer { + +// StackDepot efficiently stores huge amounts of stack traces. +struct StackDepotNode; +struct StackDepotHandle { + StackDepotNode *node_ = nullptr; + u32 id_ = 0; + StackDepotHandle(StackDepotNode *node, u32 id) : node_(node), id_(id) {} + bool valid() const { return node_; } + u32 id() const { return id_; } + int use_count() const; + void inc_use_count_unsafe(); +}; + +const int kStackDepotMaxUseCount = 1U << (SANITIZER_ANDROID ? 16 : 20); + +StackDepotStats StackDepotGetStats(); +u32 StackDepotPut(StackTrace stack); +StackDepotHandle StackDepotPut_WithHandle(StackTrace stack); +// Retrieves a stored stack trace by the id. +StackTrace StackDepotGet(u32 id); + +void StackDepotLockAll(); +void StackDepotUnlockAll(); +void StackDepotPrintAll(); +void StackDepotStopBackgroundThread(); + +void StackDepotTestOnlyUnmap(); + +} // namespace __sanitizer + +#endif // SANITIZER_STACKDEPOT_H diff --git a/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_stackdepotbase.h b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_stackdepotbase.h new file mode 100644 index 0000000000..96d1ddc87f --- /dev/null +++ b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_stackdepotbase.h @@ -0,0 +1,194 @@ +//===-- sanitizer_stackdepotbase.h ------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// Implementation of a mapping from arbitrary values to unique 32-bit +// identifiers. +//===----------------------------------------------------------------------===// + +#ifndef SANITIZER_STACKDEPOTBASE_H +#define SANITIZER_STACKDEPOTBASE_H + +#include <stdio.h> + +#include "sanitizer_atomic.h" +#include "sanitizer_flat_map.h" +#include "sanitizer_internal_defs.h" +#include "sanitizer_mutex.h" + +namespace __sanitizer { + +template <class Node, int kReservedBits, int kTabSizeLog> +class StackDepotBase { + static constexpr u32 kIdSizeLog = + sizeof(u32) * 8 - Max(kReservedBits, 1 /* At least 1 bit for locking. */); + static constexpr u32 kNodesSize1Log = kIdSizeLog / 2; + static constexpr u32 kNodesSize2Log = kIdSizeLog - kNodesSize1Log; + static constexpr int kTabSize = 1 << kTabSizeLog; // Hash table size. + static constexpr u32 kUnlockMask = (1ull << kIdSizeLog) - 1; + static constexpr u32 kLockMask = ~kUnlockMask; + + public: + typedef typename Node::args_type args_type; + typedef typename Node::handle_type handle_type; + typedef typename Node::hash_type hash_type; + + static constexpr u64 kNodesSize1 = 1ull << kNodesSize1Log; + static constexpr u64 kNodesSize2 = 1ull << kNodesSize2Log; + + // Maps stack trace to an unique id. + u32 Put(args_type args, bool *inserted = nullptr); + // Retrieves a stored stack trace by the id. + args_type Get(u32 id); + + StackDepotStats GetStats() const { + return { + atomic_load_relaxed(&n_uniq_ids), + nodes.MemoryUsage() + Node::allocated(), + }; + } + + void LockAll(); + void UnlockAll(); + void PrintAll(); + + void TestOnlyUnmap() { + nodes.TestOnlyUnmap(); + internal_memset(this, 0, sizeof(*this)); + } + + private: + friend Node; + u32 find(u32 s, args_type args, hash_type hash) const; + static u32 lock(atomic_uint32_t *p); + static void unlock(atomic_uint32_t *p, u32 s); + atomic_uint32_t tab[kTabSize]; // Hash table of Node's. + + atomic_uint32_t n_uniq_ids; + + TwoLevelMap<Node, kNodesSize1, kNodesSize2> nodes; + + friend class StackDepotReverseMap; +}; + +template <class Node, int kReservedBits, int kTabSizeLog> +u32 StackDepotBase<Node, kReservedBits, kTabSizeLog>::find( + u32 s, args_type args, hash_type hash) const { + // Searches linked list s for the stack, returns its id. + for (; s;) { + const Node &node = nodes[s]; + if (node.eq(hash, args)) + return s; + s = node.link; + } + return 0; +} + +template <class Node, int kReservedBits, int kTabSizeLog> +u32 StackDepotBase<Node, kReservedBits, kTabSizeLog>::lock(atomic_uint32_t *p) { + // Uses the pointer lsb as mutex. + for (int i = 0;; i++) { + u32 cmp = atomic_load(p, memory_order_relaxed); + if ((cmp & kLockMask) == 0 && + atomic_compare_exchange_weak(p, &cmp, cmp | kLockMask, + memory_order_acquire)) + return cmp; + if (i < 10) + proc_yield(10); + else + internal_sched_yield(); + } +} + +template <class Node, int kReservedBits, int kTabSizeLog> +void StackDepotBase<Node, kReservedBits, kTabSizeLog>::unlock( + atomic_uint32_t *p, u32 s) { + DCHECK_EQ(s & kLockMask, 0); + atomic_store(p, s, memory_order_release); +} + +template <class Node, int kReservedBits, int kTabSizeLog> +u32 StackDepotBase<Node, kReservedBits, kTabSizeLog>::Put(args_type args, + bool *inserted) { + if (inserted) + *inserted = false; + if (!LIKELY(Node::is_valid(args))) + return 0; + hash_type h = Node::hash(args); + atomic_uint32_t *p = &tab[h % kTabSize]; + u32 v = atomic_load(p, memory_order_consume); + u32 s = v & kUnlockMask; + // First, try to find the existing stack. + u32 node = find(s, args, h); + if (LIKELY(node)) + return node; + + // If failed, lock, retry and insert new. + u32 s2 = lock(p); + if (s2 != s) { + node = find(s2, args, h); + if (node) { + unlock(p, s2); + return node; + } + } + s = atomic_fetch_add(&n_uniq_ids, 1, memory_order_relaxed) + 1; + CHECK_EQ(s & kUnlockMask, s); + CHECK_EQ(s & (((u32)-1) >> kReservedBits), s); + Node &new_node = nodes[s]; + new_node.store(s, args, h); + new_node.link = s2; + unlock(p, s); + if (inserted) *inserted = true; + return s; +} + +template <class Node, int kReservedBits, int kTabSizeLog> +typename StackDepotBase<Node, kReservedBits, kTabSizeLog>::args_type +StackDepotBase<Node, kReservedBits, kTabSizeLog>::Get(u32 id) { + if (id == 0) + return args_type(); + CHECK_EQ(id & (((u32)-1) >> kReservedBits), id); + if (!nodes.contains(id)) + return args_type(); + const Node &node = nodes[id]; + return node.load(id); +} + +template <class Node, int kReservedBits, int kTabSizeLog> +void StackDepotBase<Node, kReservedBits, kTabSizeLog>::LockAll() { + for (int i = 0; i < kTabSize; ++i) { + lock(&tab[i]); + } +} + +template <class Node, int kReservedBits, int kTabSizeLog> +void StackDepotBase<Node, kReservedBits, kTabSizeLog>::UnlockAll() { + for (int i = 0; i < kTabSize; ++i) { + atomic_uint32_t *p = &tab[i]; + uptr s = atomic_load(p, memory_order_relaxed); + unlock(p, s & kUnlockMask); + } +} + +template <class Node, int kReservedBits, int kTabSizeLog> +void StackDepotBase<Node, kReservedBits, kTabSizeLog>::PrintAll() { + for (int i = 0; i < kTabSize; ++i) { + atomic_uint32_t *p = &tab[i]; + u32 s = atomic_load(p, memory_order_consume) & kUnlockMask; + for (; s;) { + const Node &node = nodes[s]; + Printf("Stack for id %u:\n", s); + node.load(s).Print(); + s = node.link; + } + } +} + +} // namespace __sanitizer + +#endif // SANITIZER_STACKDEPOTBASE_H diff --git a/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_stacktrace.cpp b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_stacktrace.cpp new file mode 100644 index 0000000000..37e9e6dd08 --- /dev/null +++ b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_stacktrace.cpp @@ -0,0 +1,168 @@ +//===-- sanitizer_stacktrace.cpp ------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file is shared between AddressSanitizer and ThreadSanitizer +// run-time libraries. +//===----------------------------------------------------------------------===// + +#include "sanitizer_stacktrace.h" + +#include "sanitizer_common.h" +#include "sanitizer_flags.h" +#include "sanitizer_platform.h" +#include "sanitizer_ptrauth.h" + +namespace __sanitizer { + +uptr StackTrace::GetNextInstructionPc(uptr pc) { +#if defined(__sparc__) || defined(__mips__) + return pc + 8; +#elif defined(__powerpc__) || defined(__arm__) || defined(__aarch64__) || \ + defined(__hexagon__) + return STRIP_PAC_PC((void *)pc) + 4; +#elif SANITIZER_RISCV64 + // Current check order is 4 -> 2 -> 6 -> 8 + u8 InsnByte = *(u8 *)(pc); + if (((InsnByte & 0x3) == 0x3) && ((InsnByte & 0x1c) != 0x1c)) { + // xxxxxxxxxxxbbb11 | 32 bit | bbb != 111 + return pc + 4; + } + if ((InsnByte & 0x3) != 0x3) { + // xxxxxxxxxxxxxxaa | 16 bit | aa != 11 + return pc + 2; + } + // RISC-V encoding allows instructions to be up to 8 bytes long + if ((InsnByte & 0x3f) == 0x1f) { + // xxxxxxxxxx011111 | 48 bit | + return pc + 6; + } + if ((InsnByte & 0x7f) == 0x3f) { + // xxxxxxxxx0111111 | 64 bit | + return pc + 8; + } + // bail-out if could not figure out the instruction size + return 0; +#else + return pc + 1; +#endif +} + +uptr StackTrace::GetCurrentPc() { + return GET_CALLER_PC(); +} + +void BufferedStackTrace::Init(const uptr *pcs, uptr cnt, uptr extra_top_pc) { + size = cnt + !!extra_top_pc; + CHECK_LE(size, kStackTraceMax); + internal_memcpy(trace_buffer, pcs, cnt * sizeof(trace_buffer[0])); + if (extra_top_pc) + trace_buffer[cnt] = extra_top_pc; + top_frame_bp = 0; +} + +// Sparc implementation is in its own file. +#if !defined(__sparc__) + +// In GCC on ARM bp points to saved lr, not fp, so we should check the next +// cell in stack to be a saved frame pointer. GetCanonicFrame returns the +// pointer to saved frame pointer in any case. +static inline uhwptr *GetCanonicFrame(uptr bp, + uptr stack_top, + uptr stack_bottom) { + CHECK_GT(stack_top, stack_bottom); +#ifdef __arm__ + if (!IsValidFrame(bp, stack_top, stack_bottom)) return 0; + uhwptr *bp_prev = (uhwptr *)bp; + if (IsValidFrame((uptr)bp_prev[0], stack_top, stack_bottom)) return bp_prev; + // The next frame pointer does not look right. This could be a GCC frame, step + // back by 1 word and try again. + if (IsValidFrame((uptr)bp_prev[-1], stack_top, stack_bottom)) + return bp_prev - 1; + // Nope, this does not look right either. This means the frame after next does + // not have a valid frame pointer, but we can still extract the caller PC. + // Unfortunately, there is no way to decide between GCC and LLVM frame + // layouts. Assume LLVM. + return bp_prev; +#else + return (uhwptr*)bp; +#endif +} + +void BufferedStackTrace::UnwindFast(uptr pc, uptr bp, uptr stack_top, + uptr stack_bottom, u32 max_depth) { + // TODO(yln): add arg sanity check for stack_top/stack_bottom + CHECK_GE(max_depth, 2); + const uptr kPageSize = GetPageSizeCached(); + trace_buffer[0] = pc; + size = 1; + if (stack_top < 4096) return; // Sanity check for stack top. + uhwptr *frame = GetCanonicFrame(bp, stack_top, stack_bottom); + // Lowest possible address that makes sense as the next frame pointer. + // Goes up as we walk the stack. + uptr bottom = stack_bottom; + // Avoid infinite loop when frame == frame[0] by using frame > prev_frame. + while (IsValidFrame((uptr)frame, stack_top, bottom) && + IsAligned((uptr)frame, sizeof(*frame)) && + size < max_depth) { +#ifdef __powerpc__ + // PowerPC ABIs specify that the return address is saved at offset + // 16 of the *caller's* stack frame. Thus we must dereference the + // back chain to find the caller frame before extracting it. + uhwptr *caller_frame = (uhwptr*)frame[0]; + if (!IsValidFrame((uptr)caller_frame, stack_top, bottom) || + !IsAligned((uptr)caller_frame, sizeof(uhwptr))) + break; + uhwptr pc1 = caller_frame[2]; +#elif defined(__s390__) + uhwptr pc1 = frame[14]; +#elif defined(__riscv) + // frame[-1] contains the return address + uhwptr pc1 = frame[-1]; +#else + uhwptr pc1 = STRIP_PAC_PC((void *)frame[1]); +#endif + // Let's assume that any pointer in the 0th page (i.e. <0x1000 on i386 and + // x86_64) is invalid and stop unwinding here. If we're adding support for + // a platform where this isn't true, we need to reconsider this check. + if (pc1 < kPageSize) + break; + if (pc1 != pc) { + trace_buffer[size++] = (uptr) pc1; + } + bottom = (uptr)frame; +#if defined(__riscv) + // frame[-2] contain fp of the previous frame + uptr new_bp = (uptr)frame[-2]; +#else + uptr new_bp = (uptr)frame[0]; +#endif + frame = GetCanonicFrame(new_bp, stack_top, bottom); + } +} + +#endif // !defined(__sparc__) + +void BufferedStackTrace::PopStackFrames(uptr count) { + CHECK_LT(count, size); + size -= count; + for (uptr i = 0; i < size; ++i) { + trace_buffer[i] = trace_buffer[i + count]; + } +} + +static uptr Distance(uptr a, uptr b) { return a < b ? b - a : a - b; } + +uptr BufferedStackTrace::LocatePcInTrace(uptr pc) { + uptr best = 0; + for (uptr i = 1; i < size; ++i) { + if (Distance(trace[i], pc) < Distance(trace[best], pc)) best = i; + } + return best; +} + +} // namespace __sanitizer diff --git a/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_stacktrace.h b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_stacktrace.h new file mode 100644 index 0000000000..aebd504669 --- /dev/null +++ b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_stacktrace.h @@ -0,0 +1,221 @@ +//===-- sanitizer_stacktrace.h ----------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file is shared between AddressSanitizer and ThreadSanitizer +// run-time libraries. +//===----------------------------------------------------------------------===// +#ifndef SANITIZER_STACKTRACE_H +#define SANITIZER_STACKTRACE_H + +#include "sanitizer_common.h" +#include "sanitizer_internal_defs.h" +#include "sanitizer_platform.h" + +namespace __sanitizer { + +struct BufferedStackTrace; + +static const u32 kStackTraceMax = 255; + +#if SANITIZER_LINUX && defined(__mips__) +# define SANITIZER_CAN_FAST_UNWIND 0 +#elif SANITIZER_WINDOWS +# define SANITIZER_CAN_FAST_UNWIND 0 +#else +# define SANITIZER_CAN_FAST_UNWIND 1 +#endif + +// Fast unwind is the only option on Mac for now; we will need to +// revisit this macro when slow unwind works on Mac, see +// https://github.com/google/sanitizers/issues/137 +#if SANITIZER_MAC +# define SANITIZER_CAN_SLOW_UNWIND 0 +#else +# define SANITIZER_CAN_SLOW_UNWIND 1 +#endif + +struct StackTrace { + const uptr *trace; + u32 size; + u32 tag; + + static const int TAG_UNKNOWN = 0; + static const int TAG_ALLOC = 1; + static const int TAG_DEALLOC = 2; + static const int TAG_CUSTOM = 100; // Tool specific tags start here. + + StackTrace() : trace(nullptr), size(0), tag(0) {} + StackTrace(const uptr *trace, u32 size) : trace(trace), size(size), tag(0) {} + StackTrace(const uptr *trace, u32 size, u32 tag) + : trace(trace), size(size), tag(tag) {} + + // Prints a symbolized stacktrace, followed by an empty line. + void Print() const; + + // Prints a symbolized stacktrace to the output string, followed by an empty + // line. + void PrintTo(InternalScopedString *output) const; + + // Prints a symbolized stacktrace to the output buffer, followed by an empty + // line. 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 "out_buf_size". + uptr PrintTo(char *out_buf, uptr out_buf_size) const; + + static bool WillUseFastUnwind(bool request_fast_unwind) { + if (!SANITIZER_CAN_FAST_UNWIND) + return false; + if (!SANITIZER_CAN_SLOW_UNWIND) + return true; + return request_fast_unwind; + } + + static uptr GetCurrentPc(); + static inline uptr GetPreviousInstructionPc(uptr pc); + static uptr GetNextInstructionPc(uptr pc); +}; + +// Performance-critical, must be in the header. +ALWAYS_INLINE +uptr StackTrace::GetPreviousInstructionPc(uptr pc) { +#if defined(__arm__) + // T32 (Thumb) branch instructions might be 16 or 32 bit long, + // so we return (pc-2) in that case in order to be safe. + // For A32 mode we return (pc-4) because all instructions are 32 bit long. + return (pc - 3) & (~1); +#elif defined(__powerpc__) || defined(__powerpc64__) || defined(__aarch64__) + // PCs are always 4 byte aligned. + return pc - 4; +#elif defined(__sparc__) || defined(__mips__) + return pc - 8; +#elif SANITIZER_RISCV64 + // RV-64 has variable instruciton length... + // C extentions gives us 2-byte instructoins + // RV-64 has 4-byte instructions + // + RISCV architecture allows instructions up to 8 bytes + // It seems difficult to figure out the exact instruction length - + // pc - 2 seems like a safe option for the purposes of stack tracing + return pc - 2; +#else + return pc - 1; +#endif +} + +// StackTrace that owns the buffer used to store the addresses. +struct BufferedStackTrace : public StackTrace { + uptr trace_buffer[kStackTraceMax]; + uptr top_frame_bp; // Optional bp of a top frame. + + BufferedStackTrace() : StackTrace(trace_buffer, 0), top_frame_bp(0) {} + + void Init(const uptr *pcs, uptr cnt, uptr extra_top_pc = 0); + + // Get the stack trace with the given pc and bp. + // The pc will be in the position 0 of the resulting stack trace. + // The bp may refer to the current frame or to the caller's frame. + void Unwind(uptr pc, uptr bp, void *context, bool request_fast, + u32 max_depth = kStackTraceMax) { + top_frame_bp = (max_depth > 0) ? bp : 0; + // Small max_depth optimization + if (max_depth <= 1) { + if (max_depth == 1) + trace_buffer[0] = pc; + size = max_depth; + return; + } + UnwindImpl(pc, bp, context, request_fast, max_depth); + } + + void Unwind(u32 max_depth, uptr pc, uptr bp, void *context, uptr stack_top, + uptr stack_bottom, bool request_fast_unwind); + + void Reset() { + *static_cast<StackTrace *>(this) = StackTrace(trace_buffer, 0); + top_frame_bp = 0; + } + + private: + // Every runtime defines its own implementation of this method + void UnwindImpl(uptr pc, uptr bp, void *context, bool request_fast, + u32 max_depth); + + // UnwindFast/Slow have platform-specific implementations + void UnwindFast(uptr pc, uptr bp, uptr stack_top, uptr stack_bottom, + u32 max_depth); + void UnwindSlow(uptr pc, u32 max_depth); + void UnwindSlow(uptr pc, void *context, u32 max_depth); + + void PopStackFrames(uptr count); + uptr LocatePcInTrace(uptr pc); + + BufferedStackTrace(const BufferedStackTrace &) = delete; + void operator=(const BufferedStackTrace &) = delete; + + friend class FastUnwindTest; +}; + +#if defined(__s390x__) +static const uptr kFrameSize = 160; +#elif defined(__s390__) +static const uptr kFrameSize = 96; +#else +static const uptr kFrameSize = 2 * sizeof(uhwptr); +#endif + +// Check if given pointer points into allocated stack area. +static inline bool IsValidFrame(uptr frame, uptr stack_top, uptr stack_bottom) { + return frame > stack_bottom && frame < stack_top - kFrameSize; +} + +} // namespace __sanitizer + +// Use this macro if you want to print stack trace with the caller +// of the current function in the top frame. +#define GET_CALLER_PC_BP \ + uptr bp = GET_CURRENT_FRAME(); \ + uptr pc = GET_CALLER_PC(); + +#define GET_CALLER_PC_BP_SP \ + GET_CALLER_PC_BP; \ + uptr local_stack; \ + uptr sp = (uptr)&local_stack + +// Use this macro if you want to print stack trace with the current +// function in the top frame. +#define GET_CURRENT_PC_BP \ + uptr bp = GET_CURRENT_FRAME(); \ + uptr pc = StackTrace::GetCurrentPc() + +#define GET_CURRENT_PC_BP_SP \ + GET_CURRENT_PC_BP; \ + uptr local_stack; \ + uptr sp = (uptr)&local_stack + +// GET_CURRENT_PC() is equivalent to StackTrace::GetCurrentPc(). +// Optimized x86 version is faster than GetCurrentPc because +// it does not involve a function call, instead it reads RIP register. +// Reads of RIP by an instruction return RIP pointing to the next +// instruction, which is exactly what we want here, thus 0 offset. +// It needs to be a macro because otherwise we will get the name +// of this function on the top of most stacks. Attribute artificial +// does not do what it claims to do, unfortunatley. And attribute +// __nodebug__ is clang-only. If we would have an attribute that +// would remove this function from debug info, we could simply make +// StackTrace::GetCurrentPc() faster. +#if defined(__x86_64__) +# define GET_CURRENT_PC() \ + (__extension__({ \ + uptr pc; \ + asm("lea 0(%%rip), %0" : "=r"(pc)); \ + pc; \ + })) +#else +# define GET_CURRENT_PC() StackTrace::GetCurrentPc() +#endif + +#endif // SANITIZER_STACKTRACE_H diff --git a/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_stacktrace_libcdep.cpp b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_stacktrace_libcdep.cpp new file mode 100644 index 0000000000..2d1c03f732 --- /dev/null +++ b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_stacktrace_libcdep.cpp @@ -0,0 +1,225 @@ +//===-- sanitizer_stacktrace_libcdep.cpp ----------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file is shared between AddressSanitizer and ThreadSanitizer +// run-time libraries. +//===----------------------------------------------------------------------===// + +#include "sanitizer_common.h" +#include "sanitizer_placement_new.h" +#include "sanitizer_stacktrace.h" +#include "sanitizer_stacktrace_printer.h" +#include "sanitizer_symbolizer.h" + +namespace __sanitizer { + +namespace { + +class StackTraceTextPrinter { + public: + StackTraceTextPrinter(const char *stack_trace_fmt, char frame_delimiter, + InternalScopedString *output, + InternalScopedString *dedup_token) + : stack_trace_fmt_(stack_trace_fmt), + frame_delimiter_(frame_delimiter), + output_(output), + dedup_token_(dedup_token), + symbolize_(RenderNeedsSymbolization(stack_trace_fmt)) {} + + bool ProcessAddressFrames(uptr pc) { + SymbolizedStack *frames = symbolize_ + ? Symbolizer::GetOrInit()->SymbolizePC(pc) + : SymbolizedStack::New(pc); + if (!frames) + return false; + + for (SymbolizedStack *cur = frames; cur; cur = cur->next) { + uptr prev_len = output_->length(); + RenderFrame(output_, stack_trace_fmt_, frame_num_++, cur->info.address, + symbolize_ ? &cur->info : nullptr, + common_flags()->symbolize_vs_style, + common_flags()->strip_path_prefix); + + if (prev_len != output_->length()) + output_->append("%c", frame_delimiter_); + + ExtendDedupToken(cur); + } + frames->ClearAll(); + return true; + } + + private: + // Extend the dedup token by appending a new frame. + void ExtendDedupToken(SymbolizedStack *stack) { + if (!dedup_token_) + return; + + if (dedup_frames_-- > 0) { + if (dedup_token_->length()) + dedup_token_->append("--"); + if (stack->info.function != nullptr) + dedup_token_->append("%s", stack->info.function); + } + } + + const char *stack_trace_fmt_; + const char frame_delimiter_; + int dedup_frames_ = common_flags()->dedup_token_length; + uptr frame_num_ = 0; + InternalScopedString *output_; + InternalScopedString *dedup_token_; + const bool symbolize_ = false; +}; + +static void CopyStringToBuffer(const InternalScopedString &str, char *out_buf, + uptr out_buf_size) { + if (!out_buf_size) + return; + + CHECK_GT(out_buf_size, 0); + uptr copy_size = Min(str.length(), out_buf_size - 1); + internal_memcpy(out_buf, str.data(), copy_size); + out_buf[copy_size] = '\0'; +} + +} // namespace + +void StackTrace::PrintTo(InternalScopedString *output) const { + CHECK(output); + + InternalScopedString dedup_token; + StackTraceTextPrinter printer(common_flags()->stack_trace_format, '\n', + output, &dedup_token); + + if (trace == nullptr || size == 0) { + output->append(" <empty stack>\n\n"); + return; + } + + for (uptr i = 0; i < size && trace[i]; i++) { + // PCs in stack traces are actually the return addresses, that is, + // addresses of the next instructions after the call. + uptr pc = GetPreviousInstructionPc(trace[i]); + CHECK(printer.ProcessAddressFrames(pc)); + } + + // Always add a trailing empty line after stack trace. + output->append("\n"); + + // Append deduplication token, if non-empty. + if (dedup_token.length()) + output->append("DEDUP_TOKEN: %s\n", dedup_token.data()); +} + +uptr StackTrace::PrintTo(char *out_buf, uptr out_buf_size) const { + CHECK(out_buf); + + InternalScopedString output; + PrintTo(&output); + CopyStringToBuffer(output, out_buf, out_buf_size); + + return output.length(); +} + +void StackTrace::Print() const { + InternalScopedString output; + PrintTo(&output); + Printf("%s", output.data()); +} + +void BufferedStackTrace::Unwind(u32 max_depth, uptr pc, uptr bp, void *context, + uptr stack_top, uptr stack_bottom, + bool request_fast_unwind) { + // Ensures all call sites get what they requested. + CHECK_EQ(request_fast_unwind, WillUseFastUnwind(request_fast_unwind)); + top_frame_bp = (max_depth > 0) ? bp : 0; + // Avoid doing any work for small max_depth. + if (max_depth == 0) { + size = 0; + return; + } + if (max_depth == 1) { + size = 1; + trace_buffer[0] = pc; + return; + } + if (!WillUseFastUnwind(request_fast_unwind)) { +#if SANITIZER_CAN_SLOW_UNWIND + if (context) + UnwindSlow(pc, context, max_depth); + else + UnwindSlow(pc, max_depth); + // If there are too few frames, the program may be built with + // -fno-asynchronous-unwind-tables. Fall back to fast unwinder below. + if (size > 2 || size >= max_depth) + return; +#else + UNREACHABLE("slow unwind requested but not available"); +#endif + } + UnwindFast(pc, bp, stack_top, stack_bottom, max_depth); +} + +static int GetModuleAndOffsetForPc(uptr pc, char *module_name, + uptr module_name_len, uptr *pc_offset) { + const char *found_module_name = nullptr; + bool ok = Symbolizer::GetOrInit()->GetModuleNameAndOffsetForPC( + pc, &found_module_name, pc_offset); + + if (!ok) return false; + + if (module_name && module_name_len) { + internal_strncpy(module_name, found_module_name, module_name_len); + module_name[module_name_len - 1] = '\x00'; + } + return true; +} + +} // namespace __sanitizer +using namespace __sanitizer; + +extern "C" { +SANITIZER_INTERFACE_ATTRIBUTE +void __sanitizer_symbolize_pc(uptr pc, const char *fmt, char *out_buf, + uptr out_buf_size) { + if (!out_buf_size) + return; + + pc = StackTrace::GetPreviousInstructionPc(pc); + + InternalScopedString output; + StackTraceTextPrinter printer(fmt, '\0', &output, nullptr); + if (!printer.ProcessAddressFrames(pc)) { + output.clear(); + output.append("<can't symbolize>"); + } + CopyStringToBuffer(output, out_buf, out_buf_size); +} + +SANITIZER_INTERFACE_ATTRIBUTE +void __sanitizer_symbolize_global(uptr data_addr, const char *fmt, + char *out_buf, uptr out_buf_size) { + if (!out_buf_size) return; + out_buf[0] = 0; + DataInfo DI; + if (!Symbolizer::GetOrInit()->SymbolizeData(data_addr, &DI)) return; + InternalScopedString data_desc; + RenderData(&data_desc, fmt, &DI, common_flags()->strip_path_prefix); + internal_strncpy(out_buf, data_desc.data(), out_buf_size); + out_buf[out_buf_size - 1] = 0; +} + +SANITIZER_INTERFACE_ATTRIBUTE +int __sanitizer_get_module_and_offset_for_pc(uptr pc, char *module_name, + uptr module_name_len, + uptr *pc_offset) { + return __sanitizer::GetModuleAndOffsetForPc(pc, module_name, module_name_len, + pc_offset); +} +} // extern "C" diff --git a/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_stacktrace_printer.cpp b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_stacktrace_printer.cpp new file mode 100644 index 0000000000..2d0eccc160 --- /dev/null +++ b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_stacktrace_printer.cpp @@ -0,0 +1,310 @@ +//===-- sanitizer_common.cpp ----------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file is shared between sanitizers' run-time libraries. +// +//===----------------------------------------------------------------------===// + +#include "sanitizer_stacktrace_printer.h" +#include "sanitizer_file.h" +#include "sanitizer_fuchsia.h" + +namespace __sanitizer { + +// sanitizer_symbolizer_markup.cpp implements these differently. +#if !SANITIZER_SYMBOLIZER_MARKUP + +static const char *StripFunctionName(const char *function, const char *prefix) { + if (!function) return nullptr; + if (!prefix) return function; + uptr prefix_len = internal_strlen(prefix); + if (0 == internal_strncmp(function, prefix, prefix_len)) + return function + prefix_len; + return function; +} + +static const char *DemangleFunctionName(const char *function) { + if (!function) return nullptr; + + // NetBSD uses indirection for old threading functions for historical reasons + // The mangled names are internal implementation detail and should not be + // exposed even in backtraces. +#if SANITIZER_NETBSD + if (!internal_strcmp(function, "__libc_mutex_init")) + return "pthread_mutex_init"; + if (!internal_strcmp(function, "__libc_mutex_lock")) + return "pthread_mutex_lock"; + if (!internal_strcmp(function, "__libc_mutex_trylock")) + return "pthread_mutex_trylock"; + if (!internal_strcmp(function, "__libc_mutex_unlock")) + return "pthread_mutex_unlock"; + if (!internal_strcmp(function, "__libc_mutex_destroy")) + return "pthread_mutex_destroy"; + if (!internal_strcmp(function, "__libc_mutexattr_init")) + return "pthread_mutexattr_init"; + if (!internal_strcmp(function, "__libc_mutexattr_settype")) + return "pthread_mutexattr_settype"; + if (!internal_strcmp(function, "__libc_mutexattr_destroy")) + return "pthread_mutexattr_destroy"; + if (!internal_strcmp(function, "__libc_cond_init")) + return "pthread_cond_init"; + if (!internal_strcmp(function, "__libc_cond_signal")) + return "pthread_cond_signal"; + if (!internal_strcmp(function, "__libc_cond_broadcast")) + return "pthread_cond_broadcast"; + if (!internal_strcmp(function, "__libc_cond_wait")) + return "pthread_cond_wait"; + if (!internal_strcmp(function, "__libc_cond_timedwait")) + return "pthread_cond_timedwait"; + if (!internal_strcmp(function, "__libc_cond_destroy")) + return "pthread_cond_destroy"; + if (!internal_strcmp(function, "__libc_rwlock_init")) + return "pthread_rwlock_init"; + if (!internal_strcmp(function, "__libc_rwlock_rdlock")) + return "pthread_rwlock_rdlock"; + if (!internal_strcmp(function, "__libc_rwlock_wrlock")) + return "pthread_rwlock_wrlock"; + if (!internal_strcmp(function, "__libc_rwlock_tryrdlock")) + return "pthread_rwlock_tryrdlock"; + if (!internal_strcmp(function, "__libc_rwlock_trywrlock")) + return "pthread_rwlock_trywrlock"; + if (!internal_strcmp(function, "__libc_rwlock_unlock")) + return "pthread_rwlock_unlock"; + if (!internal_strcmp(function, "__libc_rwlock_destroy")) + return "pthread_rwlock_destroy"; + if (!internal_strcmp(function, "__libc_thr_keycreate")) + return "pthread_key_create"; + if (!internal_strcmp(function, "__libc_thr_setspecific")) + return "pthread_setspecific"; + if (!internal_strcmp(function, "__libc_thr_getspecific")) + return "pthread_getspecific"; + if (!internal_strcmp(function, "__libc_thr_keydelete")) + return "pthread_key_delete"; + if (!internal_strcmp(function, "__libc_thr_once")) + return "pthread_once"; + if (!internal_strcmp(function, "__libc_thr_self")) + return "pthread_self"; + if (!internal_strcmp(function, "__libc_thr_exit")) + return "pthread_exit"; + if (!internal_strcmp(function, "__libc_thr_setcancelstate")) + return "pthread_setcancelstate"; + if (!internal_strcmp(function, "__libc_thr_equal")) + return "pthread_equal"; + if (!internal_strcmp(function, "__libc_thr_curcpu")) + return "pthread_curcpu_np"; + if (!internal_strcmp(function, "__libc_thr_sigsetmask")) + return "pthread_sigmask"; +#endif + + return function; +} + +static void MaybeBuildIdToBuffer(const AddressInfo &info, bool PrefixSpace, + InternalScopedString *buffer) { + if (info.uuid_size) { + if (PrefixSpace) + buffer->append(" "); + buffer->append("(BuildId: "); + for (uptr i = 0; i < info.uuid_size; ++i) { + buffer->append("%02x", info.uuid[i]); + } + buffer->append(")"); + } +} + +static const char kDefaultFormat[] = " #%n %p %F %L"; + +void RenderFrame(InternalScopedString *buffer, const char *format, int frame_no, + uptr address, const AddressInfo *info, bool vs_style, + const char *strip_path_prefix, const char *strip_func_prefix) { + // info will be null in the case where symbolization is not needed for the + // given format. This ensures that the code below will get a hard failure + // rather than print incorrect information in case RenderNeedsSymbolization + // ever ends up out of sync with this function. If non-null, the addresses + // should match. + CHECK(!info || address == info->address); + if (0 == internal_strcmp(format, "DEFAULT")) + format = kDefaultFormat; + for (const char *p = format; *p != '\0'; p++) { + if (*p != '%') { + buffer->append("%c", *p); + continue; + } + p++; + switch (*p) { + case '%': + buffer->append("%%"); + break; + // Frame number and all fields of AddressInfo structure. + case 'n': + buffer->append("%u", frame_no); + break; + case 'p': + buffer->append("0x%zx", address); + break; + case 'm': + buffer->append("%s", StripPathPrefix(info->module, strip_path_prefix)); + break; + case 'o': + buffer->append("0x%zx", info->module_offset); + break; + case 'b': + MaybeBuildIdToBuffer(*info, /*PrefixSpace=*/false, buffer); + break; + case 'f': + buffer->append("%s", DemangleFunctionName(StripFunctionName( + info->function, strip_func_prefix))); + break; + case 'q': + buffer->append("0x%zx", info->function_offset != AddressInfo::kUnknown + ? info->function_offset + : 0x0); + break; + case 's': + buffer->append("%s", StripPathPrefix(info->file, strip_path_prefix)); + break; + case 'l': + buffer->append("%d", info->line); + break; + case 'c': + buffer->append("%d", info->column); + break; + // Smarter special cases. + case 'F': + // Function name and offset, if file is unknown. + if (info->function) { + buffer->append("in %s", DemangleFunctionName(StripFunctionName( + info->function, strip_func_prefix))); + if (!info->file && info->function_offset != AddressInfo::kUnknown) + buffer->append("+0x%zx", info->function_offset); + } + break; + case 'S': + // File/line information. + RenderSourceLocation(buffer, info->file, info->line, info->column, + vs_style, strip_path_prefix); + break; + case 'L': + // Source location, or module location. + if (info->file) { + RenderSourceLocation(buffer, info->file, info->line, info->column, + vs_style, strip_path_prefix); + } else if (info->module) { + RenderModuleLocation(buffer, info->module, info->module_offset, + info->module_arch, strip_path_prefix); + + MaybeBuildIdToBuffer(*info, /*PrefixSpace=*/true, buffer); + } else { + buffer->append("(<unknown module>)"); + } + break; + case 'M': + // Module basename and offset, or PC. + if (address & kExternalPCBit) { + // There PCs are not meaningful. + } else if (info->module) { + // Always strip the module name for %M. + RenderModuleLocation(buffer, StripModuleName(info->module), + info->module_offset, info->module_arch, ""); + MaybeBuildIdToBuffer(*info, /*PrefixSpace=*/true, buffer); + } else { + buffer->append("(%p)", (void *)address); + } + break; + default: + Report("Unsupported specifier in stack frame format: %c (%p)!\n", *p, + (void *)p); + Die(); + } + } +} + +bool RenderNeedsSymbolization(const char *format) { + if (0 == internal_strcmp(format, "DEFAULT")) + format = kDefaultFormat; + for (const char *p = format; *p != '\0'; p++) { + if (*p != '%') + continue; + p++; + switch (*p) { + case '%': + break; + case 'n': + // frame_no + break; + case 'p': + // address + break; + default: + return true; + } + } + return false; +} + +void RenderData(InternalScopedString *buffer, const char *format, + const DataInfo *DI, const char *strip_path_prefix) { + for (const char *p = format; *p != '\0'; p++) { + if (*p != '%') { + buffer->append("%c", *p); + continue; + } + p++; + switch (*p) { + case '%': + buffer->append("%%"); + break; + case 's': + buffer->append("%s", StripPathPrefix(DI->file, strip_path_prefix)); + break; + case 'l': + buffer->append("%zu", DI->line); + break; + case 'g': + buffer->append("%s", DI->name); + break; + default: + Report("Unsupported specifier in stack frame format: %c (%p)!\n", *p, + (void *)p); + Die(); + } + } +} + +#endif // !SANITIZER_SYMBOLIZER_MARKUP + +void RenderSourceLocation(InternalScopedString *buffer, const char *file, + int line, int column, bool vs_style, + const char *strip_path_prefix) { + if (vs_style && line > 0) { + buffer->append("%s(%d", StripPathPrefix(file, strip_path_prefix), line); + if (column > 0) + buffer->append(",%d", column); + buffer->append(")"); + return; + } + + buffer->append("%s", StripPathPrefix(file, strip_path_prefix)); + if (line > 0) { + buffer->append(":%d", line); + if (column > 0) + buffer->append(":%d", column); + } +} + +void RenderModuleLocation(InternalScopedString *buffer, const char *module, + uptr offset, ModuleArch arch, + const char *strip_path_prefix) { + buffer->append("(%s", StripPathPrefix(module, strip_path_prefix)); + if (arch != kModuleArchUnknown) { + buffer->append(":%s", ModuleArchToString(arch)); + } + buffer->append("+0x%zx)", offset); +} + +} // namespace __sanitizer diff --git a/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_stacktrace_printer.h b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_stacktrace_printer.h new file mode 100644 index 0000000000..96119b2ee9 --- /dev/null +++ b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_stacktrace_printer.h @@ -0,0 +1,73 @@ +//===-- sanitizer_stacktrace_printer.h --------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file is shared between sanitizers' run-time libraries. +// +//===----------------------------------------------------------------------===// +#ifndef SANITIZER_STACKTRACE_PRINTER_H +#define SANITIZER_STACKTRACE_PRINTER_H + +#include "sanitizer_common.h" +#include "sanitizer_symbolizer.h" + +namespace __sanitizer { + +// Render the contents of "info" structure, which represents the contents of +// stack frame "frame_no" and appends it to the "buffer". "format" is a +// string with placeholders, which is copied to the output with +// placeholders substituted with the contents of "info". For example, +// format string +// " frame %n: function %F at %S" +// will be turned into +// " frame 10: function foo::bar() at my/file.cc:10" +// You may additionally pass "strip_path_prefix" to strip prefixes of paths to +// source files and modules, and "strip_func_prefix" to strip prefixes of +// function names. +// Here's the full list of available placeholders: +// %% - represents a '%' character; +// %n - frame number (copy of frame_no); +// %p - PC in hex format; +// %m - path to module (binary or shared object); +// %o - offset in the module in hex format; +// %f - function name; +// %q - offset in the function in hex format (*if available*); +// %s - path to source file; +// %l - line in the source file; +// %c - column in the source file; +// %F - if function is known to be <foo>, prints "in <foo>", possibly +// followed by the offset in this function, but only if source file +// is unknown; +// %S - prints file/line/column information; +// %L - prints location information: file/line/column, if it is known, or +// module+offset if it is known, or (<unknown module>) string. +// %M - prints module basename and offset, if it is known, or PC. +void RenderFrame(InternalScopedString *buffer, const char *format, int frame_no, + uptr address, const AddressInfo *info, bool vs_style, + const char *strip_path_prefix = "", + const char *strip_func_prefix = ""); + +bool RenderNeedsSymbolization(const char *format); + +void RenderSourceLocation(InternalScopedString *buffer, const char *file, + int line, int column, bool vs_style, + const char *strip_path_prefix); + +void RenderModuleLocation(InternalScopedString *buffer, const char *module, + uptr offset, ModuleArch arch, + const char *strip_path_prefix); + +// Same as RenderFrame, but for data section (global variables). +// Accepts %s, %l from above. +// Also accepts: +// %g - name of the global variable. +void RenderData(InternalScopedString *buffer, const char *format, + const DataInfo *DI, const char *strip_path_prefix = ""); + +} // namespace __sanitizer + +#endif // SANITIZER_STACKTRACE_PRINTER_H diff --git a/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_stacktrace_sparc.cpp b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_stacktrace_sparc.cpp new file mode 100644 index 0000000000..1e635a6697 --- /dev/null +++ b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_stacktrace_sparc.cpp @@ -0,0 +1,85 @@ +//===-- sanitizer_stacktrace_sparc.cpp ------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file is shared between AddressSanitizer and ThreadSanitizer +// run-time libraries. +// +// Implementation of fast stack unwinding for Sparc. +//===----------------------------------------------------------------------===// + +#if defined(__sparc__) + +#if defined(__arch64__) || defined(__sparcv9) +#define STACK_BIAS 2047 +#else +#define STACK_BIAS 0 +#endif + +#include "sanitizer_common.h" +#include "sanitizer_stacktrace.h" + +namespace __sanitizer { + +void BufferedStackTrace::UnwindFast(uptr pc, uptr bp, uptr stack_top, + uptr stack_bottom, u32 max_depth) { + // TODO(yln): add arg sanity check for stack_top/stack_bottom + CHECK_GE(max_depth, 2); + const uptr kPageSize = GetPageSizeCached(); +#if defined(__GNUC__) + // __builtin_return_address returns the address of the call instruction + // on the SPARC and not the return address, so we need to compensate. + trace_buffer[0] = GetNextInstructionPc(pc); +#else + trace_buffer[0] = pc; +#endif + size = 1; + if (stack_top < 4096) return; // Sanity check for stack top. + // Flush register windows to memory +#if defined(__sparc_v9__) || defined(__sparcv9__) || defined(__sparcv9) + asm volatile("flushw" ::: "memory"); +#else + asm volatile("ta 3" ::: "memory"); +#endif + // On the SPARC, the return address is not in the frame, it is in a + // register. There is no way to access it off of the current frame + // pointer, but it can be accessed off the previous frame pointer by + // reading the value from the register window save area. + uptr prev_bp = GET_CURRENT_FRAME(); + uptr next_bp = prev_bp; + unsigned int i = 0; + while (next_bp != bp && IsAligned(next_bp, sizeof(uhwptr)) && i++ < 8) { + prev_bp = next_bp; + next_bp = (uptr)((uhwptr *)next_bp)[14] + STACK_BIAS; + } + if (next_bp == bp) + bp = prev_bp; + // Lowest possible address that makes sense as the next frame pointer. + // Goes up as we walk the stack. + uptr bottom = stack_bottom; + // Avoid infinite loop when frame == frame[0] by using frame > prev_frame. + while (IsValidFrame(bp, stack_top, bottom) && IsAligned(bp, sizeof(uhwptr)) && + size < max_depth) { + uhwptr pc1 = ((uhwptr *)bp)[15]; + // Let's assume that any pointer in the 0th page is invalid and + // stop unwinding here. If we're adding support for a platform + // where this isn't true, we need to reconsider this check. + if (pc1 < kPageSize) + break; + if (pc1 != pc) { + // %o7 contains the address of the call instruction and not the + // return address, so we need to compensate. + trace_buffer[size++] = GetNextInstructionPc((uptr)pc1); + } + bottom = bp; + bp = (uptr)((uhwptr *)bp)[14] + STACK_BIAS; + } +} + +} // namespace __sanitizer + +#endif // !defined(__sparc__) diff --git a/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_stoptheworld.h b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_stoptheworld.h new file mode 100644 index 0000000000..7891c1081f --- /dev/null +++ b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_stoptheworld.h @@ -0,0 +1,65 @@ +//===-- sanitizer_stoptheworld.h --------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// Defines the StopTheWorld function which suspends the execution of the current +// process and runs the user-supplied callback in the same address space. +// +//===----------------------------------------------------------------------===// +#ifndef SANITIZER_STOPTHEWORLD_H +#define SANITIZER_STOPTHEWORLD_H + +#include "sanitizer_internal_defs.h" +#include "sanitizer_common.h" + +namespace __sanitizer { + +enum PtraceRegistersStatus { + REGISTERS_UNAVAILABLE_FATAL = -1, + REGISTERS_UNAVAILABLE = 0, + REGISTERS_AVAILABLE = 1 +}; + +// Holds the list of suspended threads and provides an interface to dump their +// register contexts. +class SuspendedThreadsList { + public: + SuspendedThreadsList() = default; + + // Can't declare pure virtual functions in sanitizer runtimes: + // __cxa_pure_virtual might be unavailable. Use UNIMPLEMENTED() instead. + virtual PtraceRegistersStatus GetRegistersAndSP( + uptr index, InternalMmapVector<uptr> *buffer, uptr *sp) const { + UNIMPLEMENTED(); + } + + virtual uptr ThreadCount() const { UNIMPLEMENTED(); } + virtual tid_t GetThreadID(uptr index) const { UNIMPLEMENTED(); } + + protected: + ~SuspendedThreadsList() {} + + private: + // Prohibit copy and assign. + SuspendedThreadsList(const SuspendedThreadsList &) = delete; + void operator=(const SuspendedThreadsList &) = delete; +}; + +typedef void (*StopTheWorldCallback)( + const SuspendedThreadsList &suspended_threads_list, + void *argument); + +// Suspend all threads in the current process and run the callback on the list +// of suspended threads. This function will resume the threads before returning. +// The callback should not call any libc functions. The callback must not call +// exit() nor _exit() and instead return to the caller. +// This function should NOT be called from multiple threads simultaneously. +void StopTheWorld(StopTheWorldCallback callback, void *argument); + +} // namespace __sanitizer + +#endif // SANITIZER_STOPTHEWORLD_H diff --git a/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_stoptheworld_fuchsia.cpp b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_stoptheworld_fuchsia.cpp new file mode 100644 index 0000000000..4cc6720076 --- /dev/null +++ b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_stoptheworld_fuchsia.cpp @@ -0,0 +1,43 @@ +//===-- sanitizer_stoptheworld_fuchsia.cpp -------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===---------------------------------------------------------------------===// +// +// See sanitizer_stoptheworld.h for details. +// +//===---------------------------------------------------------------------===// + +#include "sanitizer_platform.h" + +#if SANITIZER_FUCHSIA + +#error #include <zircon/sanitizer.h> + +#include "sanitizer_stoptheworld.h" +#include "sanitizer_stoptheworld_fuchsia.h" + +namespace __sanitizer { + +// The Fuchsia implementation stops the world but doesn't offer a real +// SuspendedThreadsList argument. This is enough for ASan's use case, +// and LSan does not use this API on Fuchsia. +void StopTheWorld(StopTheWorldCallback callback, void *argument) { + struct Params { + StopTheWorldCallback callback; + void *argument; + } params = {callback, argument}; + __sanitizer_memory_snapshot( + nullptr, nullptr, nullptr, nullptr, + [](zx_status_t, void *data) { + auto params = reinterpret_cast<Params *>(data); + params->callback(SuspendedThreadsListFuchsia(), params->argument); + }, + ¶ms); +} + +} // namespace __sanitizer + +#endif // SANITIZER_FUCHSIA diff --git a/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_stoptheworld_fuchsia.h b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_stoptheworld_fuchsia.h new file mode 100644 index 0000000000..6d9ead6050 --- /dev/null +++ b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_stoptheworld_fuchsia.h @@ -0,0 +1,20 @@ +//===-- sanitizer_stoptheworld_fuchsia.h ------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef SANITIZER_STOPTHEWORLD_FUCHSIA_H +#define SANITIZER_STOPTHEWORLD_FUCHSIA_H + +#include "sanitizer_stoptheworld.h" + +namespace __sanitizer { + +class SuspendedThreadsListFuchsia final : public SuspendedThreadsList {}; + +} // namespace __sanitizer + +#endif // SANITIZER_STOPTHEWORLD_FUCHSIA_H diff --git a/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cpp b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cpp new file mode 100644 index 0000000000..74eea9d0fa --- /dev/null +++ b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cpp @@ -0,0 +1,623 @@ +//===-- sanitizer_stoptheworld_linux_libcdep.cpp --------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// See sanitizer_stoptheworld.h for details. +// This implementation was inspired by Markus Gutschke's linuxthreads.cc. +// +//===----------------------------------------------------------------------===// + +#include "sanitizer_platform.h" + +#if SANITIZER_LINUX && \ + (defined(__x86_64__) || defined(__mips__) || defined(__aarch64__) || \ + defined(__powerpc64__) || defined(__s390__) || defined(__i386__) || \ + defined(__arm__) || SANITIZER_RISCV64) + +#include "sanitizer_stoptheworld.h" + +#include "sanitizer_platform_limits_posix.h" +#include "sanitizer_atomic.h" + +#include <errno.h> +#include <sched.h> // for CLONE_* definitions +#include <stddef.h> +#include <sys/prctl.h> // for PR_* definitions +#include <sys/ptrace.h> // for PTRACE_* definitions +#include <sys/types.h> // for pid_t +#include <sys/uio.h> // for iovec +#include <elf.h> // for NT_PRSTATUS +#if (defined(__aarch64__) || SANITIZER_RISCV64) && !SANITIZER_ANDROID +// GLIBC 2.20+ sys/user does not include asm/ptrace.h +# include <asm/ptrace.h> +#endif +#include <sys/user.h> // for user_regs_struct +#if SANITIZER_ANDROID && SANITIZER_MIPS +# error #include <asm/reg.h> // for mips SP register in sys/user.h +#endif +#include <sys/wait.h> // for signal-related stuff + +#ifdef sa_handler +# undef sa_handler +#endif + +#ifdef sa_sigaction +# undef sa_sigaction +#endif + +#include "sanitizer_common.h" +#include "sanitizer_flags.h" +#include "sanitizer_libc.h" +#include "sanitizer_linux.h" +#include "sanitizer_mutex.h" +#include "sanitizer_placement_new.h" + +// Sufficiently old kernel headers don't provide this value, but we can still +// call prctl with it. If the runtime kernel is new enough, the prctl call will +// have the desired effect; if the kernel is too old, the call will error and we +// can ignore said error. +#ifndef PR_SET_PTRACER +#define PR_SET_PTRACER 0x59616d61 +#endif + +// This module works by spawning a Linux task which then attaches to every +// thread in the caller process with ptrace. This suspends the threads, and +// PTRACE_GETREGS can then be used to obtain their register state. The callback +// supplied to StopTheWorld() is run in the tracer task while the threads are +// suspended. +// The tracer task must be placed in a different thread group for ptrace to +// work, so it cannot be spawned as a pthread. Instead, we use the low-level +// clone() interface (we want to share the address space with the caller +// process, so we prefer clone() over fork()). +// +// We don't use any libc functions, relying instead on direct syscalls. There +// are two reasons for this: +// 1. calling a library function while threads are suspended could cause a +// deadlock, if one of the treads happens to be holding a libc lock; +// 2. it's generally not safe to call libc functions from the tracer task, +// because clone() does not set up a thread-local storage for it. Any +// thread-local variables used by libc will be shared between the tracer task +// and the thread which spawned it. + +namespace __sanitizer { + +class SuspendedThreadsListLinux final : public SuspendedThreadsList { + public: + SuspendedThreadsListLinux() { thread_ids_.reserve(1024); } + + tid_t GetThreadID(uptr index) const override; + uptr ThreadCount() const override; + bool ContainsTid(tid_t thread_id) const; + void Append(tid_t tid); + + PtraceRegistersStatus GetRegistersAndSP(uptr index, + InternalMmapVector<uptr> *buffer, + uptr *sp) const override; + + private: + InternalMmapVector<tid_t> thread_ids_; +}; + +// Structure for passing arguments into the tracer thread. +struct TracerThreadArgument { + StopTheWorldCallback callback; + void *callback_argument; + // The tracer thread waits on this mutex while the parent finishes its + // preparations. + Mutex mutex; + // Tracer thread signals its completion by setting done. + atomic_uintptr_t done; + uptr parent_pid; +}; + +// This class handles thread suspending/unsuspending in the tracer thread. +class ThreadSuspender { + public: + explicit ThreadSuspender(pid_t pid, TracerThreadArgument *arg) + : arg(arg) + , pid_(pid) { + CHECK_GE(pid, 0); + } + bool SuspendAllThreads(); + void ResumeAllThreads(); + void KillAllThreads(); + SuspendedThreadsListLinux &suspended_threads_list() { + return suspended_threads_list_; + } + TracerThreadArgument *arg; + private: + SuspendedThreadsListLinux suspended_threads_list_; + pid_t pid_; + bool SuspendThread(tid_t thread_id); +}; + +bool ThreadSuspender::SuspendThread(tid_t tid) { + // Are we already attached to this thread? + // Currently this check takes linear time, however the number of threads is + // usually small. + if (suspended_threads_list_.ContainsTid(tid)) return false; + int pterrno; + if (internal_iserror(internal_ptrace(PTRACE_ATTACH, tid, nullptr, nullptr), + &pterrno)) { + // Either the thread is dead, or something prevented us from attaching. + // Log this event and move on. + VReport(1, "Could not attach to thread %zu (errno %d).\n", (uptr)tid, + pterrno); + return false; + } else { + VReport(2, "Attached to thread %zu.\n", (uptr)tid); + // The thread is not guaranteed to stop before ptrace returns, so we must + // wait on it. Note: if the thread receives a signal concurrently, + // we can get notification about the signal before notification about stop. + // In such case we need to forward the signal to the thread, otherwise + // the signal will be missed (as we do PTRACE_DETACH with arg=0) and + // any logic relying on signals will break. After forwarding we need to + // continue to wait for stopping, because the thread is not stopped yet. + // We do ignore delivery of SIGSTOP, because we want to make stop-the-world + // as invisible as possible. + for (;;) { + int status; + uptr waitpid_status; + HANDLE_EINTR(waitpid_status, internal_waitpid(tid, &status, __WALL)); + int wperrno; + if (internal_iserror(waitpid_status, &wperrno)) { + // Got a ECHILD error. I don't think this situation is possible, but it + // doesn't hurt to report it. + VReport(1, "Waiting on thread %zu failed, detaching (errno %d).\n", + (uptr)tid, wperrno); + internal_ptrace(PTRACE_DETACH, tid, nullptr, nullptr); + return false; + } + if (WIFSTOPPED(status) && WSTOPSIG(status) != SIGSTOP) { + internal_ptrace(PTRACE_CONT, tid, nullptr, + (void*)(uptr)WSTOPSIG(status)); + continue; + } + break; + } + suspended_threads_list_.Append(tid); + return true; + } +} + +void ThreadSuspender::ResumeAllThreads() { + for (uptr i = 0; i < suspended_threads_list_.ThreadCount(); i++) { + pid_t tid = suspended_threads_list_.GetThreadID(i); + int pterrno; + if (!internal_iserror(internal_ptrace(PTRACE_DETACH, tid, nullptr, nullptr), + &pterrno)) { + VReport(2, "Detached from thread %d.\n", tid); + } else { + // Either the thread is dead, or we are already detached. + // The latter case is possible, for instance, if this function was called + // from a signal handler. + VReport(1, "Could not detach from thread %d (errno %d).\n", tid, pterrno); + } + } +} + +void ThreadSuspender::KillAllThreads() { + for (uptr i = 0; i < suspended_threads_list_.ThreadCount(); i++) + internal_ptrace(PTRACE_KILL, suspended_threads_list_.GetThreadID(i), + nullptr, nullptr); +} + +bool ThreadSuspender::SuspendAllThreads() { + ThreadLister thread_lister(pid_); + bool retry = true; + InternalMmapVector<tid_t> threads; + threads.reserve(128); + for (int i = 0; i < 30 && retry; ++i) { + retry = false; + switch (thread_lister.ListThreads(&threads)) { + case ThreadLister::Error: + ResumeAllThreads(); + return false; + case ThreadLister::Incomplete: + retry = true; + break; + case ThreadLister::Ok: + break; + } + for (tid_t tid : threads) { + if (SuspendThread(tid)) + retry = true; + } + } + return suspended_threads_list_.ThreadCount(); +} + +// Pointer to the ThreadSuspender instance for use in signal handler. +static ThreadSuspender *thread_suspender_instance = nullptr; + +// Synchronous signals that should not be blocked. +static const int kSyncSignals[] = { SIGABRT, SIGILL, SIGFPE, SIGSEGV, SIGBUS, + SIGXCPU, SIGXFSZ }; + +static void TracerThreadDieCallback() { + // Generally a call to Die() in the tracer thread should be fatal to the + // parent process as well, because they share the address space. + // This really only works correctly if all the threads are suspended at this + // point. So we correctly handle calls to Die() from within the callback, but + // not those that happen before or after the callback. Hopefully there aren't + // a lot of opportunities for that to happen... + ThreadSuspender *inst = thread_suspender_instance; + if (inst && stoptheworld_tracer_pid == internal_getpid()) { + inst->KillAllThreads(); + thread_suspender_instance = nullptr; + } +} + +// Signal handler to wake up suspended threads when the tracer thread dies. +static void TracerThreadSignalHandler(int signum, __sanitizer_siginfo *siginfo, + void *uctx) { + SignalContext ctx(siginfo, uctx); + Printf("Tracer caught signal %d: addr=0x%zx pc=0x%zx sp=0x%zx\n", signum, + ctx.addr, ctx.pc, ctx.sp); + ThreadSuspender *inst = thread_suspender_instance; + if (inst) { + if (signum == SIGABRT) + inst->KillAllThreads(); + else + inst->ResumeAllThreads(); + RAW_CHECK(RemoveDieCallback(TracerThreadDieCallback)); + thread_suspender_instance = nullptr; + atomic_store(&inst->arg->done, 1, memory_order_relaxed); + } + internal__exit((signum == SIGABRT) ? 1 : 2); +} + +// Size of alternative stack for signal handlers in the tracer thread. +static const int kHandlerStackSize = 8192; + +// This function will be run as a cloned task. +static int TracerThread(void* argument) { + TracerThreadArgument *tracer_thread_argument = + (TracerThreadArgument *)argument; + + internal_prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0); + // Check if parent is already dead. + if (internal_getppid() != tracer_thread_argument->parent_pid) + internal__exit(4); + + // Wait for the parent thread to finish preparations. + tracer_thread_argument->mutex.Lock(); + tracer_thread_argument->mutex.Unlock(); + + RAW_CHECK(AddDieCallback(TracerThreadDieCallback)); + + ThreadSuspender thread_suspender(internal_getppid(), tracer_thread_argument); + // Global pointer for the signal handler. + thread_suspender_instance = &thread_suspender; + + // Alternate stack for signal handling. + InternalMmapVector<char> handler_stack_memory(kHandlerStackSize); + stack_t handler_stack; + internal_memset(&handler_stack, 0, sizeof(handler_stack)); + handler_stack.ss_sp = handler_stack_memory.data(); + handler_stack.ss_size = kHandlerStackSize; + internal_sigaltstack(&handler_stack, nullptr); + + // Install our handler for synchronous signals. Other signals should be + // blocked by the mask we inherited from the parent thread. + for (uptr i = 0; i < ARRAY_SIZE(kSyncSignals); i++) { + __sanitizer_sigaction act; + internal_memset(&act, 0, sizeof(act)); + act.sigaction = TracerThreadSignalHandler; + act.sa_flags = SA_ONSTACK | SA_SIGINFO; + internal_sigaction_norestorer(kSyncSignals[i], &act, 0); + } + + int exit_code = 0; + if (!thread_suspender.SuspendAllThreads()) { + VReport(1, "Failed suspending threads.\n"); + exit_code = 3; + } else { + tracer_thread_argument->callback(thread_suspender.suspended_threads_list(), + tracer_thread_argument->callback_argument); + thread_suspender.ResumeAllThreads(); + exit_code = 0; + } + RAW_CHECK(RemoveDieCallback(TracerThreadDieCallback)); + thread_suspender_instance = nullptr; + atomic_store(&tracer_thread_argument->done, 1, memory_order_relaxed); + return exit_code; +} + +class ScopedStackSpaceWithGuard { + public: + explicit ScopedStackSpaceWithGuard(uptr stack_size) { + stack_size_ = stack_size; + guard_size_ = GetPageSizeCached(); + // FIXME: Omitting MAP_STACK here works in current kernels but might break + // in the future. + guard_start_ = (uptr)MmapOrDie(stack_size_ + guard_size_, + "ScopedStackWithGuard"); + CHECK(MprotectNoAccess((uptr)guard_start_, guard_size_)); + } + ~ScopedStackSpaceWithGuard() { + UnmapOrDie((void *)guard_start_, stack_size_ + guard_size_); + } + void *Bottom() const { + return (void *)(guard_start_ + stack_size_ + guard_size_); + } + + private: + uptr stack_size_; + uptr guard_size_; + uptr guard_start_; +}; + +// We have a limitation on the stack frame size, so some stuff had to be moved +// into globals. +static __sanitizer_sigset_t blocked_sigset; +static __sanitizer_sigset_t old_sigset; + +class StopTheWorldScope { + public: + StopTheWorldScope() { + // Make this process dumpable. Processes that are not dumpable cannot be + // attached to. + process_was_dumpable_ = internal_prctl(PR_GET_DUMPABLE, 0, 0, 0, 0); + if (!process_was_dumpable_) + internal_prctl(PR_SET_DUMPABLE, 1, 0, 0, 0); + } + + ~StopTheWorldScope() { + // Restore the dumpable flag. + if (!process_was_dumpable_) + internal_prctl(PR_SET_DUMPABLE, 0, 0, 0, 0); + } + + private: + int process_was_dumpable_; +}; + +// When sanitizer output is being redirected to file (i.e. by using log_path), +// the tracer should write to the parent's log instead of trying to open a new +// file. Alert the logging code to the fact that we have a tracer. +struct ScopedSetTracerPID { + explicit ScopedSetTracerPID(uptr tracer_pid) { + stoptheworld_tracer_pid = tracer_pid; + stoptheworld_tracer_ppid = internal_getpid(); + } + ~ScopedSetTracerPID() { + stoptheworld_tracer_pid = 0; + stoptheworld_tracer_ppid = 0; + } +}; + +void StopTheWorld(StopTheWorldCallback callback, void *argument) { + StopTheWorldScope in_stoptheworld; + // Prepare the arguments for TracerThread. + struct TracerThreadArgument tracer_thread_argument; + tracer_thread_argument.callback = callback; + tracer_thread_argument.callback_argument = argument; + tracer_thread_argument.parent_pid = internal_getpid(); + atomic_store(&tracer_thread_argument.done, 0, memory_order_relaxed); + const uptr kTracerStackSize = 2 * 1024 * 1024; + ScopedStackSpaceWithGuard tracer_stack(kTracerStackSize); + // Block the execution of TracerThread until after we have set ptrace + // permissions. + tracer_thread_argument.mutex.Lock(); + // Signal handling story. + // We don't want async signals to be delivered to the tracer thread, + // so we block all async signals before creating the thread. An async signal + // handler can temporary modify errno, which is shared with this thread. + // We ought to use pthread_sigmask here, because sigprocmask has undefined + // behavior in multithreaded programs. However, on linux sigprocmask is + // equivalent to pthread_sigmask with the exception that pthread_sigmask + // does not allow to block some signals used internally in pthread + // implementation. We are fine with blocking them here, we are really not + // going to pthread_cancel the thread. + // The tracer thread should not raise any synchronous signals. But in case it + // does, we setup a special handler for sync signals that properly kills the + // parent as well. Note: we don't pass CLONE_SIGHAND to clone, so handlers + // in the tracer thread won't interfere with user program. Double note: if a + // user does something along the lines of 'kill -11 pid', that can kill the + // process even if user setup own handler for SEGV. + // Thing to watch out for: this code should not change behavior of user code + // in any observable way. In particular it should not override user signal + // handlers. + internal_sigfillset(&blocked_sigset); + for (uptr i = 0; i < ARRAY_SIZE(kSyncSignals); i++) + internal_sigdelset(&blocked_sigset, kSyncSignals[i]); + int rv = internal_sigprocmask(SIG_BLOCK, &blocked_sigset, &old_sigset); + CHECK_EQ(rv, 0); + uptr tracer_pid = internal_clone( + TracerThread, tracer_stack.Bottom(), + CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_UNTRACED, + &tracer_thread_argument, nullptr /* parent_tidptr */, + nullptr /* newtls */, nullptr /* child_tidptr */); + internal_sigprocmask(SIG_SETMASK, &old_sigset, 0); + int local_errno = 0; + if (internal_iserror(tracer_pid, &local_errno)) { + VReport(1, "Failed spawning a tracer thread (errno %d).\n", local_errno); + tracer_thread_argument.mutex.Unlock(); + } else { + ScopedSetTracerPID scoped_set_tracer_pid(tracer_pid); + // On some systems we have to explicitly declare that we want to be traced + // by the tracer thread. + internal_prctl(PR_SET_PTRACER, tracer_pid, 0, 0, 0); + // Allow the tracer thread to start. + tracer_thread_argument.mutex.Unlock(); + // NOTE: errno is shared between this thread and the tracer thread. + // internal_waitpid() may call syscall() which can access/spoil errno, + // so we can't call it now. Instead we for the tracer thread to finish using + // the spin loop below. Man page for sched_yield() says "In the Linux + // implementation, sched_yield() always succeeds", so let's hope it does not + // spoil errno. Note that this spin loop runs only for brief periods before + // the tracer thread has suspended us and when it starts unblocking threads. + while (atomic_load(&tracer_thread_argument.done, memory_order_relaxed) == 0) + sched_yield(); + // Now the tracer thread is about to exit and does not touch errno, + // wait for it. + for (;;) { + uptr waitpid_status = internal_waitpid(tracer_pid, nullptr, __WALL); + if (!internal_iserror(waitpid_status, &local_errno)) + break; + if (local_errno == EINTR) + continue; + VReport(1, "Waiting on the tracer thread failed (errno %d).\n", + local_errno); + break; + } + } +} + +// Platform-specific methods from SuspendedThreadsList. +#if SANITIZER_ANDROID && defined(__arm__) +typedef pt_regs regs_struct; +#define REG_SP ARM_sp + +#elif SANITIZER_LINUX && defined(__arm__) +typedef user_regs regs_struct; +#define REG_SP uregs[13] + +#elif defined(__i386__) || defined(__x86_64__) +typedef user_regs_struct regs_struct; +#if defined(__i386__) +#define REG_SP esp +#else +#define REG_SP rsp +#endif +#define ARCH_IOVEC_FOR_GETREGSET +// Support ptrace extensions even when compiled without required kernel support +#ifndef NT_X86_XSTATE +#define NT_X86_XSTATE 0x202 +#endif +#ifndef PTRACE_GETREGSET +#define PTRACE_GETREGSET 0x4204 +#endif +// Compiler may use FP registers to store pointers. +static constexpr uptr kExtraRegs[] = {NT_X86_XSTATE, NT_FPREGSET}; + +#elif defined(__powerpc__) || defined(__powerpc64__) +typedef pt_regs regs_struct; +#define REG_SP gpr[PT_R1] + +#elif defined(__mips__) +typedef struct user regs_struct; +# if SANITIZER_ANDROID +# define REG_SP regs[EF_R29] +# else +# define REG_SP regs[EF_REG29] +# endif + +#elif defined(__aarch64__) +typedef struct user_pt_regs regs_struct; +#define REG_SP sp +static constexpr uptr kExtraRegs[] = {0}; +#define ARCH_IOVEC_FOR_GETREGSET + +#elif SANITIZER_RISCV64 +typedef struct user_regs_struct regs_struct; +// sys/ucontext.h already defines REG_SP as 2. Undefine it first. +#undef REG_SP +#define REG_SP sp +static constexpr uptr kExtraRegs[] = {0}; +#define ARCH_IOVEC_FOR_GETREGSET + +#elif defined(__s390__) +typedef _user_regs_struct regs_struct; +#define REG_SP gprs[15] +static constexpr uptr kExtraRegs[] = {0}; +#define ARCH_IOVEC_FOR_GETREGSET + +#else +#error "Unsupported architecture" +#endif // SANITIZER_ANDROID && defined(__arm__) + +tid_t SuspendedThreadsListLinux::GetThreadID(uptr index) const { + CHECK_LT(index, thread_ids_.size()); + return thread_ids_[index]; +} + +uptr SuspendedThreadsListLinux::ThreadCount() const { + return thread_ids_.size(); +} + +bool SuspendedThreadsListLinux::ContainsTid(tid_t thread_id) const { + for (uptr i = 0; i < thread_ids_.size(); i++) { + if (thread_ids_[i] == thread_id) return true; + } + return false; +} + +void SuspendedThreadsListLinux::Append(tid_t tid) { + thread_ids_.push_back(tid); +} + +PtraceRegistersStatus SuspendedThreadsListLinux::GetRegistersAndSP( + uptr index, InternalMmapVector<uptr> *buffer, uptr *sp) const { + pid_t tid = GetThreadID(index); + constexpr uptr uptr_sz = sizeof(uptr); + int pterrno; +#ifdef ARCH_IOVEC_FOR_GETREGSET + auto append = [&](uptr regset) { + uptr size = buffer->size(); + // NT_X86_XSTATE requires 64bit alignment. + uptr size_up = RoundUpTo(size, 8 / uptr_sz); + buffer->reserve(Max<uptr>(1024, size_up)); + struct iovec regset_io; + for (;; buffer->resize(buffer->capacity() * 2)) { + buffer->resize(buffer->capacity()); + uptr available_bytes = (buffer->size() - size_up) * uptr_sz; + regset_io.iov_base = buffer->data() + size_up; + regset_io.iov_len = available_bytes; + bool fail = + internal_iserror(internal_ptrace(PTRACE_GETREGSET, tid, + (void *)regset, (void *)®set_io), + &pterrno); + if (fail) { + VReport(1, "Could not get regset %p from thread %d (errno %d).\n", + (void *)regset, tid, pterrno); + buffer->resize(size); + return false; + } + + // Far enough from the buffer size, no need to resize and repeat. + if (regset_io.iov_len + 64 < available_bytes) + break; + } + buffer->resize(size_up + RoundUpTo(regset_io.iov_len, uptr_sz) / uptr_sz); + return true; + }; + + buffer->clear(); + bool fail = !append(NT_PRSTATUS); + if (!fail) { + // Accept the first available and do not report errors. + for (uptr regs : kExtraRegs) + if (regs && append(regs)) + break; + } +#else + buffer->resize(RoundUpTo(sizeof(regs_struct), uptr_sz) / uptr_sz); + bool fail = internal_iserror( + internal_ptrace(PTRACE_GETREGS, tid, nullptr, buffer->data()), &pterrno); + if (fail) + VReport(1, "Could not get registers from thread %d (errno %d).\n", tid, + pterrno); +#endif + if (fail) { + // ESRCH means that the given thread is not suspended or already dead. + // Therefore it's unsafe to inspect its data (e.g. walk through stack) and + // we should notify caller about this. + return pterrno == ESRCH ? REGISTERS_UNAVAILABLE_FATAL + : REGISTERS_UNAVAILABLE; + } + + *sp = reinterpret_cast<regs_struct *>(buffer->data())[0].REG_SP; + return REGISTERS_AVAILABLE; +} + +} // namespace __sanitizer + +#endif // SANITIZER_LINUX && (defined(__x86_64__) || defined(__mips__) + // || defined(__aarch64__) || defined(__powerpc64__) + // || defined(__s390__) || defined(__i386__) || defined(__arm__) diff --git a/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_stoptheworld_mac.cpp b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_stoptheworld_mac.cpp new file mode 100644 index 0000000000..5ec30803b7 --- /dev/null +++ b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_stoptheworld_mac.cpp @@ -0,0 +1,180 @@ +//===-- sanitizer_stoptheworld_mac.cpp ------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// See sanitizer_stoptheworld.h for details. +// +//===----------------------------------------------------------------------===// + +#include "sanitizer_platform.h" + +#if SANITIZER_MAC && (defined(__x86_64__) || defined(__aarch64__) || \ + defined(__i386)) + +#include <mach/mach.h> +#include <mach/thread_info.h> +#include <pthread.h> + +#include "sanitizer_stoptheworld.h" + +namespace __sanitizer { +typedef struct { + tid_t tid; + thread_t thread; +} SuspendedThreadInfo; + +class SuspendedThreadsListMac final : public SuspendedThreadsList { + public: + SuspendedThreadsListMac() : threads_(1024) {} + + tid_t GetThreadID(uptr index) const override; + thread_t GetThread(uptr index) const; + uptr ThreadCount() const override; + bool ContainsThread(thread_t thread) const; + void Append(thread_t thread); + + PtraceRegistersStatus GetRegistersAndSP(uptr index, + InternalMmapVector<uptr> *buffer, + uptr *sp) const override; + + private: + InternalMmapVector<SuspendedThreadInfo> threads_; +}; + +struct RunThreadArgs { + StopTheWorldCallback callback; + void *argument; +}; + +void *RunThread(void *arg) { + struct RunThreadArgs *run_args = (struct RunThreadArgs *)arg; + SuspendedThreadsListMac suspended_threads_list; + + thread_array_t threads; + mach_msg_type_number_t num_threads; + kern_return_t err = task_threads(mach_task_self(), &threads, &num_threads); + if (err != KERN_SUCCESS) { + VReport(1, "Failed to get threads for task (errno %d).\n", err); + return nullptr; + } + + thread_t thread_self = mach_thread_self(); + for (unsigned int i = 0; i < num_threads; ++i) { + if (threads[i] == thread_self) continue; + + thread_suspend(threads[i]); + suspended_threads_list.Append(threads[i]); + } + + run_args->callback(suspended_threads_list, run_args->argument); + + uptr num_suspended = suspended_threads_list.ThreadCount(); + for (unsigned int i = 0; i < num_suspended; ++i) { + thread_resume(suspended_threads_list.GetThread(i)); + } + return nullptr; +} + +void StopTheWorld(StopTheWorldCallback callback, void *argument) { + struct RunThreadArgs arg = {callback, argument}; + pthread_t run_thread = (pthread_t)internal_start_thread(RunThread, &arg); + internal_join_thread(run_thread); +} + +#if defined(__x86_64__) +typedef x86_thread_state64_t regs_struct; + +#define SP_REG __rsp + +#elif defined(__aarch64__) +typedef arm_thread_state64_t regs_struct; + +# if __DARWIN_UNIX03 +# define SP_REG __sp +# else +# define SP_REG sp +# endif + +#elif defined(__i386) +typedef x86_thread_state32_t regs_struct; + +#define SP_REG __esp + +#else +#error "Unsupported architecture" +#endif + +tid_t SuspendedThreadsListMac::GetThreadID(uptr index) const { + CHECK_LT(index, threads_.size()); + return threads_[index].tid; +} + +thread_t SuspendedThreadsListMac::GetThread(uptr index) const { + CHECK_LT(index, threads_.size()); + return threads_[index].thread; +} + +uptr SuspendedThreadsListMac::ThreadCount() const { + return threads_.size(); +} + +bool SuspendedThreadsListMac::ContainsThread(thread_t thread) const { + for (uptr i = 0; i < threads_.size(); i++) { + if (threads_[i].thread == thread) return true; + } + return false; +} + +void SuspendedThreadsListMac::Append(thread_t thread) { + thread_identifier_info_data_t info; + mach_msg_type_number_t info_count = THREAD_IDENTIFIER_INFO_COUNT; + kern_return_t err = thread_info(thread, THREAD_IDENTIFIER_INFO, + (thread_info_t)&info, &info_count); + if (err != KERN_SUCCESS) { + VReport(1, "Error - unable to get thread ident for a thread\n"); + return; + } + threads_.push_back({info.thread_id, thread}); +} + +PtraceRegistersStatus SuspendedThreadsListMac::GetRegistersAndSP( + uptr index, InternalMmapVector<uptr> *buffer, uptr *sp) const { + thread_t thread = GetThread(index); + regs_struct regs; + int err; + mach_msg_type_number_t reg_count = MACHINE_THREAD_STATE_COUNT; + err = thread_get_state(thread, MACHINE_THREAD_STATE, (thread_state_t)®s, + ®_count); + if (err != KERN_SUCCESS) { + VReport(1, "Error - unable to get registers for a thread\n"); + // KERN_INVALID_ARGUMENT indicates that either the flavor is invalid, + // or the thread does not exist. The other possible error case, + // MIG_ARRAY_TOO_LARGE, means that the state is too large, but it's + // still safe to proceed. + return err == KERN_INVALID_ARGUMENT ? REGISTERS_UNAVAILABLE_FATAL + : REGISTERS_UNAVAILABLE; + } + + buffer->resize(RoundUpTo(sizeof(regs), sizeof(uptr)) / sizeof(uptr)); + internal_memcpy(buffer->data(), ®s, sizeof(regs)); +#if defined(__aarch64__) && defined(arm_thread_state64_get_sp) + *sp = arm_thread_state64_get_sp(regs); +#else + *sp = regs.SP_REG; +#endif + + // On x86_64 and aarch64, we must account for the stack redzone, which is 128 + // bytes. + if (SANITIZER_WORDSIZE == 64) *sp -= 128; + + return REGISTERS_AVAILABLE; +} + +} // namespace __sanitizer + +#endif // SANITIZER_MAC && (defined(__x86_64__) || defined(__aarch64__)) || + // defined(__i386)) diff --git a/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_stoptheworld_netbsd_libcdep.cpp b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_stoptheworld_netbsd_libcdep.cpp new file mode 100644 index 0000000000..7710217479 --- /dev/null +++ b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_stoptheworld_netbsd_libcdep.cpp @@ -0,0 +1,362 @@ +//===-- sanitizer_stoptheworld_netbsd_libcdep.cpp -------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// See sanitizer_stoptheworld.h for details. +// This implementation was inspired by Markus Gutschke's linuxthreads.cc. +// +// This is a NetBSD variation of Linux stoptheworld implementation +// See sanitizer_stoptheworld_linux_libcdep.cpp for code comments. +// +//===----------------------------------------------------------------------===// + +#include "sanitizer_platform.h" + +#if SANITIZER_NETBSD + +#include "sanitizer_stoptheworld.h" + +#include "sanitizer_atomic.h" +#include "sanitizer_platform_limits_posix.h" + +#include <sys/types.h> + +#include <sys/ptrace.h> +#include <sys/uio.h> +#include <sys/wait.h> + +#error #include <machine/reg.h> + +#include <elf.h> +#include <errno.h> +#include <sched.h> +#include <signal.h> +#include <stddef.h> + +#define internal_sigaction_norestorer internal_sigaction + +#include "sanitizer_common.h" +#include "sanitizer_flags.h" +#include "sanitizer_libc.h" +#include "sanitizer_linux.h" +#include "sanitizer_mutex.h" +#include "sanitizer_placement_new.h" + +namespace __sanitizer { + +class SuspendedThreadsListNetBSD final : public SuspendedThreadsList { + public: + SuspendedThreadsListNetBSD() { thread_ids_.reserve(1024); } + + tid_t GetThreadID(uptr index) const; + uptr ThreadCount() const; + bool ContainsTid(tid_t thread_id) const; + void Append(tid_t tid); + + PtraceRegistersStatus GetRegistersAndSP(uptr index, + InternalMmapVector<uptr> *buffer, + uptr *sp) const; + + private: + InternalMmapVector<tid_t> thread_ids_; +}; + +struct TracerThreadArgument { + StopTheWorldCallback callback; + void *callback_argument; + Mutex mutex; + atomic_uintptr_t done; + uptr parent_pid; +}; + +class ThreadSuspender { + public: + explicit ThreadSuspender(pid_t pid, TracerThreadArgument *arg) + : arg(arg), pid_(pid) { + CHECK_GE(pid, 0); + } + bool SuspendAllThreads(); + void ResumeAllThreads(); + void KillAllThreads(); + SuspendedThreadsListNetBSD &suspended_threads_list() { + return suspended_threads_list_; + } + TracerThreadArgument *arg; + + private: + SuspendedThreadsListNetBSD suspended_threads_list_; + pid_t pid_; +}; + +void ThreadSuspender::ResumeAllThreads() { + int pterrno; + if (!internal_iserror(internal_ptrace(PT_DETACH, pid_, (void *)(uptr)1, 0), + &pterrno)) { + VReport(2, "Detached from process %d.\n", pid_); + } else { + VReport(1, "Could not detach from process %d (errno %d).\n", pid_, pterrno); + } +} + +void ThreadSuspender::KillAllThreads() { + internal_ptrace(PT_KILL, pid_, nullptr, 0); +} + +bool ThreadSuspender::SuspendAllThreads() { + int pterrno; + if (internal_iserror(internal_ptrace(PT_ATTACH, pid_, nullptr, 0), + &pterrno)) { + Printf("Could not attach to process %d (errno %d).\n", pid_, pterrno); + return false; + } + + int status; + uptr waitpid_status; + HANDLE_EINTR(waitpid_status, internal_waitpid(pid_, &status, 0)); + + VReport(2, "Attached to process %d.\n", pid_); + +#ifdef PT_LWPNEXT + struct ptrace_lwpstatus pl; + int op = PT_LWPNEXT; +#else + struct ptrace_lwpinfo pl; + int op = PT_LWPINFO; +#endif + + pl.pl_lwpid = 0; + + int val; + while ((val = internal_ptrace(op, pid_, (void *)&pl, sizeof(pl))) != -1 && + pl.pl_lwpid != 0) { + suspended_threads_list_.Append(pl.pl_lwpid); + VReport(2, "Appended thread %d in process %d.\n", pl.pl_lwpid, pid_); + } + return true; +} + +// Pointer to the ThreadSuspender instance for use in signal handler. +static ThreadSuspender *thread_suspender_instance = nullptr; + +// Synchronous signals that should not be blocked. +static const int kSyncSignals[] = {SIGABRT, SIGILL, SIGFPE, SIGSEGV, + SIGBUS, SIGXCPU, SIGXFSZ}; + +static void TracerThreadDieCallback() { + ThreadSuspender *inst = thread_suspender_instance; + if (inst && stoptheworld_tracer_pid == internal_getpid()) { + inst->KillAllThreads(); + thread_suspender_instance = nullptr; + } +} + +// Signal handler to wake up suspended threads when the tracer thread dies. +static void TracerThreadSignalHandler(int signum, __sanitizer_siginfo *siginfo, + void *uctx) { + SignalContext ctx(siginfo, uctx); + Printf("Tracer caught signal %d: addr=0x%zx pc=0x%zx sp=0x%zx\n", signum, + ctx.addr, ctx.pc, ctx.sp); + ThreadSuspender *inst = thread_suspender_instance; + if (inst) { + if (signum == SIGABRT) + inst->KillAllThreads(); + else + inst->ResumeAllThreads(); + RAW_CHECK(RemoveDieCallback(TracerThreadDieCallback)); + thread_suspender_instance = nullptr; + atomic_store(&inst->arg->done, 1, memory_order_relaxed); + } + internal__exit((signum == SIGABRT) ? 1 : 2); +} + +// Size of alternative stack for signal handlers in the tracer thread. +static const int kHandlerStackSize = 8192; + +// This function will be run as a cloned task. +static int TracerThread(void *argument) { + TracerThreadArgument *tracer_thread_argument = + (TracerThreadArgument *)argument; + + // Check if parent is already dead. + if (internal_getppid() != tracer_thread_argument->parent_pid) + internal__exit(4); + + // Wait for the parent thread to finish preparations. + tracer_thread_argument->mutex.Lock(); + tracer_thread_argument->mutex.Unlock(); + + RAW_CHECK(AddDieCallback(TracerThreadDieCallback)); + + ThreadSuspender thread_suspender(internal_getppid(), tracer_thread_argument); + // Global pointer for the signal handler. + thread_suspender_instance = &thread_suspender; + + // Alternate stack for signal handling. + InternalMmapVector<char> handler_stack_memory(kHandlerStackSize); + stack_t handler_stack; + internal_memset(&handler_stack, 0, sizeof(handler_stack)); + handler_stack.ss_sp = handler_stack_memory.data(); + handler_stack.ss_size = kHandlerStackSize; + internal_sigaltstack(&handler_stack, nullptr); + + // Install our handler for synchronous signals. Other signals should be + // blocked by the mask we inherited from the parent thread. + for (uptr i = 0; i < ARRAY_SIZE(kSyncSignals); i++) { + __sanitizer_sigaction act; + internal_memset(&act, 0, sizeof(act)); + act.sigaction = TracerThreadSignalHandler; + act.sa_flags = SA_ONSTACK | SA_SIGINFO; + internal_sigaction_norestorer(kSyncSignals[i], &act, 0); + } + + int exit_code = 0; + if (!thread_suspender.SuspendAllThreads()) { + VReport(1, "Failed suspending threads.\n"); + exit_code = 3; + } else { + tracer_thread_argument->callback(thread_suspender.suspended_threads_list(), + tracer_thread_argument->callback_argument); + thread_suspender.ResumeAllThreads(); + exit_code = 0; + } + RAW_CHECK(RemoveDieCallback(TracerThreadDieCallback)); + thread_suspender_instance = nullptr; + atomic_store(&tracer_thread_argument->done, 1, memory_order_relaxed); + return exit_code; +} + +class ScopedStackSpaceWithGuard { + public: + explicit ScopedStackSpaceWithGuard(uptr stack_size) { + stack_size_ = stack_size; + guard_size_ = GetPageSizeCached(); + // FIXME: Omitting MAP_STACK here works in current kernels but might break + // in the future. + guard_start_ = + (uptr)MmapOrDie(stack_size_ + guard_size_, "ScopedStackWithGuard"); + CHECK(MprotectNoAccess((uptr)guard_start_, guard_size_)); + } + ~ScopedStackSpaceWithGuard() { + UnmapOrDie((void *)guard_start_, stack_size_ + guard_size_); + } + void *Bottom() const { + return (void *)(guard_start_ + stack_size_ + guard_size_); + } + + private: + uptr stack_size_; + uptr guard_size_; + uptr guard_start_; +}; + +static __sanitizer_sigset_t blocked_sigset; +static __sanitizer_sigset_t old_sigset; + +struct ScopedSetTracerPID { + explicit ScopedSetTracerPID(uptr tracer_pid) { + stoptheworld_tracer_pid = tracer_pid; + stoptheworld_tracer_ppid = internal_getpid(); + } + ~ScopedSetTracerPID() { + stoptheworld_tracer_pid = 0; + stoptheworld_tracer_ppid = 0; + } +}; + +void StopTheWorld(StopTheWorldCallback callback, void *argument) { + // Prepare the arguments for TracerThread. + struct TracerThreadArgument tracer_thread_argument; + tracer_thread_argument.callback = callback; + tracer_thread_argument.callback_argument = argument; + tracer_thread_argument.parent_pid = internal_getpid(); + atomic_store(&tracer_thread_argument.done, 0, memory_order_relaxed); + const uptr kTracerStackSize = 2 * 1024 * 1024; + ScopedStackSpaceWithGuard tracer_stack(kTracerStackSize); + + tracer_thread_argument.mutex.Lock(); + + internal_sigfillset(&blocked_sigset); + for (uptr i = 0; i < ARRAY_SIZE(kSyncSignals); i++) + internal_sigdelset(&blocked_sigset, kSyncSignals[i]); + int rv = internal_sigprocmask(SIG_BLOCK, &blocked_sigset, &old_sigset); + CHECK_EQ(rv, 0); + uptr tracer_pid = internal_clone(TracerThread, tracer_stack.Bottom(), + CLONE_VM | CLONE_FS | CLONE_FILES, + &tracer_thread_argument); + internal_sigprocmask(SIG_SETMASK, &old_sigset, 0); + int local_errno = 0; + if (internal_iserror(tracer_pid, &local_errno)) { + VReport(1, "Failed spawning a tracer thread (errno %d).\n", local_errno); + tracer_thread_argument.mutex.Unlock(); + } else { + ScopedSetTracerPID scoped_set_tracer_pid(tracer_pid); + + tracer_thread_argument.mutex.Unlock(); + + while (atomic_load(&tracer_thread_argument.done, memory_order_relaxed) == 0) + sched_yield(); + + for (;;) { + uptr waitpid_status = internal_waitpid(tracer_pid, nullptr, __WALL); + if (!internal_iserror(waitpid_status, &local_errno)) + break; + if (local_errno == EINTR) + continue; + VReport(1, "Waiting on the tracer thread failed (errno %d).\n", + local_errno); + break; + } + } +} + +tid_t SuspendedThreadsListNetBSD::GetThreadID(uptr index) const { + CHECK_LT(index, thread_ids_.size()); + return thread_ids_[index]; +} + +uptr SuspendedThreadsListNetBSD::ThreadCount() const { + return thread_ids_.size(); +} + +bool SuspendedThreadsListNetBSD::ContainsTid(tid_t thread_id) const { + for (uptr i = 0; i < thread_ids_.size(); i++) { + if (thread_ids_[i] == thread_id) + return true; + } + return false; +} + +void SuspendedThreadsListNetBSD::Append(tid_t tid) { + thread_ids_.push_back(tid); +} + +PtraceRegistersStatus SuspendedThreadsListNetBSD::GetRegistersAndSP( + uptr index, InternalMmapVector<uptr> *buffer, uptr *sp) const { + lwpid_t tid = GetThreadID(index); + pid_t ppid = internal_getppid(); + struct reg regs; + int pterrno; + bool isErr = + internal_iserror(internal_ptrace(PT_GETREGS, ppid, ®s, tid), &pterrno); + if (isErr) { + VReport(1, + "Could not get registers from process %d thread %d (errno %d).\n", + ppid, tid, pterrno); + return pterrno == ESRCH ? REGISTERS_UNAVAILABLE_FATAL + : REGISTERS_UNAVAILABLE; + } + + *sp = PTRACE_REG_SP(®s); + buffer->resize(RoundUpTo(sizeof(regs), sizeof(uptr)) / sizeof(uptr)); + internal_memcpy(buffer->data(), ®s, sizeof(regs)); + + return REGISTERS_AVAILABLE; +} + +} // namespace __sanitizer + +#endif diff --git a/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_stoptheworld_win.cpp b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_stoptheworld_win.cpp new file mode 100644 index 0000000000..f114acea79 --- /dev/null +++ b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_stoptheworld_win.cpp @@ -0,0 +1,175 @@ +//===-- sanitizer_stoptheworld_win.cpp ------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// See sanitizer_stoptheworld.h for details. +// +//===----------------------------------------------------------------------===// + +#include "sanitizer_platform.h" + +#if SANITIZER_WINDOWS + +# define WIN32_LEAN_AND_MEAN +# include <windows.h> +// windows.h needs to be included before tlhelp32.h +# include <tlhelp32.h> + +# include "sanitizer_stoptheworld.h" + +namespace __sanitizer { + +namespace { + +struct SuspendedThreadsListWindows final : public SuspendedThreadsList { + InternalMmapVector<HANDLE> threadHandles; + InternalMmapVector<DWORD> threadIds; + + SuspendedThreadsListWindows() { + threadIds.reserve(1024); + threadHandles.reserve(1024); + } + + PtraceRegistersStatus GetRegistersAndSP(uptr index, + InternalMmapVector<uptr> *buffer, + uptr *sp) const override; + + tid_t GetThreadID(uptr index) const override; + uptr ThreadCount() const override; +}; + +// Stack Pointer register names on different architectures +# if SANITIZER_X64 +# define SP_REG Rsp +# elif SANITIZER_I386 +# define SP_REG Esp +# elif SANITIZER_ARM | SANITIZER_ARM64 +# define SP_REG Sp +# else +# error Architecture not supported! +# endif + +PtraceRegistersStatus SuspendedThreadsListWindows::GetRegistersAndSP( + uptr index, InternalMmapVector<uptr> *buffer, uptr *sp) const { + CHECK_LT(index, threadHandles.size()); + + buffer->resize(RoundUpTo(sizeof(CONTEXT), sizeof(uptr)) / sizeof(uptr)); + CONTEXT *thread_context = reinterpret_cast<CONTEXT *>(buffer->data()); + thread_context->ContextFlags = CONTEXT_ALL; + CHECK(GetThreadContext(threadHandles[index], thread_context)); + *sp = thread_context->SP_REG; + + return REGISTERS_AVAILABLE; +} + +tid_t SuspendedThreadsListWindows::GetThreadID(uptr index) const { + CHECK_LT(index, threadIds.size()); + return threadIds[index]; +} + +uptr SuspendedThreadsListWindows::ThreadCount() const { + return threadIds.size(); +} + +struct RunThreadArgs { + StopTheWorldCallback callback; + void *argument; +}; + +DWORD WINAPI RunThread(void *argument) { + RunThreadArgs *run_args = (RunThreadArgs *)argument; + + const DWORD this_thread = GetCurrentThreadId(); + const DWORD this_process = GetCurrentProcessId(); + + SuspendedThreadsListWindows suspended_threads_list; + bool new_thread_found; + + do { + // Take a snapshot of all Threads + const HANDLE threads = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0); + CHECK(threads != INVALID_HANDLE_VALUE); + + THREADENTRY32 thread_entry; + thread_entry.dwSize = sizeof(thread_entry); + new_thread_found = false; + + if (!Thread32First(threads, &thread_entry)) + break; + + do { + if (thread_entry.th32ThreadID == this_thread || + thread_entry.th32OwnerProcessID != this_process) + continue; + + bool suspended_thread = false; + for (const auto thread_id : suspended_threads_list.threadIds) { + if (thread_id == thread_entry.th32ThreadID) { + suspended_thread = true; + break; + } + } + + // Skip the Thread if it was already suspended + if (suspended_thread) + continue; + + const HANDLE thread = + OpenThread(THREAD_ALL_ACCESS, FALSE, thread_entry.th32ThreadID); + CHECK(thread); + + if (SuspendThread(thread) == (DWORD)-1) { + DWORD last_error = GetLastError(); + + VPrintf(1, "Could not suspend thread %lu (error %lu)", + thread_entry.th32ThreadID, last_error); + continue; + } + + suspended_threads_list.threadIds.push_back(thread_entry.th32ThreadID); + suspended_threads_list.threadHandles.push_back(thread); + new_thread_found = true; + } while (Thread32Next(threads, &thread_entry)); + + CloseHandle(threads); + + // Between the call to `CreateToolhelp32Snapshot` and suspending the + // relevant Threads, new Threads could have potentially been created. So + // continue to find and suspend new Threads until we don't find any. + } while (new_thread_found); + + // Now all Threads of this Process except of this Thread should be suspended. + // Execute the callback function. + run_args->callback(suspended_threads_list, run_args->argument); + + // Resume all Threads + for (const auto suspended_thread_handle : + suspended_threads_list.threadHandles) { + CHECK_NE(ResumeThread(suspended_thread_handle), -1); + CloseHandle(suspended_thread_handle); + } + + return 0; +} + +} // namespace + +void StopTheWorld(StopTheWorldCallback callback, void *argument) { + struct RunThreadArgs arg = {callback, argument}; + DWORD trace_thread_id; + + auto trace_thread = + CreateThread(nullptr, 0, RunThread, &arg, 0, &trace_thread_id); + CHECK(trace_thread); + + WaitForSingleObject(trace_thread, INFINITE); + CloseHandle(trace_thread); +} + +} // namespace __sanitizer + +#endif // SANITIZER_WINDOWS diff --git a/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_suppressions.cpp b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_suppressions.cpp new file mode 100644 index 0000000000..a674034b8e --- /dev/null +++ b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_suppressions.cpp @@ -0,0 +1,181 @@ +//===-- sanitizer_suppressions.cpp ----------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// Suppression parsing/matching code. +// +//===----------------------------------------------------------------------===// + +#include "sanitizer_suppressions.h" + +#include "sanitizer_allocator_internal.h" +#include "sanitizer_common.h" +#include "sanitizer_flags.h" +#include "sanitizer_file.h" +#include "sanitizer_libc.h" +#include "sanitizer_placement_new.h" + +namespace __sanitizer { + +SuppressionContext::SuppressionContext(const char *suppression_types[], + int suppression_types_num) + : suppression_types_(suppression_types), + suppression_types_num_(suppression_types_num), + can_parse_(true) { + CHECK_LE(suppression_types_num_, kMaxSuppressionTypes); + internal_memset(has_suppression_type_, 0, suppression_types_num_); +} + +#if !SANITIZER_FUCHSIA +static bool GetPathAssumingFileIsRelativeToExec(const char *file_path, + /*out*/char *new_file_path, + uptr new_file_path_size) { + InternalMmapVector<char> exec(kMaxPathLength); + if (ReadBinaryNameCached(exec.data(), exec.size())) { + const char *file_name_pos = StripModuleName(exec.data()); + uptr path_to_exec_len = file_name_pos - exec.data(); + internal_strncat(new_file_path, exec.data(), + Min(path_to_exec_len, new_file_path_size - 1)); + internal_strncat(new_file_path, file_path, + new_file_path_size - internal_strlen(new_file_path) - 1); + return true; + } + return false; +} + +static const char *FindFile(const char *file_path, + /*out*/char *new_file_path, + uptr new_file_path_size) { + // If we cannot find the file, check if its location is relative to + // the location of the executable. + if (!FileExists(file_path) && !IsAbsolutePath(file_path) && + GetPathAssumingFileIsRelativeToExec(file_path, new_file_path, + new_file_path_size)) { + return new_file_path; + } + return file_path; +} +#else +static const char *FindFile(const char *file_path, char *, uptr) { + return file_path; +} +#endif + +void SuppressionContext::ParseFromFile(const char *filename) { + if (filename[0] == '\0') + return; + + InternalMmapVector<char> new_file_path(kMaxPathLength); + filename = FindFile(filename, new_file_path.data(), new_file_path.size()); + + // Read the file. + VPrintf(1, "%s: reading suppressions file at %s\n", + SanitizerToolName, filename); + char *file_contents; + uptr buffer_size; + uptr contents_size; + if (!ReadFileToBuffer(filename, &file_contents, &buffer_size, + &contents_size)) { + Printf("%s: failed to read suppressions file '%s'\n", SanitizerToolName, + filename); + Die(); + } + + Parse(file_contents); +} + +bool SuppressionContext::Match(const char *str, const char *type, + Suppression **s) { + can_parse_ = false; + if (!HasSuppressionType(type)) + return false; + for (uptr i = 0; i < suppressions_.size(); i++) { + Suppression &cur = suppressions_[i]; + if (0 == internal_strcmp(cur.type, type) && TemplateMatch(cur.templ, str)) { + *s = &cur; + return true; + } + } + return false; +} + +static const char *StripPrefix(const char *str, const char *prefix) { + while (*str && *str == *prefix) { + str++; + prefix++; + } + if (!*prefix) + return str; + return 0; +} + +void SuppressionContext::Parse(const char *str) { + // Context must not mutate once Match has been called. + CHECK(can_parse_); + const char *line = str; + while (line) { + while (line[0] == ' ' || line[0] == '\t') + line++; + const char *end = internal_strchr(line, '\n'); + if (end == 0) + end = line + internal_strlen(line); + if (line != end && line[0] != '#') { + const char *end2 = end; + while (line != end2 && + (end2[-1] == ' ' || end2[-1] == '\t' || end2[-1] == '\r')) + end2--; + int type; + for (type = 0; type < suppression_types_num_; type++) { + const char *next_char = StripPrefix(line, suppression_types_[type]); + if (next_char && *next_char == ':') { + line = ++next_char; + break; + } + } + if (type == suppression_types_num_) { + Printf("%s: failed to parse suppressions\n", SanitizerToolName); + Die(); + } + Suppression s; + s.type = suppression_types_[type]; + s.templ = (char*)InternalAlloc(end2 - line + 1); + internal_memcpy(s.templ, line, end2 - line); + s.templ[end2 - line] = 0; + suppressions_.push_back(s); + has_suppression_type_[type] = true; + } + if (end[0] == 0) + break; + line = end + 1; + } +} + +uptr SuppressionContext::SuppressionCount() const { + return suppressions_.size(); +} + +bool SuppressionContext::HasSuppressionType(const char *type) const { + for (int i = 0; i < suppression_types_num_; i++) { + if (0 == internal_strcmp(type, suppression_types_[i])) + return has_suppression_type_[i]; + } + return false; +} + +const Suppression *SuppressionContext::SuppressionAt(uptr i) const { + CHECK_LT(i, suppressions_.size()); + return &suppressions_[i]; +} + +void SuppressionContext::GetMatched( + InternalMmapVector<Suppression *> *matched) { + for (uptr i = 0; i < suppressions_.size(); i++) + if (atomic_load_relaxed(&suppressions_[i].hit_count)) + matched->push_back(&suppressions_[i]); +} + +} // namespace __sanitizer diff --git a/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_suppressions.h b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_suppressions.h new file mode 100644 index 0000000000..2d88b1f72f --- /dev/null +++ b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_suppressions.h @@ -0,0 +1,56 @@ +//===-- sanitizer_suppressions.h --------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// Suppression parsing/matching code. +// +//===----------------------------------------------------------------------===// +#ifndef SANITIZER_SUPPRESSIONS_H +#define SANITIZER_SUPPRESSIONS_H + +#include "sanitizer_common.h" +#include "sanitizer_atomic.h" +#include "sanitizer_internal_defs.h" + +namespace __sanitizer { + +struct Suppression { + Suppression() { internal_memset(this, 0, sizeof(*this)); } + const char *type; + char *templ; + atomic_uint32_t hit_count; + uptr weight; +}; + +class SuppressionContext { + public: + // Create new SuppressionContext capable of parsing given suppression types. + SuppressionContext(const char *supprression_types[], + int suppression_types_num); + + void ParseFromFile(const char *filename); + void Parse(const char *str); + + bool Match(const char *str, const char *type, Suppression **s); + uptr SuppressionCount() const; + bool HasSuppressionType(const char *type) const; + const Suppression *SuppressionAt(uptr i) const; + void GetMatched(InternalMmapVector<Suppression *> *matched); + + private: + static const int kMaxSuppressionTypes = 64; + const char **const suppression_types_; + const int suppression_types_num_; + + InternalMmapVector<Suppression> suppressions_; + bool has_suppression_type_[kMaxSuppressionTypes]; + bool can_parse_; +}; + +} // namespace __sanitizer + +#endif // SANITIZER_SUPPRESSIONS_H diff --git a/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_symbolizer.cpp b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_symbolizer.cpp new file mode 100644 index 0000000000..d3cffaa6ee --- /dev/null +++ b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_symbolizer.cpp @@ -0,0 +1,141 @@ +//===-- sanitizer_symbolizer.cpp ------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file is shared between AddressSanitizer and ThreadSanitizer +// run-time libraries. +//===----------------------------------------------------------------------===// + +#include "sanitizer_allocator_internal.h" +#include "sanitizer_common.h" +#include "sanitizer_internal_defs.h" +#include "sanitizer_libc.h" +#include "sanitizer_placement_new.h" +#include "sanitizer_platform.h" +#include "sanitizer_symbolizer_internal.h" + +namespace __sanitizer { + +AddressInfo::AddressInfo() { + internal_memset(this, 0, sizeof(AddressInfo)); + function_offset = kUnknown; +} + +void AddressInfo::Clear() { + InternalFree(module); + InternalFree(function); + InternalFree(file); + internal_memset(this, 0, sizeof(AddressInfo)); + function_offset = kUnknown; + uuid_size = 0; +} + +void AddressInfo::FillModuleInfo(const char *mod_name, uptr mod_offset, + ModuleArch mod_arch) { + module = internal_strdup(mod_name); + module_offset = mod_offset; + module_arch = mod_arch; + uuid_size = 0; +} + +void AddressInfo::FillModuleInfo(const LoadedModule &mod) { + module = internal_strdup(mod.full_name()); + module_offset = address - mod.base_address(); + module_arch = mod.arch(); + if (mod.uuid_size()) + internal_memcpy(uuid, mod.uuid(), mod.uuid_size()); + uuid_size = mod.uuid_size(); +} + +SymbolizedStack::SymbolizedStack() : next(nullptr), info() {} + +SymbolizedStack *SymbolizedStack::New(uptr addr) { + void *mem = InternalAlloc(sizeof(SymbolizedStack)); + SymbolizedStack *res = new(mem) SymbolizedStack(); + res->info.address = addr; + return res; +} + +void SymbolizedStack::ClearAll() { + info.Clear(); + if (next) + next->ClearAll(); + InternalFree(this); +} + +DataInfo::DataInfo() { + internal_memset(this, 0, sizeof(DataInfo)); +} + +void DataInfo::Clear() { + InternalFree(module); + InternalFree(file); + InternalFree(name); + internal_memset(this, 0, sizeof(DataInfo)); +} + +void FrameInfo::Clear() { + InternalFree(module); + for (LocalInfo &local : locals) { + InternalFree(local.function_name); + InternalFree(local.name); + InternalFree(local.decl_file); + } + locals.clear(); +} + +Symbolizer *Symbolizer::symbolizer_; +StaticSpinMutex Symbolizer::init_mu_; +LowLevelAllocator Symbolizer::symbolizer_allocator_; + +void Symbolizer::InvalidateModuleList() { + modules_fresh_ = false; +} + +void Symbolizer::AddHooks(Symbolizer::StartSymbolizationHook start_hook, + Symbolizer::EndSymbolizationHook end_hook) { + CHECK(start_hook_ == 0 && end_hook_ == 0); + start_hook_ = start_hook; + end_hook_ = end_hook; +} + +const char *Symbolizer::ModuleNameOwner::GetOwnedCopy(const char *str) { + mu_->CheckLocked(); + + // 'str' will be the same string multiple times in a row, optimize this case. + if (last_match_ && !internal_strcmp(last_match_, str)) + return last_match_; + + // FIXME: this is linear search. + // We should optimize this further if this turns out to be a bottleneck later. + for (uptr i = 0; i < storage_.size(); ++i) { + if (!internal_strcmp(storage_[i], str)) { + last_match_ = storage_[i]; + return last_match_; + } + } + last_match_ = internal_strdup(str); + storage_.push_back(last_match_); + return last_match_; +} + +Symbolizer::Symbolizer(IntrusiveList<SymbolizerTool> tools) + : module_names_(&mu_), modules_(), modules_fresh_(false), tools_(tools), + start_hook_(0), end_hook_(0) {} + +Symbolizer::SymbolizerScope::SymbolizerScope(const Symbolizer *sym) + : sym_(sym) { + if (sym_->start_hook_) + sym_->start_hook_(); +} + +Symbolizer::SymbolizerScope::~SymbolizerScope() { + if (sym_->end_hook_) + sym_->end_hook_(); +} + +} // namespace __sanitizer diff --git a/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_symbolizer.h b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_symbolizer.h new file mode 100644 index 0000000000..bad4761e34 --- /dev/null +++ b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_symbolizer.h @@ -0,0 +1,224 @@ +//===-- sanitizer_symbolizer.h ----------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// Symbolizer is used by sanitizers to map instruction address to a location in +// source code at run-time. Symbolizer either uses __sanitizer_symbolize_* +// defined in the program, or (if they are missing) tries to find and +// launch "llvm-symbolizer" commandline tool in a separate process and +// communicate with it. +// +// Generally we should try to avoid calling system library functions during +// symbolization (and use their replacements from sanitizer_libc.h instead). +//===----------------------------------------------------------------------===// +#ifndef SANITIZER_SYMBOLIZER_H +#define SANITIZER_SYMBOLIZER_H + +#include "sanitizer_common.h" +#include "sanitizer_mutex.h" +#include "sanitizer_vector.h" + +namespace __sanitizer { + +struct AddressInfo { + // Owns all the string members. Storage for them is + // (de)allocated using sanitizer internal allocator. + uptr address; + + char *module; + uptr module_offset; + ModuleArch module_arch; + u8 uuid[kModuleUUIDSize]; + uptr uuid_size; + + static const uptr kUnknown = ~(uptr)0; + char *function; + uptr function_offset; + + char *file; + int line; + int column; + + AddressInfo(); + // Deletes all strings and resets all fields. + void Clear(); + void FillModuleInfo(const char *mod_name, uptr mod_offset, ModuleArch arch); + void FillModuleInfo(const LoadedModule &mod); + uptr module_base() const { return address - module_offset; } +}; + +// Linked list of symbolized frames (each frame is described by AddressInfo). +struct SymbolizedStack { + SymbolizedStack *next; + AddressInfo info; + static SymbolizedStack *New(uptr addr); + // Deletes current, and all subsequent frames in the linked list. + // The object cannot be accessed after the call to this function. + void ClearAll(); + + private: + SymbolizedStack(); +}; + +// For now, DataInfo is used to describe global variable. +struct DataInfo { + // Owns all the string members. Storage for them is + // (de)allocated using sanitizer internal allocator. + char *module; + uptr module_offset; + ModuleArch module_arch; + + char *file; + uptr line; + char *name; + uptr start; + uptr size; + + DataInfo(); + void Clear(); +}; + +struct LocalInfo { + char *function_name = nullptr; + char *name = nullptr; + char *decl_file = nullptr; + unsigned decl_line = 0; + + bool has_frame_offset = false; + bool has_size = false; + bool has_tag_offset = false; + + sptr frame_offset; + uptr size; + uptr tag_offset; + + void Clear(); +}; + +struct FrameInfo { + char *module; + uptr module_offset; + ModuleArch module_arch; + + InternalMmapVector<LocalInfo> locals; + void Clear(); +}; + +class SymbolizerTool; + +class Symbolizer final { + public: + /// Initialize and return platform-specific implementation of symbolizer + /// (if it wasn't already initialized). + static Symbolizer *GetOrInit(); + static void LateInitialize(); + // Returns a list of symbolized frames for a given address (containing + // all inlined functions, if necessary). + SymbolizedStack *SymbolizePC(uptr address); + bool SymbolizeData(uptr address, DataInfo *info); + bool SymbolizeFrame(uptr address, FrameInfo *info); + + // The module names Symbolizer returns are stable and unique for every given + // module. It is safe to store and compare them as pointers. + bool GetModuleNameAndOffsetForPC(uptr pc, const char **module_name, + uptr *module_address); + const char *GetModuleNameForPc(uptr pc) { + const char *module_name = nullptr; + uptr unused; + if (GetModuleNameAndOffsetForPC(pc, &module_name, &unused)) + return module_name; + return nullptr; + } + + // Release internal caches (if any). + void Flush(); + // Attempts to demangle the provided C++ mangled name. + const char *Demangle(const char *name); + + // Allow user to install hooks that would be called before/after Symbolizer + // does the actual file/line info fetching. Specific sanitizers may need this + // to distinguish system library calls made in user code from calls made + // during in-process symbolization. + typedef void (*StartSymbolizationHook)(); + typedef void (*EndSymbolizationHook)(); + // May be called at most once. + void AddHooks(StartSymbolizationHook start_hook, + EndSymbolizationHook end_hook); + + void RefreshModules(); + const LoadedModule *FindModuleForAddress(uptr address); + + void InvalidateModuleList(); + + private: + // GetModuleNameAndOffsetForPC has to return a string to the caller. + // Since the corresponding module might get unloaded later, we should create + // our owned copies of the strings that we can safely return. + // ModuleNameOwner does not provide any synchronization, thus calls to + // its method should be protected by |mu_|. + class ModuleNameOwner { + public: + explicit ModuleNameOwner(Mutex *synchronized_by) + : last_match_(nullptr), mu_(synchronized_by) { + storage_.reserve(kInitialCapacity); + } + const char *GetOwnedCopy(const char *str); + + private: + static const uptr kInitialCapacity = 1000; + InternalMmapVector<const char*> storage_; + const char *last_match_; + + Mutex *mu_; + } module_names_; + + /// Platform-specific function for creating a Symbolizer object. + static Symbolizer *PlatformInit(); + + bool FindModuleNameAndOffsetForAddress(uptr address, const char **module_name, + uptr *module_offset, + ModuleArch *module_arch); + ListOfModules modules_; + ListOfModules fallback_modules_; + // If stale, need to reload the modules before looking up addresses. + bool modules_fresh_; + + // Platform-specific default demangler, must not return nullptr. + const char *PlatformDemangle(const char *name); + + static Symbolizer *symbolizer_; + static StaticSpinMutex init_mu_; + + // Mutex locked from public methods of |Symbolizer|, so that the internals + // (including individual symbolizer tools and platform-specific methods) are + // always synchronized. + Mutex mu_; + + IntrusiveList<SymbolizerTool> tools_; + + explicit Symbolizer(IntrusiveList<SymbolizerTool> tools); + + static LowLevelAllocator symbolizer_allocator_; + + StartSymbolizationHook start_hook_; + EndSymbolizationHook end_hook_; + class SymbolizerScope { + public: + explicit SymbolizerScope(const Symbolizer *sym); + ~SymbolizerScope(); + private: + const Symbolizer *sym_; + }; +}; + +#ifdef SANITIZER_WINDOWS +void InitializeDbgHelpIfNeeded(); +#endif + +} // namespace __sanitizer + +#endif // SANITIZER_SYMBOLIZER_H diff --git a/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_symbolizer_fuchsia.h b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_symbolizer_fuchsia.h new file mode 100644 index 0000000000..c4061e38c6 --- /dev/null +++ b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_symbolizer_fuchsia.h @@ -0,0 +1,42 @@ +//===-- sanitizer_symbolizer_fuchsia.h -----------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file is shared between various sanitizers' runtime libraries. +// +// Define Fuchsia's string formats and limits for the markup symbolizer. +//===----------------------------------------------------------------------===// +#ifndef SANITIZER_SYMBOLIZER_FUCHSIA_H +#define SANITIZER_SYMBOLIZER_FUCHSIA_H + +#include "sanitizer_internal_defs.h" + +namespace __sanitizer { + +// See the spec at: +// https://fuchsia.googlesource.com/zircon/+/master/docs/symbolizer_markup.md + +// This is used by UBSan for type names, and by ASan for global variable names. +constexpr const char *kFormatDemangle = "{{{symbol:%s}}}"; +constexpr uptr kFormatDemangleMax = 1024; // Arbitrary. + +// Function name or equivalent from PC location. +constexpr const char *kFormatFunction = "{{{pc:%p}}}"; +constexpr uptr kFormatFunctionMax = 64; // More than big enough for 64-bit hex. + +// Global variable name or equivalent from data memory address. +constexpr const char *kFormatData = "{{{data:%p}}}"; + +// One frame in a backtrace (printed on a line by itself). +constexpr const char *kFormatFrame = "{{{bt:%u:%p}}}"; + +// Dump trigger element. +#define FORMAT_DUMPFILE "{{{dumpfile:%s:%s}}}" + +} // namespace __sanitizer + +#endif // SANITIZER_SYMBOLIZER_FUCHSIA_H diff --git a/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_symbolizer_internal.h b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_symbolizer_internal.h new file mode 100644 index 0000000000..df122ed342 --- /dev/null +++ b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_symbolizer_internal.h @@ -0,0 +1,165 @@ +//===-- sanitizer_symbolizer_internal.h -------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// Header for internal classes and functions to be used by implementations of +// symbolizers. +// +//===----------------------------------------------------------------------===// +#ifndef SANITIZER_SYMBOLIZER_INTERNAL_H +#define SANITIZER_SYMBOLIZER_INTERNAL_H + +#include "sanitizer_symbolizer.h" +#include "sanitizer_file.h" +#include "sanitizer_vector.h" + +namespace __sanitizer { + +// Parsing helpers, 'str' is searched for delimiter(s) and a string or uptr +// is extracted. When extracting a string, a newly allocated (using +// InternalAlloc) and null-terminated buffer is returned. They return a pointer +// to the next characted after the found delimiter. +const char *ExtractToken(const char *str, const char *delims, char **result); +const char *ExtractInt(const char *str, const char *delims, int *result); +const char *ExtractUptr(const char *str, const char *delims, uptr *result); +const char *ExtractTokenUpToDelimiter(const char *str, const char *delimiter, + char **result); + +const char *DemangleSwiftAndCXX(const char *name); + +// SymbolizerTool is an interface that is implemented by individual "tools" +// that can perform symbolication (external llvm-symbolizer, libbacktrace, +// Windows DbgHelp symbolizer, etc.). +class SymbolizerTool { + public: + // The main |Symbolizer| class implements a "fallback chain" of symbolizer + // tools. In a request to symbolize an address, if one tool returns false, + // the next tool in the chain will be tried. + SymbolizerTool *next; + + SymbolizerTool() : next(nullptr) { } + + // Can't declare pure virtual functions in sanitizer runtimes: + // __cxa_pure_virtual might be unavailable. + + // The |stack| parameter is inout. It is pre-filled with the address, + // module base and module offset values and is to be used to construct + // other stack frames. + virtual bool SymbolizePC(uptr addr, SymbolizedStack *stack) { + UNIMPLEMENTED(); + } + + // The |info| parameter is inout. It is pre-filled with the module base + // and module offset values. + virtual bool SymbolizeData(uptr addr, DataInfo *info) { + UNIMPLEMENTED(); + } + + virtual bool SymbolizeFrame(uptr addr, FrameInfo *info) { + return false; + } + + virtual void Flush() {} + + // Return nullptr to fallback to the default platform-specific demangler. + virtual const char *Demangle(const char *name) { + return nullptr; + } + + protected: + ~SymbolizerTool() {} +}; + +// SymbolizerProcess encapsulates communication between the tool and +// external symbolizer program, running in a different subprocess. +// SymbolizerProcess may not be used from two threads simultaneously. +class SymbolizerProcess { + public: + explicit SymbolizerProcess(const char *path, bool use_posix_spawn = false); + const char *SendCommand(const char *command); + + protected: + ~SymbolizerProcess() {} + + /// The maximum number of arguments required to invoke a tool process. + static const unsigned kArgVMax = 16; + + // Customizable by subclasses. + virtual bool StartSymbolizerSubprocess(); + virtual bool ReadFromSymbolizer(char *buffer, uptr max_length); + // Return the environment to run the symbolizer in. + virtual char **GetEnvP() { return GetEnviron(); } + + private: + virtual bool ReachedEndOfOutput(const char *buffer, uptr length) const { + UNIMPLEMENTED(); + } + + /// Fill in an argv array to invoke the child process. + virtual void GetArgV(const char *path_to_binary, + const char *(&argv)[kArgVMax]) const { + UNIMPLEMENTED(); + } + + bool Restart(); + const char *SendCommandImpl(const char *command); + bool WriteToSymbolizer(const char *buffer, uptr length); + + const char *path_; + fd_t input_fd_; + fd_t output_fd_; + + static const uptr kBufferSize = 16 * 1024; + char buffer_[kBufferSize]; + + static const uptr kMaxTimesRestarted = 5; + static const int kSymbolizerStartupTimeMillis = 10; + uptr times_restarted_; + bool failed_to_start_; + bool reported_invalid_path_; + bool use_posix_spawn_; +}; + +class LLVMSymbolizerProcess; + +// This tool invokes llvm-symbolizer in a subprocess. It should be as portable +// as the llvm-symbolizer tool is. +class LLVMSymbolizer final : public SymbolizerTool { + public: + explicit LLVMSymbolizer(const char *path, LowLevelAllocator *allocator); + + bool SymbolizePC(uptr addr, SymbolizedStack *stack) override; + bool SymbolizeData(uptr addr, DataInfo *info) override; + bool SymbolizeFrame(uptr addr, FrameInfo *info) override; + + private: + const char *FormatAndSendCommand(const char *command_prefix, + const char *module_name, uptr module_offset, + ModuleArch arch); + + LLVMSymbolizerProcess *symbolizer_process_; + static const uptr kBufferSize = 16 * 1024; + char buffer_[kBufferSize]; +}; + +// Parses one or more two-line strings in the following format: +// <function_name> +// <file_name>:<line_number>[:<column_number>] +// Used by LLVMSymbolizer, Addr2LinePool and InternalSymbolizer, since all of +// them use the same output format. Returns true if any useful debug +// information was found. +void ParseSymbolizePCOutput(const char *str, SymbolizedStack *res); + +// Parses a two-line string in the following format: +// <symbol_name> +// <start_address> <size> +// Used by LLVMSymbolizer and InternalSymbolizer. +void ParseSymbolizeDataOutput(const char *str, DataInfo *info); + +} // namespace __sanitizer + +#endif // SANITIZER_SYMBOLIZER_INTERNAL_H diff --git a/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_symbolizer_libbacktrace.cpp b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_symbolizer_libbacktrace.cpp new file mode 100644 index 0000000000..c3b2799261 --- /dev/null +++ b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_symbolizer_libbacktrace.cpp @@ -0,0 +1,209 @@ +//===-- sanitizer_symbolizer_libbacktrace.cpp -----------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file is shared between AddressSanitizer and ThreadSanitizer +// run-time libraries. +// Libbacktrace implementation of symbolizer parts. +//===----------------------------------------------------------------------===// + +#include "sanitizer_platform.h" + +#include "sanitizer_internal_defs.h" +#include "sanitizer_symbolizer.h" +#include "sanitizer_symbolizer_libbacktrace.h" + +#if SANITIZER_LIBBACKTRACE +# error #include "backtrace-supported.h" +# if SANITIZER_POSIX && BACKTRACE_SUPPORTED && !BACKTRACE_USES_MALLOC +# error #include "backtrace.h" +# if SANITIZER_CP_DEMANGLE +# undef ARRAY_SIZE +# error #include "demangle.h" +# endif +# else +# define SANITIZER_LIBBACKTRACE 0 +# endif +#endif + +namespace __sanitizer { + +static char *DemangleAlloc(const char *name, bool always_alloc); + +#if SANITIZER_LIBBACKTRACE + +namespace { + +# if SANITIZER_CP_DEMANGLE +struct CplusV3DemangleData { + char *buf; + uptr size, allocated; +}; + +extern "C" { +static void CplusV3DemangleCallback(const char *s, size_t l, void *vdata) { + CplusV3DemangleData *data = (CplusV3DemangleData *)vdata; + uptr needed = data->size + l + 1; + if (needed > data->allocated) { + data->allocated *= 2; + if (needed > data->allocated) + data->allocated = needed; + char *buf = (char *)InternalAlloc(data->allocated); + if (data->buf) { + internal_memcpy(buf, data->buf, data->size); + InternalFree(data->buf); + } + data->buf = buf; + } + internal_memcpy(data->buf + data->size, s, l); + data->buf[data->size + l] = '\0'; + data->size += l; +} +} // extern "C" + +char *CplusV3Demangle(const char *name) { + CplusV3DemangleData data; + data.buf = 0; + data.size = 0; + data.allocated = 0; + if (cplus_demangle_v3_callback(name, DMGL_PARAMS | DMGL_ANSI, + CplusV3DemangleCallback, &data)) { + if (data.size + 64 > data.allocated) + return data.buf; + char *buf = internal_strdup(data.buf); + InternalFree(data.buf); + return buf; + } + if (data.buf) + InternalFree(data.buf); + return 0; +} +# endif // SANITIZER_CP_DEMANGLE + +struct SymbolizeCodeCallbackArg { + SymbolizedStack *first; + SymbolizedStack *last; + uptr frames_symbolized; + + AddressInfo *get_new_frame(uintptr_t addr) { + CHECK(last); + if (frames_symbolized > 0) { + SymbolizedStack *cur = SymbolizedStack::New(addr); + AddressInfo *info = &cur->info; + info->FillModuleInfo(first->info.module, first->info.module_offset, + first->info.module_arch); + last->next = cur; + last = cur; + } + CHECK_EQ(addr, first->info.address); + CHECK_EQ(addr, last->info.address); + return &last->info; + } +}; + +extern "C" { +static int SymbolizeCodePCInfoCallback(void *vdata, uintptr_t addr, + const char *filename, int lineno, + const char *function) { + SymbolizeCodeCallbackArg *cdata = (SymbolizeCodeCallbackArg *)vdata; + if (function) { + AddressInfo *info = cdata->get_new_frame(addr); + info->function = DemangleAlloc(function, /*always_alloc*/ true); + if (filename) + info->file = internal_strdup(filename); + info->line = lineno; + cdata->frames_symbolized++; + } + return 0; +} + +static void SymbolizeCodeCallback(void *vdata, uintptr_t addr, + const char *symname, uintptr_t, uintptr_t) { + SymbolizeCodeCallbackArg *cdata = (SymbolizeCodeCallbackArg *)vdata; + if (symname) { + AddressInfo *info = cdata->get_new_frame(addr); + info->function = DemangleAlloc(symname, /*always_alloc*/ true); + cdata->frames_symbolized++; + } +} + +static void SymbolizeDataCallback(void *vdata, uintptr_t, const char *symname, + uintptr_t symval, uintptr_t symsize) { + DataInfo *info = (DataInfo *)vdata; + if (symname && symval) { + info->name = DemangleAlloc(symname, /*always_alloc*/ true); + info->start = symval; + info->size = symsize; + } +} + +static void ErrorCallback(void *, const char *, int) {} +} // extern "C" + +} // namespace + +LibbacktraceSymbolizer *LibbacktraceSymbolizer::get(LowLevelAllocator *alloc) { + // State created in backtrace_create_state is leaked. + void *state = (void *)(backtrace_create_state("/proc/self/exe", 0, + ErrorCallback, NULL)); + if (!state) + return 0; + return new(*alloc) LibbacktraceSymbolizer(state); +} + +bool LibbacktraceSymbolizer::SymbolizePC(uptr addr, SymbolizedStack *stack) { + SymbolizeCodeCallbackArg data; + data.first = stack; + data.last = stack; + data.frames_symbolized = 0; + backtrace_pcinfo((backtrace_state *)state_, addr, SymbolizeCodePCInfoCallback, + ErrorCallback, &data); + if (data.frames_symbolized > 0) + return true; + backtrace_syminfo((backtrace_state *)state_, addr, SymbolizeCodeCallback, + ErrorCallback, &data); + return (data.frames_symbolized > 0); +} + +bool LibbacktraceSymbolizer::SymbolizeData(uptr addr, DataInfo *info) { + backtrace_syminfo((backtrace_state *)state_, addr, SymbolizeDataCallback, + ErrorCallback, info); + return true; +} + +#else // SANITIZER_LIBBACKTRACE + +LibbacktraceSymbolizer *LibbacktraceSymbolizer::get(LowLevelAllocator *alloc) { + return 0; +} + +bool LibbacktraceSymbolizer::SymbolizePC(uptr addr, SymbolizedStack *stack) { + (void)state_; + return false; +} + +bool LibbacktraceSymbolizer::SymbolizeData(uptr addr, DataInfo *info) { + return false; +} + +#endif // SANITIZER_LIBBACKTRACE + +static char *DemangleAlloc(const char *name, bool always_alloc) { +#if SANITIZER_LIBBACKTRACE && SANITIZER_CP_DEMANGLE + if (char *demangled = CplusV3Demangle(name)) + return demangled; +#endif + if (always_alloc) + return internal_strdup(name); + return 0; +} + +const char *LibbacktraceSymbolizer::Demangle(const char *name) { + return DemangleAlloc(name, /*always_alloc*/ false); +} + +} // namespace __sanitizer diff --git a/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_symbolizer_libbacktrace.h b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_symbolizer_libbacktrace.h new file mode 100644 index 0000000000..7b039b894b --- /dev/null +++ b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_symbolizer_libbacktrace.h @@ -0,0 +1,49 @@ +//===-- sanitizer_symbolizer_libbacktrace.h ---------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file is shared between AddressSanitizer and ThreadSanitizer +// run-time libraries. +// Header for libbacktrace symbolizer. +//===----------------------------------------------------------------------===// +#ifndef SANITIZER_SYMBOLIZER_LIBBACKTRACE_H +#define SANITIZER_SYMBOLIZER_LIBBACKTRACE_H + +#include "sanitizer_platform.h" +#include "sanitizer_common.h" +#include "sanitizer_allocator_internal.h" +#include "sanitizer_symbolizer_internal.h" + +#ifndef SANITIZER_LIBBACKTRACE +# define SANITIZER_LIBBACKTRACE 0 +#endif + +#ifndef SANITIZER_CP_DEMANGLE +# define SANITIZER_CP_DEMANGLE 0 +#endif + +namespace __sanitizer { + +class LibbacktraceSymbolizer final : public SymbolizerTool { + public: + static LibbacktraceSymbolizer *get(LowLevelAllocator *alloc); + + bool SymbolizePC(uptr addr, SymbolizedStack *stack) override; + + bool SymbolizeData(uptr addr, DataInfo *info) override; + + // May return NULL if demangling failed. + const char *Demangle(const char *name) override; + + private: + explicit LibbacktraceSymbolizer(void *state) : state_(state) {} + + void *state_; // Leaked. +}; + +} // namespace __sanitizer +#endif // SANITIZER_SYMBOLIZER_LIBBACKTRACE_H diff --git a/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_symbolizer_libcdep.cpp b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_symbolizer_libcdep.cpp new file mode 100644 index 0000000000..8bbd4af0c7 --- /dev/null +++ b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_symbolizer_libcdep.cpp @@ -0,0 +1,557 @@ +//===-- sanitizer_symbolizer_libcdep.cpp ----------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file is shared between AddressSanitizer and ThreadSanitizer +// run-time libraries. +//===----------------------------------------------------------------------===// + +#include "sanitizer_allocator_internal.h" +#include "sanitizer_internal_defs.h" +#include "sanitizer_platform.h" +#include "sanitizer_symbolizer_internal.h" + +namespace __sanitizer { + +Symbolizer *Symbolizer::GetOrInit() { + SpinMutexLock l(&init_mu_); + if (symbolizer_) + return symbolizer_; + symbolizer_ = PlatformInit(); + CHECK(symbolizer_); + return symbolizer_; +} + +// See sanitizer_symbolizer_markup.cpp. +#if !SANITIZER_SYMBOLIZER_MARKUP + +const char *ExtractToken(const char *str, const char *delims, char **result) { + uptr prefix_len = internal_strcspn(str, delims); + *result = (char*)InternalAlloc(prefix_len + 1); + internal_memcpy(*result, str, prefix_len); + (*result)[prefix_len] = '\0'; + const char *prefix_end = str + prefix_len; + if (*prefix_end != '\0') prefix_end++; + return prefix_end; +} + +const char *ExtractInt(const char *str, const char *delims, int *result) { + char *buff = nullptr; + const char *ret = ExtractToken(str, delims, &buff); + if (buff) { + *result = (int)internal_atoll(buff); + } + InternalFree(buff); + return ret; +} + +const char *ExtractUptr(const char *str, const char *delims, uptr *result) { + char *buff = nullptr; + const char *ret = ExtractToken(str, delims, &buff); + if (buff) { + *result = (uptr)internal_atoll(buff); + } + InternalFree(buff); + return ret; +} + +const char *ExtractSptr(const char *str, const char *delims, sptr *result) { + char *buff = nullptr; + const char *ret = ExtractToken(str, delims, &buff); + if (buff) { + *result = (sptr)internal_atoll(buff); + } + InternalFree(buff); + return ret; +} + +const char *ExtractTokenUpToDelimiter(const char *str, const char *delimiter, + char **result) { + const char *found_delimiter = internal_strstr(str, delimiter); + uptr prefix_len = + found_delimiter ? found_delimiter - str : internal_strlen(str); + *result = (char *)InternalAlloc(prefix_len + 1); + internal_memcpy(*result, str, prefix_len); + (*result)[prefix_len] = '\0'; + const char *prefix_end = str + prefix_len; + if (*prefix_end != '\0') prefix_end += internal_strlen(delimiter); + return prefix_end; +} + +SymbolizedStack *Symbolizer::SymbolizePC(uptr addr) { + Lock l(&mu_); + SymbolizedStack *res = SymbolizedStack::New(addr); + auto *mod = FindModuleForAddress(addr); + if (!mod) + return res; + // Always fill data about module name and offset. + res->info.FillModuleInfo(*mod); + for (auto &tool : tools_) { + SymbolizerScope sym_scope(this); + if (tool.SymbolizePC(addr, res)) { + return res; + } + } + return res; +} + +bool Symbolizer::SymbolizeData(uptr addr, DataInfo *info) { + Lock l(&mu_); + const char *module_name = nullptr; + uptr module_offset; + ModuleArch arch; + if (!FindModuleNameAndOffsetForAddress(addr, &module_name, &module_offset, + &arch)) + return false; + info->Clear(); + info->module = internal_strdup(module_name); + info->module_offset = module_offset; + info->module_arch = arch; + for (auto &tool : tools_) { + SymbolizerScope sym_scope(this); + if (tool.SymbolizeData(addr, info)) { + return true; + } + } + return true; +} + +bool Symbolizer::SymbolizeFrame(uptr addr, FrameInfo *info) { + Lock l(&mu_); + const char *module_name = nullptr; + if (!FindModuleNameAndOffsetForAddress( + addr, &module_name, &info->module_offset, &info->module_arch)) + return false; + info->module = internal_strdup(module_name); + for (auto &tool : tools_) { + SymbolizerScope sym_scope(this); + if (tool.SymbolizeFrame(addr, info)) { + return true; + } + } + return true; +} + +bool Symbolizer::GetModuleNameAndOffsetForPC(uptr pc, const char **module_name, + uptr *module_address) { + Lock l(&mu_); + const char *internal_module_name = nullptr; + ModuleArch arch; + if (!FindModuleNameAndOffsetForAddress(pc, &internal_module_name, + module_address, &arch)) + return false; + + if (module_name) + *module_name = module_names_.GetOwnedCopy(internal_module_name); + return true; +} + +void Symbolizer::Flush() { + Lock l(&mu_); + for (auto &tool : tools_) { + SymbolizerScope sym_scope(this); + tool.Flush(); + } +} + +const char *Symbolizer::Demangle(const char *name) { + Lock l(&mu_); + for (auto &tool : tools_) { + SymbolizerScope sym_scope(this); + if (const char *demangled = tool.Demangle(name)) + return demangled; + } + return PlatformDemangle(name); +} + +bool Symbolizer::FindModuleNameAndOffsetForAddress(uptr address, + const char **module_name, + uptr *module_offset, + ModuleArch *module_arch) { + const LoadedModule *module = FindModuleForAddress(address); + if (!module) + return false; + *module_name = module->full_name(); + *module_offset = address - module->base_address(); + *module_arch = module->arch(); + return true; +} + +void Symbolizer::RefreshModules() { + modules_.init(); + fallback_modules_.fallbackInit(); + RAW_CHECK(modules_.size() > 0); + modules_fresh_ = true; +} + +static const LoadedModule *SearchForModule(const ListOfModules &modules, + uptr address) { + for (uptr i = 0; i < modules.size(); i++) { + if (modules[i].containsAddress(address)) { + return &modules[i]; + } + } + return nullptr; +} + +const LoadedModule *Symbolizer::FindModuleForAddress(uptr address) { + bool modules_were_reloaded = false; + if (!modules_fresh_) { + RefreshModules(); + modules_were_reloaded = true; + } + const LoadedModule *module = SearchForModule(modules_, address); + if (module) return module; + + // dlopen/dlclose interceptors invalidate the module list, but when + // interception is disabled, we need to retry if the lookup fails in + // case the module list changed. +#if !SANITIZER_INTERCEPT_DLOPEN_DLCLOSE + if (!modules_were_reloaded) { + RefreshModules(); + module = SearchForModule(modules_, address); + if (module) return module; + } +#endif + + if (fallback_modules_.size()) { + module = SearchForModule(fallback_modules_, address); + } + return module; +} + +// For now we assume the following protocol: +// For each request of the form +// <module_name> <module_offset> +// passed to STDIN, external symbolizer prints to STDOUT response: +// <function_name> +// <file_name>:<line_number>:<column_number> +// <function_name> +// <file_name>:<line_number>:<column_number> +// ... +// <empty line> +class LLVMSymbolizerProcess final : public SymbolizerProcess { + public: + explicit LLVMSymbolizerProcess(const char *path) + : SymbolizerProcess(path, /*use_posix_spawn=*/SANITIZER_MAC) {} + + private: + bool ReachedEndOfOutput(const char *buffer, uptr length) const override { + // Empty line marks the end of llvm-symbolizer output. + return length >= 2 && buffer[length - 1] == '\n' && + buffer[length - 2] == '\n'; + } + + // When adding a new architecture, don't forget to also update + // script/asan_symbolize.py and sanitizer_common.h. + void GetArgV(const char *path_to_binary, + const char *(&argv)[kArgVMax]) const override { +#if defined(__x86_64h__) + const char* const kSymbolizerArch = "--default-arch=x86_64h"; +#elif defined(__x86_64__) + const char* const kSymbolizerArch = "--default-arch=x86_64"; +#elif defined(__i386__) + const char* const kSymbolizerArch = "--default-arch=i386"; +#elif SANITIZER_RISCV64 + const char *const kSymbolizerArch = "--default-arch=riscv64"; +#elif defined(__aarch64__) + const char* const kSymbolizerArch = "--default-arch=arm64"; +#elif defined(__arm__) + const char* const kSymbolizerArch = "--default-arch=arm"; +#elif defined(__powerpc64__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ + const char* const kSymbolizerArch = "--default-arch=powerpc64"; +#elif defined(__powerpc64__) && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ + const char* const kSymbolizerArch = "--default-arch=powerpc64le"; +#elif defined(__s390x__) + const char* const kSymbolizerArch = "--default-arch=s390x"; +#elif defined(__s390__) + const char* const kSymbolizerArch = "--default-arch=s390"; +#else + const char* const kSymbolizerArch = "--default-arch=unknown"; +#endif + + const char *const demangle_flag = + common_flags()->demangle ? "--demangle" : "--no-demangle"; + const char *const inline_flag = + common_flags()->symbolize_inline_frames ? "--inlines" : "--no-inlines"; + int i = 0; + argv[i++] = path_to_binary; + argv[i++] = demangle_flag; + argv[i++] = inline_flag; + argv[i++] = kSymbolizerArch; + argv[i++] = nullptr; + CHECK_LE(i, kArgVMax); + } +}; + +LLVMSymbolizer::LLVMSymbolizer(const char *path, LowLevelAllocator *allocator) + : symbolizer_process_(new(*allocator) LLVMSymbolizerProcess(path)) {} + +// Parse a <file>:<line>[:<column>] buffer. The file path may contain colons on +// Windows, so extract tokens from the right hand side first. The column info is +// also optional. +static const char *ParseFileLineInfo(AddressInfo *info, const char *str) { + char *file_line_info = nullptr; + str = ExtractToken(str, "\n", &file_line_info); + CHECK(file_line_info); + + if (uptr size = internal_strlen(file_line_info)) { + char *back = file_line_info + size - 1; + for (int i = 0; i < 2; ++i) { + while (back > file_line_info && IsDigit(*back)) --back; + if (*back != ':' || !IsDigit(back[1])) break; + info->column = info->line; + info->line = internal_atoll(back + 1); + // Truncate the string at the colon to keep only filename. + *back = '\0'; + --back; + } + ExtractToken(file_line_info, "", &info->file); + } + + InternalFree(file_line_info); + return str; +} + +// Parses one or more two-line strings in the following format: +// <function_name> +// <file_name>:<line_number>[:<column_number>] +// Used by LLVMSymbolizer, Addr2LinePool and InternalSymbolizer, since all of +// them use the same output format. +void ParseSymbolizePCOutput(const char *str, SymbolizedStack *res) { + bool top_frame = true; + SymbolizedStack *last = res; + while (true) { + char *function_name = nullptr; + str = ExtractToken(str, "\n", &function_name); + CHECK(function_name); + if (function_name[0] == '\0') { + // There are no more frames. + InternalFree(function_name); + break; + } + SymbolizedStack *cur; + if (top_frame) { + cur = res; + top_frame = false; + } else { + cur = SymbolizedStack::New(res->info.address); + cur->info.FillModuleInfo(res->info.module, res->info.module_offset, + res->info.module_arch); + last->next = cur; + last = cur; + } + + AddressInfo *info = &cur->info; + info->function = function_name; + str = ParseFileLineInfo(info, str); + + // Functions and filenames can be "??", in which case we write 0 + // to address info to mark that names are unknown. + if (0 == internal_strcmp(info->function, "??")) { + InternalFree(info->function); + info->function = 0; + } + if (info->file && 0 == internal_strcmp(info->file, "??")) { + InternalFree(info->file); + info->file = 0; + } + } +} + +// Parses a two-line string in the following format: +// <symbol_name> +// <start_address> <size> +// Used by LLVMSymbolizer and InternalSymbolizer. +void ParseSymbolizeDataOutput(const char *str, DataInfo *info) { + str = ExtractToken(str, "\n", &info->name); + str = ExtractUptr(str, " ", &info->start); + str = ExtractUptr(str, "\n", &info->size); +} + +static void ParseSymbolizeFrameOutput(const char *str, + InternalMmapVector<LocalInfo> *locals) { + if (internal_strncmp(str, "??", 2) == 0) + return; + + while (*str) { + LocalInfo local; + str = ExtractToken(str, "\n", &local.function_name); + str = ExtractToken(str, "\n", &local.name); + + AddressInfo addr; + str = ParseFileLineInfo(&addr, str); + local.decl_file = addr.file; + local.decl_line = addr.line; + + local.has_frame_offset = internal_strncmp(str, "??", 2) != 0; + str = ExtractSptr(str, " ", &local.frame_offset); + + local.has_size = internal_strncmp(str, "??", 2) != 0; + str = ExtractUptr(str, " ", &local.size); + + local.has_tag_offset = internal_strncmp(str, "??", 2) != 0; + str = ExtractUptr(str, "\n", &local.tag_offset); + + locals->push_back(local); + } +} + +bool LLVMSymbolizer::SymbolizePC(uptr addr, SymbolizedStack *stack) { + AddressInfo *info = &stack->info; + const char *buf = FormatAndSendCommand( + "CODE", info->module, info->module_offset, info->module_arch); + if (!buf) + return false; + ParseSymbolizePCOutput(buf, stack); + return true; +} + +bool LLVMSymbolizer::SymbolizeData(uptr addr, DataInfo *info) { + const char *buf = FormatAndSendCommand( + "DATA", info->module, info->module_offset, info->module_arch); + if (!buf) + return false; + ParseSymbolizeDataOutput(buf, info); + info->start += (addr - info->module_offset); // Add the base address. + return true; +} + +bool LLVMSymbolizer::SymbolizeFrame(uptr addr, FrameInfo *info) { + const char *buf = FormatAndSendCommand( + "FRAME", info->module, info->module_offset, info->module_arch); + if (!buf) + return false; + ParseSymbolizeFrameOutput(buf, &info->locals); + return true; +} + +const char *LLVMSymbolizer::FormatAndSendCommand(const char *command_prefix, + const char *module_name, + uptr module_offset, + ModuleArch arch) { + CHECK(module_name); + int size_needed = 0; + if (arch == kModuleArchUnknown) + size_needed = internal_snprintf(buffer_, kBufferSize, "%s \"%s\" 0x%zx\n", + command_prefix, module_name, module_offset); + else + size_needed = internal_snprintf(buffer_, kBufferSize, + "%s \"%s:%s\" 0x%zx\n", command_prefix, + module_name, ModuleArchToString(arch), + module_offset); + + if (size_needed >= static_cast<int>(kBufferSize)) { + Report("WARNING: Command buffer too small"); + return nullptr; + } + + return symbolizer_process_->SendCommand(buffer_); +} + +SymbolizerProcess::SymbolizerProcess(const char *path, bool use_posix_spawn) + : path_(path), + input_fd_(kInvalidFd), + output_fd_(kInvalidFd), + times_restarted_(0), + failed_to_start_(false), + reported_invalid_path_(false), + use_posix_spawn_(use_posix_spawn) { + CHECK(path_); + CHECK_NE(path_[0], '\0'); +} + +static bool IsSameModule(const char* path) { + if (const char* ProcessName = GetProcessName()) { + if (const char* SymbolizerName = StripModuleName(path)) { + return !internal_strcmp(ProcessName, SymbolizerName); + } + } + return false; +} + +const char *SymbolizerProcess::SendCommand(const char *command) { + if (failed_to_start_) + return nullptr; + if (IsSameModule(path_)) { + Report("WARNING: Symbolizer was blocked from starting itself!\n"); + failed_to_start_ = true; + return nullptr; + } + for (; times_restarted_ < kMaxTimesRestarted; times_restarted_++) { + // Start or restart symbolizer if we failed to send command to it. + if (const char *res = SendCommandImpl(command)) + return res; + Restart(); + } + if (!failed_to_start_) { + Report("WARNING: Failed to use and restart external symbolizer!\n"); + failed_to_start_ = true; + } + return nullptr; +} + +const char *SymbolizerProcess::SendCommandImpl(const char *command) { + if (input_fd_ == kInvalidFd || output_fd_ == kInvalidFd) + return nullptr; + if (!WriteToSymbolizer(command, internal_strlen(command))) + return nullptr; + if (!ReadFromSymbolizer(buffer_, kBufferSize)) + return nullptr; + return buffer_; +} + +bool SymbolizerProcess::Restart() { + if (input_fd_ != kInvalidFd) + CloseFile(input_fd_); + if (output_fd_ != kInvalidFd) + CloseFile(output_fd_); + return StartSymbolizerSubprocess(); +} + +bool SymbolizerProcess::ReadFromSymbolizer(char *buffer, uptr max_length) { + if (max_length == 0) + return true; + uptr read_len = 0; + while (true) { + uptr just_read = 0; + bool success = ReadFromFile(input_fd_, buffer + read_len, + max_length - read_len - 1, &just_read); + // We can't read 0 bytes, as we don't expect external symbolizer to close + // its stdout. + if (!success || just_read == 0) { + Report("WARNING: Can't read from symbolizer at fd %d\n", input_fd_); + return false; + } + read_len += just_read; + if (ReachedEndOfOutput(buffer, read_len)) + break; + if (read_len + 1 == max_length) { + Report("WARNING: Symbolizer buffer too small\n"); + read_len = 0; + break; + } + } + buffer[read_len] = '\0'; + return true; +} + +bool SymbolizerProcess::WriteToSymbolizer(const char *buffer, uptr length) { + if (length == 0) + return true; + uptr write_len = 0; + bool success = WriteToFile(output_fd_, buffer, length, &write_len); + if (!success || write_len != length) { + Report("WARNING: Can't write to symbolizer at fd %d\n", output_fd_); + return false; + } + return true; +} + +#endif // !SANITIZER_SYMBOLIZER_MARKUP + +} // namespace __sanitizer diff --git a/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_symbolizer_mac.cpp b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_symbolizer_mac.cpp new file mode 100644 index 0000000000..ac811c8a91 --- /dev/null +++ b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_symbolizer_mac.cpp @@ -0,0 +1,205 @@ +//===-- sanitizer_symbolizer_mac.cpp --------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file is shared between various sanitizers' runtime libraries. +// +// Implementation of Mac-specific "atos" symbolizer. +//===----------------------------------------------------------------------===// + +#include "sanitizer_platform.h" +#if SANITIZER_MAC + +#include "sanitizer_allocator_internal.h" +#include "sanitizer_mac.h" +#include "sanitizer_symbolizer_mac.h" + +#include <dlfcn.h> +#include <errno.h> +#include <stdlib.h> +#include <sys/wait.h> +#include <unistd.h> +#include <util.h> + +namespace __sanitizer { + +bool DlAddrSymbolizer::SymbolizePC(uptr addr, SymbolizedStack *stack) { + Dl_info info; + int result = dladdr((const void *)addr, &info); + if (!result) return false; + + // Compute offset if possible. `dladdr()` doesn't always ensure that `addr >= + // sym_addr` so only compute the offset when this holds. Failure to find the + // function offset is not treated as a failure because it might still be + // possible to get the symbol name. + uptr sym_addr = reinterpret_cast<uptr>(info.dli_saddr); + if (addr >= sym_addr) { + stack->info.function_offset = addr - sym_addr; + } + + const char *demangled = DemangleSwiftAndCXX(info.dli_sname); + if (!demangled) return false; + stack->info.function = internal_strdup(demangled); + return true; +} + +bool DlAddrSymbolizer::SymbolizeData(uptr addr, DataInfo *datainfo) { + Dl_info info; + int result = dladdr((const void *)addr, &info); + if (!result) return false; + const char *demangled = DemangleSwiftAndCXX(info.dli_sname); + datainfo->name = internal_strdup(demangled); + datainfo->start = (uptr)info.dli_saddr; + return true; +} + +class AtosSymbolizerProcess final : public SymbolizerProcess { + public: + explicit AtosSymbolizerProcess(const char *path) + : SymbolizerProcess(path, /*use_posix_spawn*/ true) { + pid_str_[0] = '\0'; + } + + private: + bool StartSymbolizerSubprocess() override { + // Put the string command line argument in the object so that it outlives + // the call to GetArgV. + internal_snprintf(pid_str_, sizeof(pid_str_), "%d", (int)internal_getpid()); + + // Configure sandbox before starting atos process. + return SymbolizerProcess::StartSymbolizerSubprocess(); + } + + bool ReachedEndOfOutput(const char *buffer, uptr length) const override { + return (length >= 1 && buffer[length - 1] == '\n'); + } + + void GetArgV(const char *path_to_binary, + const char *(&argv)[kArgVMax]) const override { + int i = 0; + argv[i++] = path_to_binary; + argv[i++] = "-p"; + argv[i++] = &pid_str_[0]; + if (GetMacosAlignedVersion() == MacosVersion(10, 9)) { + // On Mavericks atos prints a deprecation warning which we suppress by + // passing -d. The warning isn't present on other OSX versions, even the + // newer ones. + argv[i++] = "-d"; + } + argv[i++] = nullptr; + CHECK_LE(i, kArgVMax); + } + + char pid_str_[16]; +}; + +#undef K_ATOS_ENV_VAR + +static bool ParseCommandOutput(const char *str, uptr addr, char **out_name, + char **out_module, char **out_file, uptr *line, + uptr *start_address) { + // Trim ending newlines. + char *trim; + ExtractTokenUpToDelimiter(str, "\n", &trim); + + // The line from `atos` is in one of these formats: + // myfunction (in library.dylib) (sourcefile.c:17) + // myfunction (in library.dylib) + 0x1fe + // myfunction (in library.dylib) + 15 + // 0xdeadbeef (in library.dylib) + 0x1fe + // 0xdeadbeef (in library.dylib) + 15 + // 0xdeadbeef (in library.dylib) + // 0xdeadbeef + + const char *rest = trim; + char *symbol_name; + rest = ExtractTokenUpToDelimiter(rest, " (in ", &symbol_name); + if (rest[0] == '\0') { + InternalFree(symbol_name); + InternalFree(trim); + return false; + } + + if (internal_strncmp(symbol_name, "0x", 2) != 0) + *out_name = symbol_name; + else + InternalFree(symbol_name); + rest = ExtractTokenUpToDelimiter(rest, ") ", out_module); + + if (rest[0] == '(') { + if (out_file) { + rest++; + rest = ExtractTokenUpToDelimiter(rest, ":", out_file); + char *extracted_line_number; + rest = ExtractTokenUpToDelimiter(rest, ")", &extracted_line_number); + if (line) *line = (uptr)internal_atoll(extracted_line_number); + InternalFree(extracted_line_number); + } + } else if (rest[0] == '+') { + rest += 2; + uptr offset = internal_atoll(rest); + if (start_address) *start_address = addr - offset; + } + + InternalFree(trim); + return true; +} + +AtosSymbolizer::AtosSymbolizer(const char *path, LowLevelAllocator *allocator) + : process_(new (*allocator) AtosSymbolizerProcess(path)) {} + +bool AtosSymbolizer::SymbolizePC(uptr addr, SymbolizedStack *stack) { + if (!process_) return false; + if (addr == 0) return false; + char command[32]; + internal_snprintf(command, sizeof(command), "0x%zx\n", addr); + const char *buf = process_->SendCommand(command); + if (!buf) return false; + uptr line; + uptr start_address = AddressInfo::kUnknown; + if (!ParseCommandOutput(buf, addr, &stack->info.function, &stack->info.module, + &stack->info.file, &line, &start_address)) { + process_ = nullptr; + return false; + } + stack->info.line = (int)line; + + if (start_address == AddressInfo::kUnknown) { + // Fallback to dladdr() to get function start address if atos doesn't report + // it. + Dl_info info; + int result = dladdr((const void *)addr, &info); + if (result) + start_address = reinterpret_cast<uptr>(info.dli_saddr); + } + + // Only assign to `function_offset` if we were able to get the function's + // start address and we got a sensible `start_address` (dladdr doesn't always + // ensure that `addr >= sym_addr`). + if (start_address != AddressInfo::kUnknown && addr >= start_address) { + stack->info.function_offset = addr - start_address; + } + return true; +} + +bool AtosSymbolizer::SymbolizeData(uptr addr, DataInfo *info) { + if (!process_) return false; + char command[32]; + internal_snprintf(command, sizeof(command), "0x%zx\n", addr); + const char *buf = process_->SendCommand(command); + if (!buf) return false; + if (!ParseCommandOutput(buf, addr, &info->name, &info->module, nullptr, + nullptr, &info->start)) { + process_ = nullptr; + return false; + } + return true; +} + +} // namespace __sanitizer + +#endif // SANITIZER_MAC diff --git a/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_symbolizer_mac.h b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_symbolizer_mac.h new file mode 100644 index 0000000000..d5abe9d98c --- /dev/null +++ b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_symbolizer_mac.h @@ -0,0 +1,47 @@ +//===-- sanitizer_symbolizer_mac.h ------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file is shared between various sanitizers' runtime libraries. +// +// Header for Mac-specific "atos" symbolizer. +//===----------------------------------------------------------------------===// + +#ifndef SANITIZER_SYMBOLIZER_MAC_H +#define SANITIZER_SYMBOLIZER_MAC_H + +#include "sanitizer_platform.h" +#if SANITIZER_MAC + +#include "sanitizer_symbolizer_internal.h" + +namespace __sanitizer { + +class DlAddrSymbolizer final : public SymbolizerTool { + public: + bool SymbolizePC(uptr addr, SymbolizedStack *stack) override; + bool SymbolizeData(uptr addr, DataInfo *info) override; +}; + +class AtosSymbolizerProcess; + +class AtosSymbolizer final : public SymbolizerTool { + public: + explicit AtosSymbolizer(const char *path, LowLevelAllocator *allocator); + + bool SymbolizePC(uptr addr, SymbolizedStack *stack) override; + bool SymbolizeData(uptr addr, DataInfo *info) override; + + private: + AtosSymbolizerProcess *process_; +}; + +} // namespace __sanitizer + +#endif // SANITIZER_MAC + +#endif // SANITIZER_SYMBOLIZER_MAC_H diff --git a/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_symbolizer_markup.cpp b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_symbolizer_markup.cpp new file mode 100644 index 0000000000..1ec0c5cad7 --- /dev/null +++ b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_symbolizer_markup.cpp @@ -0,0 +1,150 @@ +//===-- sanitizer_symbolizer_markup.cpp -----------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file is shared between various sanitizers' runtime libraries. +// +// Implementation of offline markup symbolizer. +//===----------------------------------------------------------------------===// + +#include "sanitizer_platform.h" +#if SANITIZER_SYMBOLIZER_MARKUP + +#if SANITIZER_FUCHSIA +#include "sanitizer_symbolizer_fuchsia.h" +# endif + +# include <limits.h> +# include <unwind.h> + +# include "sanitizer_stacktrace.h" +# include "sanitizer_symbolizer.h" + +namespace __sanitizer { + +// This generic support for offline symbolizing is based on the +// Fuchsia port. We don't do any actual symbolization per se. +// Instead, we emit text containing raw addresses and raw linkage +// symbol names, embedded in Fuchsia's symbolization markup format. +// Fuchsia's logging infrastructure emits enough information about +// process memory layout that a post-processing filter can do the +// symbolization and pretty-print the markup. See the spec at: +// https://fuchsia.googlesource.com/zircon/+/master/docs/symbolizer_markup.md + +// This is used by UBSan for type names, and by ASan for global variable names. +// It's expected to return a static buffer that will be reused on each call. +const char *Symbolizer::Demangle(const char *name) { + static char buffer[kFormatDemangleMax]; + internal_snprintf(buffer, sizeof(buffer), kFormatDemangle, name); + return buffer; +} + +// This is used mostly for suppression matching. Making it work +// would enable "interceptor_via_lib" suppressions. It's also used +// once in UBSan to say "in module ..." in a message that also +// includes an address in the module, so post-processing can already +// pretty-print that so as to indicate the module. +bool Symbolizer::GetModuleNameAndOffsetForPC(uptr pc, const char **module_name, + uptr *module_address) { + return false; +} + +// This is mainly used by hwasan for online symbolization. This isn't needed +// since hwasan can always just dump stack frames for offline symbolization. +bool Symbolizer::SymbolizeFrame(uptr addr, FrameInfo *info) { return false; } + +// This is used in some places for suppression checking, which we +// don't really support for Fuchsia. It's also used in UBSan to +// identify a PC location to a function name, so we always fill in +// the function member with a string containing markup around the PC +// value. +// TODO(mcgrathr): Under SANITIZER_GO, it's currently used by TSan +// to render stack frames, but that should be changed to use +// RenderStackFrame. +SymbolizedStack *Symbolizer::SymbolizePC(uptr addr) { + SymbolizedStack *s = SymbolizedStack::New(addr); + char buffer[kFormatFunctionMax]; + internal_snprintf(buffer, sizeof(buffer), kFormatFunction, addr); + s->info.function = internal_strdup(buffer); + return s; +} + +// Always claim we succeeded, so that RenderDataInfo will be called. +bool Symbolizer::SymbolizeData(uptr addr, DataInfo *info) { + info->Clear(); + info->start = addr; + return true; +} + +// We ignore the format argument to __sanitizer_symbolize_global. +void RenderData(InternalScopedString *buffer, const char *format, + const DataInfo *DI, const char *strip_path_prefix) { + buffer->append(kFormatData, DI->start); +} + +bool RenderNeedsSymbolization(const char *format) { return false; } + +// We don't support the stack_trace_format flag at all. +void RenderFrame(InternalScopedString *buffer, const char *format, int frame_no, + uptr address, const AddressInfo *info, bool vs_style, + const char *strip_path_prefix, const char *strip_func_prefix) { + CHECK(!RenderNeedsSymbolization(format)); + buffer->append(kFormatFrame, frame_no, address); +} + +Symbolizer *Symbolizer::PlatformInit() { + return new (symbolizer_allocator_) Symbolizer({}); +} + +void Symbolizer::LateInitialize() { Symbolizer::GetOrInit(); } + +void StartReportDeadlySignal() {} +void ReportDeadlySignal(const SignalContext &sig, u32 tid, + UnwindSignalStackCallbackType unwind, + const void *unwind_context) {} + +#if SANITIZER_CAN_SLOW_UNWIND +struct UnwindTraceArg { + BufferedStackTrace *stack; + u32 max_depth; +}; + +_Unwind_Reason_Code Unwind_Trace(struct _Unwind_Context *ctx, void *param) { + UnwindTraceArg *arg = static_cast<UnwindTraceArg *>(param); + CHECK_LT(arg->stack->size, arg->max_depth); + uptr pc = _Unwind_GetIP(ctx); + if (pc < PAGE_SIZE) return _URC_NORMAL_STOP; + arg->stack->trace_buffer[arg->stack->size++] = pc; + return (arg->stack->size == arg->max_depth ? _URC_NORMAL_STOP + : _URC_NO_REASON); +} + +void BufferedStackTrace::UnwindSlow(uptr pc, u32 max_depth) { + CHECK_GE(max_depth, 2); + size = 0; + UnwindTraceArg arg = {this, Min(max_depth + 1, kStackTraceMax)}; + _Unwind_Backtrace(Unwind_Trace, &arg); + CHECK_GT(size, 0); + // We need to pop a few frames so that pc is on top. + uptr to_pop = LocatePcInTrace(pc); + // trace_buffer[0] belongs to the current function so we always pop it, + // unless there is only 1 frame in the stack trace (1 frame is always better + // than 0!). + PopStackFrames(Min(to_pop, static_cast<uptr>(1))); + trace_buffer[0] = pc; +} + +void BufferedStackTrace::UnwindSlow(uptr pc, void *context, u32 max_depth) { + CHECK(context); + CHECK_GE(max_depth, 2); + UNREACHABLE("signal context doesn't exist"); +} +#endif // SANITIZER_CAN_SLOW_UNWIND + +} // namespace __sanitizer + +#endif // SANITIZER_SYMBOLIZER_MARKUP diff --git a/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cpp b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cpp new file mode 100644 index 0000000000..5f6e4cc318 --- /dev/null +++ b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cpp @@ -0,0 +1,511 @@ +//===-- sanitizer_symbolizer_posix_libcdep.cpp ----------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file is shared between AddressSanitizer and ThreadSanitizer +// run-time libraries. +// POSIX-specific implementation of symbolizer parts. +//===----------------------------------------------------------------------===// + +#include "sanitizer_platform.h" +#if SANITIZER_POSIX +#include "sanitizer_allocator_internal.h" +#include "sanitizer_common.h" +#include "sanitizer_file.h" +#include "sanitizer_flags.h" +#include "sanitizer_internal_defs.h" +#include "sanitizer_linux.h" +#include "sanitizer_placement_new.h" +#include "sanitizer_posix.h" +#include "sanitizer_procmaps.h" +#include "sanitizer_symbolizer_internal.h" +#include "sanitizer_symbolizer_libbacktrace.h" +#include "sanitizer_symbolizer_mac.h" + +#include <dlfcn.h> // for dlsym() +#include <errno.h> +#include <stdint.h> +#include <stdlib.h> +#include <sys/wait.h> +#include <unistd.h> + +// C++ demangling function, as required by Itanium C++ ABI. This is weak, +// because we do not require a C++ ABI library to be linked to a program +// using sanitizers; if it's not present, we'll just use the mangled name. +namespace __cxxabiv1 { + extern "C" SANITIZER_WEAK_ATTRIBUTE + char *__cxa_demangle(const char *mangled, char *buffer, + size_t *length, int *status); +} + +namespace __sanitizer { + +// Attempts to demangle the name via __cxa_demangle from __cxxabiv1. +const char *DemangleCXXABI(const char *name) { + // FIXME: __cxa_demangle aggressively insists on allocating memory. + // There's not much we can do about that, short of providing our + // own demangler (libc++abi's implementation could be adapted so that + // it does not allocate). For now, we just call it anyway, and we leak + // the returned value. + if (&__cxxabiv1::__cxa_demangle) + if (const char *demangled_name = + __cxxabiv1::__cxa_demangle(name, 0, 0, 0)) + return demangled_name; + + return name; +} + +// As of now, there are no headers for the Swift runtime. Once they are +// present, we will weakly link since we do not require Swift runtime to be +// linked. +typedef char *(*swift_demangle_ft)(const char *mangledName, + size_t mangledNameLength, char *outputBuffer, + size_t *outputBufferSize, uint32_t flags); +static swift_demangle_ft swift_demangle_f; + +// This must not happen lazily at symbolication time, because dlsym uses +// malloc and thread-local storage, which is not a good thing to do during +// symbolication. +static void InitializeSwiftDemangler() { + swift_demangle_f = (swift_demangle_ft)dlsym(RTLD_DEFAULT, "swift_demangle"); + (void)dlerror(); // Cleanup error message in case of failure +} + +// Attempts to demangle a Swift name. The demangler will return nullptr if a +// non-Swift name is passed in. +const char *DemangleSwift(const char *name) { + if (swift_demangle_f) + return swift_demangle_f(name, internal_strlen(name), 0, 0, 0); + + return nullptr; +} + +const char *DemangleSwiftAndCXX(const char *name) { + if (!name) return nullptr; + if (const char *swift_demangled_name = DemangleSwift(name)) + return swift_demangled_name; + return DemangleCXXABI(name); +} + +static bool CreateTwoHighNumberedPipes(int *infd_, int *outfd_) { + int *infd = NULL; + int *outfd = NULL; + // The client program may close its stdin and/or stdout and/or stderr + // thus allowing socketpair to reuse file descriptors 0, 1 or 2. + // In this case the communication between the forked processes may be + // broken if either the parent or the child tries to close or duplicate + // these descriptors. The loop below produces two pairs of file + // descriptors, each greater than 2 (stderr). + int sock_pair[5][2]; + for (int i = 0; i < 5; i++) { + if (pipe(sock_pair[i]) == -1) { + for (int j = 0; j < i; j++) { + internal_close(sock_pair[j][0]); + internal_close(sock_pair[j][1]); + } + return false; + } else if (sock_pair[i][0] > 2 && sock_pair[i][1] > 2) { + if (infd == NULL) { + infd = sock_pair[i]; + } else { + outfd = sock_pair[i]; + for (int j = 0; j < i; j++) { + if (sock_pair[j] == infd) continue; + internal_close(sock_pair[j][0]); + internal_close(sock_pair[j][1]); + } + break; + } + } + } + CHECK(infd); + CHECK(outfd); + infd_[0] = infd[0]; + infd_[1] = infd[1]; + outfd_[0] = outfd[0]; + outfd_[1] = outfd[1]; + return true; +} + +bool SymbolizerProcess::StartSymbolizerSubprocess() { + if (!FileExists(path_)) { + if (!reported_invalid_path_) { + Report("WARNING: invalid path to external symbolizer!\n"); + reported_invalid_path_ = true; + } + return false; + } + + const char *argv[kArgVMax]; + GetArgV(path_, argv); + pid_t pid; + + // Report how symbolizer is being launched for debugging purposes. + if (Verbosity() >= 3) { + // Only use `Report` for first line so subsequent prints don't get prefixed + // with current PID. + Report("Launching Symbolizer process: "); + for (unsigned index = 0; index < kArgVMax && argv[index]; ++index) + Printf("%s ", argv[index]); + Printf("\n"); + } + + if (use_posix_spawn_) { +#if SANITIZER_MAC + fd_t fd = internal_spawn(argv, const_cast<const char **>(GetEnvP()), &pid); + if (fd == kInvalidFd) { + Report("WARNING: failed to spawn external symbolizer (errno: %d)\n", + errno); + return false; + } + + input_fd_ = fd; + output_fd_ = fd; +#else // SANITIZER_MAC + UNIMPLEMENTED(); +#endif // SANITIZER_MAC + } else { + fd_t infd[2] = {}, outfd[2] = {}; + if (!CreateTwoHighNumberedPipes(infd, outfd)) { + Report("WARNING: Can't create a socket pair to start " + "external symbolizer (errno: %d)\n", errno); + return false; + } + + pid = StartSubprocess(path_, argv, GetEnvP(), /* stdin */ outfd[0], + /* stdout */ infd[1]); + if (pid < 0) { + internal_close(infd[0]); + internal_close(outfd[1]); + return false; + } + + input_fd_ = infd[0]; + output_fd_ = outfd[1]; + } + + CHECK_GT(pid, 0); + + // Check that symbolizer subprocess started successfully. + SleepForMillis(kSymbolizerStartupTimeMillis); + if (!IsProcessRunning(pid)) { + // Either waitpid failed, or child has already exited. + Report("WARNING: external symbolizer didn't start up correctly!\n"); + return false; + } + + return true; +} + +class Addr2LineProcess final : public SymbolizerProcess { + public: + Addr2LineProcess(const char *path, const char *module_name) + : SymbolizerProcess(path), module_name_(internal_strdup(module_name)) {} + + const char *module_name() const { return module_name_; } + + private: + void GetArgV(const char *path_to_binary, + const char *(&argv)[kArgVMax]) const override { + int i = 0; + argv[i++] = path_to_binary; + if (common_flags()->demangle) + argv[i++] = "-C"; + if (common_flags()->symbolize_inline_frames) + argv[i++] = "-i"; + argv[i++] = "-fe"; + argv[i++] = module_name_; + argv[i++] = nullptr; + CHECK_LE(i, kArgVMax); + } + + bool ReachedEndOfOutput(const char *buffer, uptr length) const override; + + bool ReadFromSymbolizer(char *buffer, uptr max_length) override { + if (!SymbolizerProcess::ReadFromSymbolizer(buffer, max_length)) + return false; + // The returned buffer is empty when output is valid, but exceeds + // max_length. + if (*buffer == '\0') + return true; + // We should cut out output_terminator_ at the end of given buffer, + // appended by addr2line to mark the end of its meaningful output. + // We cannot scan buffer from it's beginning, because it is legal for it + // to start with output_terminator_ in case given offset is invalid. So, + // scanning from second character. + char *garbage = internal_strstr(buffer + 1, output_terminator_); + // This should never be NULL since buffer must end up with + // output_terminator_. + CHECK(garbage); + // Trim the buffer. + garbage[0] = '\0'; + return true; + } + + const char *module_name_; // Owned, leaked. + static const char output_terminator_[]; +}; + +const char Addr2LineProcess::output_terminator_[] = "??\n??:0\n"; + +bool Addr2LineProcess::ReachedEndOfOutput(const char *buffer, + uptr length) const { + const size_t kTerminatorLen = sizeof(output_terminator_) - 1; + // Skip, if we read just kTerminatorLen bytes, because Addr2Line output + // should consist at least of two pairs of lines: + // 1. First one, corresponding to given offset to be symbolized + // (may be equal to output_terminator_, if offset is not valid). + // 2. Second one for output_terminator_, itself to mark the end of output. + if (length <= kTerminatorLen) return false; + // Addr2Line output should end up with output_terminator_. + return !internal_memcmp(buffer + length - kTerminatorLen, + output_terminator_, kTerminatorLen); +} + +class Addr2LinePool final : public SymbolizerTool { + public: + explicit Addr2LinePool(const char *addr2line_path, + LowLevelAllocator *allocator) + : addr2line_path_(addr2line_path), allocator_(allocator) { + addr2line_pool_.reserve(16); + } + + bool SymbolizePC(uptr addr, SymbolizedStack *stack) override { + if (const char *buf = + SendCommand(stack->info.module, stack->info.module_offset)) { + ParseSymbolizePCOutput(buf, stack); + return true; + } + return false; + } + + bool SymbolizeData(uptr addr, DataInfo *info) override { + return false; + } + + private: + const char *SendCommand(const char *module_name, uptr module_offset) { + Addr2LineProcess *addr2line = 0; + for (uptr i = 0; i < addr2line_pool_.size(); ++i) { + if (0 == + internal_strcmp(module_name, addr2line_pool_[i]->module_name())) { + addr2line = addr2line_pool_[i]; + break; + } + } + if (!addr2line) { + addr2line = + new(*allocator_) Addr2LineProcess(addr2line_path_, module_name); + addr2line_pool_.push_back(addr2line); + } + CHECK_EQ(0, internal_strcmp(module_name, addr2line->module_name())); + char buffer[kBufferSize]; + internal_snprintf(buffer, kBufferSize, "0x%zx\n0x%zx\n", + module_offset, dummy_address_); + return addr2line->SendCommand(buffer); + } + + static const uptr kBufferSize = 64; + const char *addr2line_path_; + LowLevelAllocator *allocator_; + InternalMmapVector<Addr2LineProcess*> addr2line_pool_; + static const uptr dummy_address_ = + FIRST_32_SECOND_64(UINT32_MAX, UINT64_MAX); +}; + +# if SANITIZER_SUPPORTS_WEAK_HOOKS +extern "C" { +SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE bool +__sanitizer_symbolize_code(const char *ModuleName, u64 ModuleOffset, + char *Buffer, int MaxLength); +SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE bool +__sanitizer_symbolize_data(const char *ModuleName, u64 ModuleOffset, + char *Buffer, int MaxLength); +SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE void +__sanitizer_symbolize_flush(); +SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE int +__sanitizer_symbolize_demangle(const char *Name, char *Buffer, int MaxLength); +SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE bool +__sanitizer_symbolize_set_demangle(bool Demangle); +SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE bool +__sanitizer_symbolize_set_inline_frames(bool InlineFrames); +} // extern "C" + +class InternalSymbolizer final : public SymbolizerTool { + public: + static InternalSymbolizer *get(LowLevelAllocator *alloc) { + if (__sanitizer_symbolize_set_demangle) + CHECK(__sanitizer_symbolize_set_demangle(common_flags()->demangle)); + if (__sanitizer_symbolize_set_inline_frames) + CHECK(__sanitizer_symbolize_set_inline_frames( + common_flags()->symbolize_inline_frames)); + if (__sanitizer_symbolize_code && __sanitizer_symbolize_data) + return new (*alloc) InternalSymbolizer(); + return 0; + } + + bool SymbolizePC(uptr addr, SymbolizedStack *stack) override { + bool result = __sanitizer_symbolize_code( + stack->info.module, stack->info.module_offset, buffer_, kBufferSize); + if (result) + ParseSymbolizePCOutput(buffer_, stack); + return result; + } + + bool SymbolizeData(uptr addr, DataInfo *info) override { + bool result = __sanitizer_symbolize_data(info->module, info->module_offset, + buffer_, kBufferSize); + if (result) { + ParseSymbolizeDataOutput(buffer_, info); + info->start += (addr - info->module_offset); // Add the base address. + } + return result; + } + + void Flush() override { + if (__sanitizer_symbolize_flush) + __sanitizer_symbolize_flush(); + } + + const char *Demangle(const char *name) override { + if (__sanitizer_symbolize_demangle) { + for (uptr res_length = 1024; + res_length <= InternalSizeClassMap::kMaxSize;) { + char *res_buff = static_cast<char *>(InternalAlloc(res_length)); + uptr req_length = + __sanitizer_symbolize_demangle(name, res_buff, res_length); + if (req_length > res_length) { + res_length = req_length + 1; + InternalFree(res_buff); + continue; + } + return res_buff; + } + } + return name; + } + + private: + InternalSymbolizer() {} + + static const int kBufferSize = 16 * 1024; + char buffer_[kBufferSize]; +}; +# else // SANITIZER_SUPPORTS_WEAK_HOOKS + +class InternalSymbolizer final : public SymbolizerTool { + public: + static InternalSymbolizer *get(LowLevelAllocator *alloc) { return 0; } +}; + +# endif // SANITIZER_SUPPORTS_WEAK_HOOKS + +const char *Symbolizer::PlatformDemangle(const char *name) { + return DemangleSwiftAndCXX(name); +} + +static SymbolizerTool *ChooseExternalSymbolizer(LowLevelAllocator *allocator) { + const char *path = common_flags()->external_symbolizer_path; + + if (path && internal_strchr(path, '%')) { + char *new_path = (char *)InternalAlloc(kMaxPathLength); + SubstituteForFlagValue(path, new_path, kMaxPathLength); + path = new_path; + } + + const char *binary_name = path ? StripModuleName(path) : ""; + static const char kLLVMSymbolizerPrefix[] = "llvm-symbolizer"; + if (path && path[0] == '\0') { + VReport(2, "External symbolizer is explicitly disabled.\n"); + return nullptr; + } else if (!internal_strncmp(binary_name, kLLVMSymbolizerPrefix, + internal_strlen(kLLVMSymbolizerPrefix))) { + VReport(2, "Using llvm-symbolizer at user-specified path: %s\n", path); + return new(*allocator) LLVMSymbolizer(path, allocator); + } else if (!internal_strcmp(binary_name, "atos")) { +#if SANITIZER_MAC + VReport(2, "Using atos at user-specified path: %s\n", path); + return new(*allocator) AtosSymbolizer(path, allocator); +#else // SANITIZER_MAC + Report("ERROR: Using `atos` is only supported on Darwin.\n"); + Die(); +#endif // SANITIZER_MAC + } else if (!internal_strcmp(binary_name, "addr2line")) { + VReport(2, "Using addr2line at user-specified path: %s\n", path); + return new(*allocator) Addr2LinePool(path, allocator); + } else if (path) { + Report("ERROR: External symbolizer path is set to '%s' which isn't " + "a known symbolizer. Please set the path to the llvm-symbolizer " + "binary or other known tool.\n", path); + Die(); + } + + // Otherwise symbolizer program is unknown, let's search $PATH + CHECK(path == nullptr); +#if SANITIZER_MAC + if (const char *found_path = FindPathToBinary("atos")) { + VReport(2, "Using atos found at: %s\n", found_path); + return new(*allocator) AtosSymbolizer(found_path, allocator); + } +#endif // SANITIZER_MAC + if (const char *found_path = FindPathToBinary("llvm-symbolizer")) { + VReport(2, "Using llvm-symbolizer found at: %s\n", found_path); + return new(*allocator) LLVMSymbolizer(found_path, allocator); + } + if (common_flags()->allow_addr2line) { + if (const char *found_path = FindPathToBinary("addr2line")) { + VReport(2, "Using addr2line found at: %s\n", found_path); + return new(*allocator) Addr2LinePool(found_path, allocator); + } + } + return nullptr; +} + +static void ChooseSymbolizerTools(IntrusiveList<SymbolizerTool> *list, + LowLevelAllocator *allocator) { + if (!common_flags()->symbolize) { + VReport(2, "Symbolizer is disabled.\n"); + return; + } + if (IsAllocatorOutOfMemory()) { + VReport(2, "Cannot use internal symbolizer: out of memory\n"); + } else if (SymbolizerTool *tool = InternalSymbolizer::get(allocator)) { + VReport(2, "Using internal symbolizer.\n"); + list->push_back(tool); + return; + } + if (SymbolizerTool *tool = LibbacktraceSymbolizer::get(allocator)) { + VReport(2, "Using libbacktrace symbolizer.\n"); + list->push_back(tool); + return; + } + + if (SymbolizerTool *tool = ChooseExternalSymbolizer(allocator)) { + list->push_back(tool); + } + +#if SANITIZER_MAC + VReport(2, "Using dladdr symbolizer.\n"); + list->push_back(new(*allocator) DlAddrSymbolizer()); +#endif // SANITIZER_MAC +} + +Symbolizer *Symbolizer::PlatformInit() { + IntrusiveList<SymbolizerTool> list; + list.clear(); + ChooseSymbolizerTools(&list, &symbolizer_allocator_); + return new(symbolizer_allocator_) Symbolizer(list); +} + +void Symbolizer::LateInitialize() { + Symbolizer::GetOrInit(); + InitializeSwiftDemangler(); +} + +} // namespace __sanitizer + +#endif // SANITIZER_POSIX diff --git a/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_symbolizer_report.cpp b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_symbolizer_report.cpp new file mode 100644 index 0000000000..ac855c8be1 --- /dev/null +++ b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_symbolizer_report.cpp @@ -0,0 +1,298 @@ +//===-- sanitizer_symbolizer_report.cpp -----------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +/// +/// This file is shared between AddressSanitizer and other sanitizer run-time +/// libraries and implements symbolized reports related functions. +/// +//===----------------------------------------------------------------------===// + +#include "sanitizer_common.h" +#include "sanitizer_file.h" +#include "sanitizer_flags.h" +#include "sanitizer_procmaps.h" +#include "sanitizer_report_decorator.h" +#include "sanitizer_stacktrace.h" +#include "sanitizer_stacktrace_printer.h" +#include "sanitizer_symbolizer.h" + +#if SANITIZER_POSIX +# include "sanitizer_posix.h" +# include <sys/mman.h> +#endif + +namespace __sanitizer { + +#if !SANITIZER_GO +void ReportErrorSummary(const char *error_type, const AddressInfo &info, + const char *alt_tool_name) { + if (!common_flags()->print_summary) return; + InternalScopedString buff; + buff.append("%s ", error_type); + RenderFrame(&buff, "%L %F", 0, info.address, &info, + common_flags()->symbolize_vs_style, + common_flags()->strip_path_prefix); + ReportErrorSummary(buff.data(), alt_tool_name); +} +#endif + +#if !SANITIZER_FUCHSIA + +bool ReportFile::SupportsColors() { + SpinMutexLock l(mu); + ReopenIfNecessary(); + return SupportsColoredOutput(fd); +} + +static inline bool ReportSupportsColors() { + return report_file.SupportsColors(); +} + +#else // SANITIZER_FUCHSIA + +// Fuchsia's logs always go through post-processing that handles colorization. +static inline bool ReportSupportsColors() { return true; } + +#endif // !SANITIZER_FUCHSIA + +bool ColorizeReports() { + // FIXME: Add proper Windows support to AnsiColorDecorator and re-enable color + // printing on Windows. + if (SANITIZER_WINDOWS) + return false; + + const char *flag = common_flags()->color; + return internal_strcmp(flag, "always") == 0 || + (internal_strcmp(flag, "auto") == 0 && ReportSupportsColors()); +} + +void ReportErrorSummary(const char *error_type, const StackTrace *stack, + const char *alt_tool_name) { +#if !SANITIZER_GO + if (!common_flags()->print_summary) + return; + if (stack->size == 0) { + ReportErrorSummary(error_type); + return; + } + // Currently, we include the first stack frame into the report summary. + // Maybe sometimes we need to choose another frame (e.g. skip memcpy/etc). + uptr pc = StackTrace::GetPreviousInstructionPc(stack->trace[0]); + SymbolizedStack *frame = Symbolizer::GetOrInit()->SymbolizePC(pc); + ReportErrorSummary(error_type, frame->info, alt_tool_name); + frame->ClearAll(); +#endif +} + +void ReportMmapWriteExec(int prot, int flags) { +#if SANITIZER_POSIX && (!SANITIZER_GO && !SANITIZER_ANDROID) + int pflags = (PROT_WRITE | PROT_EXEC); + if ((prot & pflags) != pflags) + return; + +# if SANITIZER_MAC && defined(MAP_JIT) + if ((flags & MAP_JIT) == MAP_JIT) + return; +# endif + + ScopedErrorReportLock l; + SanitizerCommonDecorator d; + + InternalMmapVector<BufferedStackTrace> stack_buffer(1); + BufferedStackTrace *stack = stack_buffer.data(); + stack->Reset(); + uptr top = 0; + uptr bottom = 0; + GET_CALLER_PC_BP_SP; + (void)sp; + bool fast = common_flags()->fast_unwind_on_fatal; + if (StackTrace::WillUseFastUnwind(fast)) { + GetThreadStackTopAndBottom(false, &top, &bottom); + stack->Unwind(kStackTraceMax, pc, bp, nullptr, top, bottom, true); + } else { + stack->Unwind(kStackTraceMax, pc, 0, nullptr, 0, 0, false); + } + + Printf("%s", d.Warning()); + Report("WARNING: %s: writable-executable page usage\n", SanitizerToolName); + Printf("%s", d.Default()); + + stack->Print(); + ReportErrorSummary("w-and-x-usage", stack); +#endif +} + +#if !SANITIZER_FUCHSIA && !SANITIZER_GO +void StartReportDeadlySignal() { + // Write the first message using fd=2, just in case. + // It may actually fail to write in case stderr is closed. + CatastrophicErrorWrite(SanitizerToolName, internal_strlen(SanitizerToolName)); + static const char kDeadlySignal[] = ":DEADLYSIGNAL\n"; + CatastrophicErrorWrite(kDeadlySignal, sizeof(kDeadlySignal) - 1); +} + +static void MaybeReportNonExecRegion(uptr pc) { +#if SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD + MemoryMappingLayout proc_maps(/*cache_enabled*/ true); + MemoryMappedSegment segment; + while (proc_maps.Next(&segment)) { + if (pc >= segment.start && pc < segment.end && !segment.IsExecutable()) + Report("Hint: PC is at a non-executable region. Maybe a wild jump?\n"); + } +#endif +} + +static void PrintMemoryByte(InternalScopedString *str, const char *before, + u8 byte) { + SanitizerCommonDecorator d; + str->append("%s%s%x%x%s ", before, d.MemoryByte(), byte >> 4, byte & 15, + d.Default()); +} + +static void MaybeDumpInstructionBytes(uptr pc) { + if (!common_flags()->dump_instruction_bytes || (pc < GetPageSizeCached())) + return; + InternalScopedString str; + str.append("First 16 instruction bytes at pc: "); + if (IsAccessibleMemoryRange(pc, 16)) { + for (int i = 0; i < 16; ++i) { + PrintMemoryByte(&str, "", ((u8 *)pc)[i]); + } + str.append("\n"); + } else { + str.append("unaccessible\n"); + } + Report("%s", str.data()); +} + +static void MaybeDumpRegisters(void *context) { + if (!common_flags()->dump_registers) return; + SignalContext::DumpAllRegisters(context); +} + +static void ReportStackOverflowImpl(const SignalContext &sig, u32 tid, + UnwindSignalStackCallbackType unwind, + const void *unwind_context) { + SanitizerCommonDecorator d; + Printf("%s", d.Warning()); + static const char kDescription[] = "stack-overflow"; + Report("ERROR: %s: %s on address %p (pc %p bp %p sp %p T%d)\n", + SanitizerToolName, kDescription, (void *)sig.addr, (void *)sig.pc, + (void *)sig.bp, (void *)sig.sp, tid); + Printf("%s", d.Default()); + InternalMmapVector<BufferedStackTrace> stack_buffer(1); + BufferedStackTrace *stack = stack_buffer.data(); + stack->Reset(); + unwind(sig, unwind_context, stack); + stack->Print(); + ReportErrorSummary(kDescription, stack); +} + +static void ReportDeadlySignalImpl(const SignalContext &sig, u32 tid, + UnwindSignalStackCallbackType unwind, + const void *unwind_context) { + SanitizerCommonDecorator d; + Printf("%s", d.Warning()); + const char *description = sig.Describe(); + if (sig.is_memory_access && !sig.is_true_faulting_addr) + Report("ERROR: %s: %s on unknown address (pc %p bp %p sp %p T%d)\n", + SanitizerToolName, description, (void *)sig.pc, (void *)sig.bp, + (void *)sig.sp, tid); + else + Report("ERROR: %s: %s on unknown address %p (pc %p bp %p sp %p T%d)\n", + SanitizerToolName, description, (void *)sig.addr, (void *)sig.pc, + (void *)sig.bp, (void *)sig.sp, tid); + Printf("%s", d.Default()); + if (sig.pc < GetPageSizeCached()) + Report("Hint: pc points to the zero page.\n"); + if (sig.is_memory_access) { + const char *access_type = + sig.write_flag == SignalContext::Write + ? "WRITE" + : (sig.write_flag == SignalContext::Read ? "READ" : "UNKNOWN"); + Report("The signal is caused by a %s memory access.\n", access_type); + if (!sig.is_true_faulting_addr) + Report("Hint: this fault was caused by a dereference of a high value " + "address (see register values below). Disassemble the provided " + "pc to learn which register was used.\n"); + else if (sig.addr < GetPageSizeCached()) + Report("Hint: address points to the zero page.\n"); + } + MaybeReportNonExecRegion(sig.pc); + InternalMmapVector<BufferedStackTrace> stack_buffer(1); + BufferedStackTrace *stack = stack_buffer.data(); + stack->Reset(); + unwind(sig, unwind_context, stack); + stack->Print(); + MaybeDumpInstructionBytes(sig.pc); + MaybeDumpRegisters(sig.context); + Printf("%s can not provide additional info.\n", SanitizerToolName); + ReportErrorSummary(description, stack); +} + +void ReportDeadlySignal(const SignalContext &sig, u32 tid, + UnwindSignalStackCallbackType unwind, + const void *unwind_context) { + if (sig.IsStackOverflow()) + ReportStackOverflowImpl(sig, tid, unwind, unwind_context); + else + ReportDeadlySignalImpl(sig, tid, unwind, unwind_context); +} + +void HandleDeadlySignal(void *siginfo, void *context, u32 tid, + UnwindSignalStackCallbackType unwind, + const void *unwind_context) { + StartReportDeadlySignal(); + ScopedErrorReportLock rl; + SignalContext sig(siginfo, context); + ReportDeadlySignal(sig, tid, unwind, unwind_context); + Report("ABORTING\n"); + Die(); +} + +#endif // !SANITIZER_FUCHSIA && !SANITIZER_GO + +atomic_uintptr_t ScopedErrorReportLock::reporting_thread_ = {0}; +StaticSpinMutex ScopedErrorReportLock::mutex_; + +void ScopedErrorReportLock::Lock() { + uptr current = GetThreadSelf(); + for (;;) { + uptr expected = 0; + if (atomic_compare_exchange_strong(&reporting_thread_, &expected, current, + memory_order_relaxed)) { + // We've claimed reporting_thread so proceed. + mutex_.Lock(); + return; + } + + if (expected == current) { + // This is either asynch signal or nested error during error reporting. + // Fail simple to avoid deadlocks in Report(). + + // Can't use Report() here because of potential deadlocks in nested + // signal handlers. + CatastrophicErrorWrite(SanitizerToolName, + internal_strlen(SanitizerToolName)); + static const char msg[] = ": nested bug in the same thread, aborting.\n"; + CatastrophicErrorWrite(msg, sizeof(msg) - 1); + + internal__exit(common_flags()->exitcode); + } + + internal_sched_yield(); + } +} + +void ScopedErrorReportLock::Unlock() { + mutex_.Unlock(); + atomic_store_relaxed(&reporting_thread_, 0); +} + +void ScopedErrorReportLock::CheckLocked() { mutex_.CheckLocked(); } + +} // namespace __sanitizer diff --git a/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_symbolizer_win.cpp b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_symbolizer_win.cpp new file mode 100644 index 0000000000..c647ab107e --- /dev/null +++ b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_symbolizer_win.cpp @@ -0,0 +1,326 @@ +//===-- sanitizer_symbolizer_win.cpp --------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file is shared between AddressSanitizer and ThreadSanitizer +// run-time libraries. +// Windows-specific implementation of symbolizer parts. +//===----------------------------------------------------------------------===// + +#include "sanitizer_platform.h" +#if SANITIZER_WINDOWS + +#include "sanitizer_dbghelp.h" +#include "sanitizer_symbolizer_internal.h" + +namespace __sanitizer { + +decltype(::StackWalk64) *StackWalk64; +decltype(::SymCleanup) *SymCleanup; +decltype(::SymFromAddr) *SymFromAddr; +decltype(::SymFunctionTableAccess64) *SymFunctionTableAccess64; +decltype(::SymGetLineFromAddr64) *SymGetLineFromAddr64; +decltype(::SymGetModuleBase64) *SymGetModuleBase64; +decltype(::SymGetSearchPathW) *SymGetSearchPathW; +decltype(::SymInitialize) *SymInitialize; +decltype(::SymSetOptions) *SymSetOptions; +decltype(::SymSetSearchPathW) *SymSetSearchPathW; +decltype(::UnDecorateSymbolName) *UnDecorateSymbolName; + +namespace { + +class WinSymbolizerTool final : public SymbolizerTool { + public: + // The constructor is provided to avoid synthesized memsets. + WinSymbolizerTool() {} + + bool SymbolizePC(uptr addr, SymbolizedStack *stack) override; + bool SymbolizeData(uptr addr, DataInfo *info) override { + return false; + } + const char *Demangle(const char *name) override; +}; + +bool is_dbghelp_initialized = false; + +bool TrySymInitialize() { + SymSetOptions(SYMOPT_DEFERRED_LOADS | SYMOPT_UNDNAME | SYMOPT_LOAD_LINES); + return SymInitialize(GetCurrentProcess(), 0, TRUE); + // FIXME: We don't call SymCleanup() on exit yet - should we? +} + +} // namespace + +// Initializes DbgHelp library, if it's not yet initialized. Calls to this +// function should be synchronized with respect to other calls to DbgHelp API +// (e.g. from WinSymbolizerTool). +void InitializeDbgHelpIfNeeded() { + if (is_dbghelp_initialized) + return; + + HMODULE dbghelp = LoadLibraryA("dbghelp.dll"); + CHECK(dbghelp && "failed to load dbghelp.dll"); + +#define DBGHELP_IMPORT(name) \ + do { \ + name = \ + reinterpret_cast<decltype(::name) *>(GetProcAddress(dbghelp, #name)); \ + CHECK(name != nullptr); \ + } while (0) + DBGHELP_IMPORT(StackWalk64); + DBGHELP_IMPORT(SymCleanup); + DBGHELP_IMPORT(SymFromAddr); + DBGHELP_IMPORT(SymFunctionTableAccess64); + DBGHELP_IMPORT(SymGetLineFromAddr64); + DBGHELP_IMPORT(SymGetModuleBase64); + DBGHELP_IMPORT(SymGetSearchPathW); + DBGHELP_IMPORT(SymInitialize); + DBGHELP_IMPORT(SymSetOptions); + DBGHELP_IMPORT(SymSetSearchPathW); + DBGHELP_IMPORT(UnDecorateSymbolName); +#undef DBGHELP_IMPORT + + if (!TrySymInitialize()) { + // OK, maybe the client app has called SymInitialize already. + // That's a bit unfortunate for us as all the DbgHelp functions are + // single-threaded and we can't coordinate with the app. + // FIXME: Can we stop the other threads at this point? + // Anyways, we have to reconfigure stuff to make sure that SymInitialize + // has all the appropriate options set. + // Cross our fingers and reinitialize DbgHelp. + Report("*** WARNING: Failed to initialize DbgHelp! ***\n"); + Report("*** Most likely this means that the app is already ***\n"); + Report("*** using DbgHelp, possibly with incompatible flags. ***\n"); + Report("*** Due to technical reasons, symbolization might crash ***\n"); + Report("*** or produce wrong results. ***\n"); + SymCleanup(GetCurrentProcess()); + TrySymInitialize(); + } + is_dbghelp_initialized = true; + + // When an executable is run from a location different from the one where it + // was originally built, we may not see the nearby PDB files. + // To work around this, let's append the directory of the main module + // to the symbol search path. All the failures below are not fatal. + const size_t kSymPathSize = 2048; + static wchar_t path_buffer[kSymPathSize + 1 + MAX_PATH]; + if (!SymGetSearchPathW(GetCurrentProcess(), path_buffer, kSymPathSize)) { + Report("*** WARNING: Failed to SymGetSearchPathW ***\n"); + return; + } + size_t sz = wcslen(path_buffer); + if (sz) { + CHECK_EQ(0, wcscat_s(path_buffer, L";")); + sz++; + } + DWORD res = GetModuleFileNameW(NULL, path_buffer + sz, MAX_PATH); + if (res == 0 || res == MAX_PATH) { + Report("*** WARNING: Failed to getting the EXE directory ***\n"); + return; + } + // Write the zero character in place of the last backslash to get the + // directory of the main module at the end of path_buffer. + wchar_t *last_bslash = wcsrchr(path_buffer + sz, L'\\'); + CHECK_NE(last_bslash, 0); + *last_bslash = L'\0'; + if (!SymSetSearchPathW(GetCurrentProcess(), path_buffer)) { + Report("*** WARNING: Failed to SymSetSearchPathW\n"); + return; + } +} + +bool WinSymbolizerTool::SymbolizePC(uptr addr, SymbolizedStack *frame) { + InitializeDbgHelpIfNeeded(); + + // See https://docs.microsoft.com/en-us/windows/win32/debug/retrieving-symbol-information-by-address + InternalMmapVector<char> buffer(sizeof(SYMBOL_INFO) + + MAX_SYM_NAME * sizeof(CHAR)); + PSYMBOL_INFO symbol = (PSYMBOL_INFO)&buffer[0]; + symbol->SizeOfStruct = sizeof(SYMBOL_INFO); + symbol->MaxNameLen = MAX_SYM_NAME; + DWORD64 offset = 0; + BOOL got_objname = SymFromAddr(GetCurrentProcess(), + (DWORD64)addr, &offset, symbol); + if (!got_objname) + return false; + + DWORD unused; + IMAGEHLP_LINE64 line_info; + line_info.SizeOfStruct = sizeof(IMAGEHLP_LINE64); + BOOL got_fileline = SymGetLineFromAddr64(GetCurrentProcess(), (DWORD64)addr, + &unused, &line_info); + frame->info.function = internal_strdup(symbol->Name); + frame->info.function_offset = (uptr)offset; + if (got_fileline) { + frame->info.file = internal_strdup(line_info.FileName); + frame->info.line = line_info.LineNumber; + } + // Only consider this a successful symbolization attempt if we got file info. + // Otherwise, try llvm-symbolizer. + return got_fileline; +} + +const char *WinSymbolizerTool::Demangle(const char *name) { + CHECK(is_dbghelp_initialized); + static char demangle_buffer[1000]; + if (name[0] == '\01' && + UnDecorateSymbolName(name + 1, demangle_buffer, sizeof(demangle_buffer), + UNDNAME_NAME_ONLY)) + return demangle_buffer; + else + return name; +} + +const char *Symbolizer::PlatformDemangle(const char *name) { + return name; +} + +namespace { +struct ScopedHandle { + ScopedHandle() : h_(nullptr) {} + explicit ScopedHandle(HANDLE h) : h_(h) {} + ~ScopedHandle() { + if (h_) + ::CloseHandle(h_); + } + HANDLE get() { return h_; } + HANDLE *receive() { return &h_; } + HANDLE release() { + HANDLE h = h_; + h_ = nullptr; + return h; + } + HANDLE h_; +}; +} // namespace + +bool SymbolizerProcess::StartSymbolizerSubprocess() { + // Create inherited pipes for stdin and stdout. + ScopedHandle stdin_read, stdin_write; + ScopedHandle stdout_read, stdout_write; + SECURITY_ATTRIBUTES attrs; + attrs.nLength = sizeof(SECURITY_ATTRIBUTES); + attrs.bInheritHandle = TRUE; + attrs.lpSecurityDescriptor = nullptr; + if (!::CreatePipe(stdin_read.receive(), stdin_write.receive(), &attrs, 0) || + !::CreatePipe(stdout_read.receive(), stdout_write.receive(), &attrs, 0)) { + VReport(2, "WARNING: %s CreatePipe failed (error code: %d)\n", + SanitizerToolName, path_, GetLastError()); + return false; + } + + // Don't inherit the writing end of stdin or the reading end of stdout. + if (!SetHandleInformation(stdin_write.get(), HANDLE_FLAG_INHERIT, 0) || + !SetHandleInformation(stdout_read.get(), HANDLE_FLAG_INHERIT, 0)) { + VReport(2, "WARNING: %s SetHandleInformation failed (error code: %d)\n", + SanitizerToolName, path_, GetLastError()); + return false; + } + + // Compute the command line. Wrap double quotes around everything. + const char *argv[kArgVMax]; + GetArgV(path_, argv); + InternalScopedString command_line; + for (int i = 0; argv[i]; i++) { + const char *arg = argv[i]; + int arglen = internal_strlen(arg); + // Check that tool command lines are simple and that complete escaping is + // unnecessary. + CHECK(!internal_strchr(arg, '"') && "quotes in args unsupported"); + CHECK(!internal_strstr(arg, "\\\\") && + "double backslashes in args unsupported"); + CHECK(arglen > 0 && arg[arglen - 1] != '\\' && + "args ending in backslash and empty args unsupported"); + command_line.append("\"%s\" ", arg); + } + VReport(3, "Launching symbolizer command: %s\n", command_line.data()); + + // Launch llvm-symbolizer with stdin and stdout redirected. + STARTUPINFOA si; + memset(&si, 0, sizeof(si)); + si.cb = sizeof(si); + si.dwFlags |= STARTF_USESTDHANDLES; + si.hStdInput = stdin_read.get(); + si.hStdOutput = stdout_write.get(); + PROCESS_INFORMATION pi; + memset(&pi, 0, sizeof(pi)); + if (!CreateProcessA(path_, // Executable + command_line.data(), // Command line + nullptr, // Process handle not inheritable + nullptr, // Thread handle not inheritable + TRUE, // Set handle inheritance to TRUE + 0, // Creation flags + nullptr, // Use parent's environment block + nullptr, // Use parent's starting directory + &si, &pi)) { + VReport(2, "WARNING: %s failed to create process for %s (error code: %d)\n", + SanitizerToolName, path_, GetLastError()); + return false; + } + + // Process creation succeeded, so transfer handle ownership into the fields. + input_fd_ = stdout_read.release(); + output_fd_ = stdin_write.release(); + + // The llvm-symbolizer process is responsible for quitting itself when the + // stdin pipe is closed, so we don't need these handles. Close them to prevent + // leaks. If we ever want to try to kill the symbolizer process from the + // parent, we'll want to hang on to these handles. + CloseHandle(pi.hProcess); + CloseHandle(pi.hThread); + return true; +} + +static void ChooseSymbolizerTools(IntrusiveList<SymbolizerTool> *list, + LowLevelAllocator *allocator) { + if (!common_flags()->symbolize) { + VReport(2, "Symbolizer is disabled.\n"); + return; + } + + // Add llvm-symbolizer. + const char *user_path = common_flags()->external_symbolizer_path; + + if (user_path && internal_strchr(user_path, '%')) { + char *new_path = (char *)InternalAlloc(kMaxPathLength); + SubstituteForFlagValue(user_path, new_path, kMaxPathLength); + user_path = new_path; + } + + const char *path = + user_path ? user_path : FindPathToBinary("llvm-symbolizer.exe"); + if (path) { + VReport(2, "Using llvm-symbolizer at %spath: %s\n", + user_path ? "user-specified " : "", path); + list->push_back(new(*allocator) LLVMSymbolizer(path, allocator)); + } else { + if (user_path && user_path[0] == '\0') { + VReport(2, "External symbolizer is explicitly disabled.\n"); + } else { + VReport(2, "External symbolizer is not present.\n"); + } + } + + // Add the dbghelp based symbolizer. + list->push_back(new(*allocator) WinSymbolizerTool()); +} + +Symbolizer *Symbolizer::PlatformInit() { + IntrusiveList<SymbolizerTool> list; + list.clear(); + ChooseSymbolizerTools(&list, &symbolizer_allocator_); + + return new(symbolizer_allocator_) Symbolizer(list); +} + +void Symbolizer::LateInitialize() { + Symbolizer::GetOrInit(); +} + +} // namespace __sanitizer + +#endif // _WIN32 diff --git a/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_syscall_generic.inc b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_syscall_generic.inc new file mode 100644 index 0000000000..8829985b5b --- /dev/null +++ b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_syscall_generic.inc @@ -0,0 +1,38 @@ +//===-- sanitizer_syscall_generic.inc ---------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// Generic implementations of internal_syscall* and internal_iserror. +// +//===----------------------------------------------------------------------===// + +// NetBSD uses libc calls directly +#if !SANITIZER_NETBSD + +#if SANITIZER_FREEBSD || SANITIZER_MAC || SANITIZER_SOLARIS +# define SYSCALL(name) SYS_ ## name +#else +# define SYSCALL(name) __NR_ ## name +#endif + +#if defined(__x86_64__) && (SANITIZER_FREEBSD || SANITIZER_MAC) +# define internal_syscall __syscall +# else +# define internal_syscall syscall +#endif + +#endif + +bool internal_iserror(uptr retval, int *rverrno) { + if (retval == (uptr)-1) { + if (rverrno) + *rverrno = errno; + return true; + } else { + return false; + } +} diff --git a/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_syscall_linux_aarch64.inc b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_syscall_linux_aarch64.inc new file mode 100644 index 0000000000..56c5e99220 --- /dev/null +++ b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_syscall_linux_aarch64.inc @@ -0,0 +1,137 @@ +//===-- sanitizer_syscall_linux_aarch64.inc --------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// Implementations of internal_syscall and internal_iserror for Linux/aarch64. +// +//===----------------------------------------------------------------------===// + +#define SYSCALL(name) __NR_ ## name + +static uptr __internal_syscall(u64 nr) { + register u64 x8 asm("x8") = nr; + register u64 x0 asm("x0"); + asm volatile("svc 0" + : "=r"(x0) + : "r"(x8) + : "memory", "cc"); + return x0; +} +#define __internal_syscall0(n) \ + (__internal_syscall)(n) + +static uptr __internal_syscall(u64 nr, u64 arg1) { + register u64 x8 asm("x8") = nr; + register u64 x0 asm("x0") = arg1; + asm volatile("svc 0" + : "=r"(x0) + : "r"(x8), "0"(x0) + : "memory", "cc"); + return x0; +} +#define __internal_syscall1(n, a1) \ + (__internal_syscall)(n, (u64)(a1)) + +static uptr __internal_syscall(u64 nr, u64 arg1, long arg2) { + register u64 x8 asm("x8") = nr; + register u64 x0 asm("x0") = arg1; + register u64 x1 asm("x1") = arg2; + asm volatile("svc 0" + : "=r"(x0) + : "r"(x8), "0"(x0), "r"(x1) + : "memory", "cc"); + return x0; +} +#define __internal_syscall2(n, a1, a2) \ + (__internal_syscall)(n, (u64)(a1), (long)(a2)) + +static uptr __internal_syscall(u64 nr, u64 arg1, long arg2, long arg3) { + register u64 x8 asm("x8") = nr; + register u64 x0 asm("x0") = arg1; + register u64 x1 asm("x1") = arg2; + register u64 x2 asm("x2") = arg3; + asm volatile("svc 0" + : "=r"(x0) + : "r"(x8), "0"(x0), "r"(x1), "r"(x2) + : "memory", "cc"); + return x0; +} +#define __internal_syscall3(n, a1, a2, a3) \ + (__internal_syscall)(n, (u64)(a1), (long)(a2), (long)(a3)) + +static uptr __internal_syscall(u64 nr, u64 arg1, long arg2, long arg3, + u64 arg4) { + register u64 x8 asm("x8") = nr; + register u64 x0 asm("x0") = arg1; + register u64 x1 asm("x1") = arg2; + register u64 x2 asm("x2") = arg3; + register u64 x3 asm("x3") = arg4; + asm volatile("svc 0" + : "=r"(x0) + : "r"(x8), "0"(x0), "r"(x1), "r"(x2), "r"(x3) + : "memory", "cc"); + return x0; +} +#define __internal_syscall4(n, a1, a2, a3, a4) \ + (__internal_syscall)(n, (u64)(a1), (long)(a2), (long)(a3), (long)(a4)) + +static uptr __internal_syscall(u64 nr, u64 arg1, long arg2, long arg3, + u64 arg4, long arg5) { + register u64 x8 asm("x8") = nr; + register u64 x0 asm("x0") = arg1; + register u64 x1 asm("x1") = arg2; + register u64 x2 asm("x2") = arg3; + register u64 x3 asm("x3") = arg4; + register u64 x4 asm("x4") = arg5; + asm volatile("svc 0" + : "=r"(x0) + : "r"(x8), "0"(x0), "r"(x1), "r"(x2), "r"(x3), "r"(x4) + : "memory", "cc"); + return x0; +} +#define __internal_syscall5(n, a1, a2, a3, a4, a5) \ + (__internal_syscall)(n, (u64)(a1), (long)(a2), (long)(a3), (long)(a4), \ + (u64)(a5)) + +static uptr __internal_syscall(u64 nr, u64 arg1, long arg2, long arg3, + u64 arg4, long arg5, long arg6) { + register u64 x8 asm("x8") = nr; + register u64 x0 asm("x0") = arg1; + register u64 x1 asm("x1") = arg2; + register u64 x2 asm("x2") = arg3; + register u64 x3 asm("x3") = arg4; + register u64 x4 asm("x4") = arg5; + register u64 x5 asm("x5") = arg6; + asm volatile("svc 0" + : "=r"(x0) + : "r"(x8), "0"(x0), "r"(x1), "r"(x2), "r"(x3), "r"(x4), "r"(x5) + : "memory", "cc"); + return x0; +} +#define __internal_syscall6(n, a1, a2, a3, a4, a5, a6) \ + (__internal_syscall)(n, (u64)(a1), (long)(a2), (long)(a3), (long)(a4), \ + (u64)(a5), (long)(a6)) + +#define __SYSCALL_NARGS_X(a1, a2, a3, a4, a5, a6, a7, a8, n, ...) n +#define __SYSCALL_NARGS(...) \ + __SYSCALL_NARGS_X(__VA_ARGS__, 7, 6, 5, 4, 3, 2, 1, 0, ) +#define __SYSCALL_CONCAT_X(a, b) a##b +#define __SYSCALL_CONCAT(a, b) __SYSCALL_CONCAT_X(a, b) +#define __SYSCALL_DISP(b, ...) \ + __SYSCALL_CONCAT(b, __SYSCALL_NARGS(__VA_ARGS__))(__VA_ARGS__) + +#define internal_syscall(...) __SYSCALL_DISP(__internal_syscall, __VA_ARGS__) + +// Helper function used to avoid cobbler errno. +bool internal_iserror(uptr retval, int *rverrno) { + if (retval >= (uptr)-4095) { + if (rverrno) + *rverrno = -retval; + return true; + } + return false; +} diff --git a/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_syscall_linux_arm.inc b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_syscall_linux_arm.inc new file mode 100644 index 0000000000..121a9445b4 --- /dev/null +++ b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_syscall_linux_arm.inc @@ -0,0 +1,137 @@ +//===-- sanitizer_syscall_linux_arm.inc -------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// Implementations of internal_syscall and internal_iserror for Linux/arm. +// +//===----------------------------------------------------------------------===// + +#define SYSCALL(name) __NR_ ## name + +static uptr __internal_syscall(u32 nr) { + register u32 r8 asm("r7") = nr; + register u32 r0 asm("r0"); + asm volatile("swi #0" + : "=r"(r0) + : "r"(r8) + : "memory", "cc"); + return r0; +} +#define __internal_syscall0(n) \ + (__internal_syscall)(n) + +static uptr __internal_syscall(u32 nr, u32 arg1) { + register u32 r8 asm("r7") = nr; + register u32 r0 asm("r0") = arg1; + asm volatile("swi #0" + : "=r"(r0) + : "r"(r8), "0"(r0) + : "memory", "cc"); + return r0; +} +#define __internal_syscall1(n, a1) \ + (__internal_syscall)(n, (u32)(a1)) + +static uptr __internal_syscall(u32 nr, u32 arg1, long arg2) { + register u32 r8 asm("r7") = nr; + register u32 r0 asm("r0") = arg1; + register u32 r1 asm("r1") = arg2; + asm volatile("swi #0" + : "=r"(r0) + : "r"(r8), "0"(r0), "r"(r1) + : "memory", "cc"); + return r0; +} +#define __internal_syscall2(n, a1, a2) \ + (__internal_syscall)(n, (u32)(a1), (long)(a2)) + +static uptr __internal_syscall(u32 nr, u32 arg1, long arg2, long arg3) { + register u32 r8 asm("r7") = nr; + register u32 r0 asm("r0") = arg1; + register u32 r1 asm("r1") = arg2; + register u32 r2 asm("r2") = arg3; + asm volatile("swi #0" + : "=r"(r0) + : "r"(r8), "0"(r0), "r"(r1), "r"(r2) + : "memory", "cc"); + return r0; +} +#define __internal_syscall3(n, a1, a2, a3) \ + (__internal_syscall)(n, (u32)(a1), (long)(a2), (long)(a3)) + +static uptr __internal_syscall(u32 nr, u32 arg1, long arg2, long arg3, + u32 arg4) { + register u32 r8 asm("r7") = nr; + register u32 r0 asm("r0") = arg1; + register u32 r1 asm("r1") = arg2; + register u32 r2 asm("r2") = arg3; + register u32 r3 asm("r3") = arg4; + asm volatile("swi #0" + : "=r"(r0) + : "r"(r8), "0"(r0), "r"(r1), "r"(r2), "r"(r3) + : "memory", "cc"); + return r0; +} +#define __internal_syscall4(n, a1, a2, a3, a4) \ + (__internal_syscall)(n, (u32)(a1), (long)(a2), (long)(a3), (long)(a4)) + +static uptr __internal_syscall(u32 nr, u32 arg1, long arg2, long arg3, + u32 arg4, long arg5) { + register u32 r8 asm("r7") = nr; + register u32 r0 asm("r0") = arg1; + register u32 r1 asm("r1") = arg2; + register u32 r2 asm("r2") = arg3; + register u32 r3 asm("r3") = arg4; + register u32 r4 asm("r4") = arg5; + asm volatile("swi #0" + : "=r"(r0) + : "r"(r8), "0"(r0), "r"(r1), "r"(r2), "r"(r3), "r"(r4) + : "memory", "cc"); + return r0; +} +#define __internal_syscall5(n, a1, a2, a3, a4, a5) \ + (__internal_syscall)(n, (u32)(a1), (long)(a2), (long)(a3), (long)(a4), \ + (u32)(a5)) + +static uptr __internal_syscall(u32 nr, u32 arg1, long arg2, long arg3, + u32 arg4, long arg5, long arg6) { + register u32 r8 asm("r7") = nr; + register u32 r0 asm("r0") = arg1; + register u32 r1 asm("r1") = arg2; + register u32 r2 asm("r2") = arg3; + register u32 r3 asm("r3") = arg4; + register u32 r4 asm("r4") = arg5; + register u32 r5 asm("r5") = arg6; + asm volatile("swi #0" + : "=r"(r0) + : "r"(r8), "0"(r0), "r"(r1), "r"(r2), "r"(r3), "r"(r4), "r"(r5) + : "memory", "cc"); + return r0; +} +#define __internal_syscall6(n, a1, a2, a3, a4, a5, a6) \ + (__internal_syscall)(n, (u32)(a1), (long)(a2), (long)(a3), (long)(a4), \ + (u32)(a5), (long)(a6)) + +#define __SYSCALL_NARGS_X(a1, a2, a3, a4, a5, a6, a7, a8, n, ...) n +#define __SYSCALL_NARGS(...) \ + __SYSCALL_NARGS_X(__VA_ARGS__, 7, 6, 5, 4, 3, 2, 1, 0, ) +#define __SYSCALL_CONCAT_X(a, b) a##b +#define __SYSCALL_CONCAT(a, b) __SYSCALL_CONCAT_X(a, b) +#define __SYSCALL_DISP(b, ...) \ + __SYSCALL_CONCAT(b, __SYSCALL_NARGS(__VA_ARGS__))(__VA_ARGS__) + +#define internal_syscall(...) __SYSCALL_DISP(__internal_syscall, __VA_ARGS__) + +// Helper function used to avoid cobbler errno. +bool internal_iserror(uptr retval, int *rverrno) { + if (retval >= (uptr)-4095) { + if (rverrno) + *rverrno = -retval; + return true; + } + return false; +} diff --git a/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_syscall_linux_hexagon.inc b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_syscall_linux_hexagon.inc new file mode 100644 index 0000000000..553bff7503 --- /dev/null +++ b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_syscall_linux_hexagon.inc @@ -0,0 +1,131 @@ +//===-- sanitizer_syscall_linux_hexagon.inc ---------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// Implementations of internal_syscall and internal_iserror for Linux/hexagon. +// +//===----------------------------------------------------------------------===// + +#define SYSCALL(name) __NR_##name + +#define __internal_syscall_LL_E(x) \ + ((union { \ + long long ll; \ + long l[2]; \ + }){.ll = x}) \ + .l[0], \ + ((union { \ + long long ll; \ + long l[2]; \ + }){.ll = x}) \ + .l[1] +#define __internal_syscall_LL_O(x) 0, __SYSCALL_LL_E((x)) + +#define __asm_syscall(...) \ + do { \ + __asm__ __volatile__("trap0(#1)" : "=r"(r0) : __VA_ARGS__ : "memory"); \ + return r0; \ + } while (0) + +#define __internal_syscall0(n) (__internal_syscall)(n) + +static uptr __internal_syscall(long n) { + register u32 r6 __asm__("r6") = n; + register u32 r0 __asm__("r0"); + __asm_syscall("r"(r6)); +} + +#define __internal_syscall1(n, a1) (__internal_syscall)(n, (long)(a1)) + +static uptr __internal_syscall(long n, long a) { + register u32 r6 __asm__("r6") = n; + register u32 r0 __asm__("r0") = a; + __asm_syscall("r"(r6), "0"(r0)); +} + +#define __internal_syscall2(n, a1, a2) \ + (__internal_syscall)(n, (long)(a1), (long)(a2)) + +static uptr __internal_syscall(long n, long a, long b) { + register u32 r6 __asm__("r6") = n; + register u32 r0 __asm__("r0") = a; + register u32 r1 __asm__("r1") = b; + __asm_syscall("r"(r6), "0"(r0), "r"(r1)); +} + +#define __internal_syscall3(n, a1, a2, a3) \ + (__internal_syscall)(n, (long)(a1), (long)(a2), (long)(a3)) + +static uptr __internal_syscall(long n, long a, long b, long c) { + register u32 r6 __asm__("r6") = n; + register u32 r0 __asm__("r0") = a; + register u32 r1 __asm__("r1") = b; + register u32 r2 __asm__("r2") = c; + __asm_syscall("r"(r6), "0"(r0), "r"(r1), "r"(r2)); +} + +#define __internal_syscall4(n, a1, a2, a3, a4) \ + (__internal_syscall)(n, (long)(a1), (long)(a2), (long)(a3), (long)(a4)) + +static uptr __internal_syscall(long n, long a, long b, long c, long d) { + register u32 r6 __asm__("r6") = n; + register u32 r0 __asm__("r0") = a; + register u32 r1 __asm__("r1") = b; + register u32 r2 __asm__("r2") = c; + register u32 r3 __asm__("r3") = d; + __asm_syscall("r"(r6), "0"(r0), "r"(r1), "r"(r2), "r"(r3)); +} + +#define __internal_syscall5(n, a1, a2, a3, a4, a5) \ + (__internal_syscall)(n, (long)(a1), (long)(a2), (long)(a3), (long)(a4), \ + (long)(a5)) + +static uptr __internal_syscall(long n, long a, long b, long c, long d, long e) { + register u32 r6 __asm__("r6") = n; + register u32 r0 __asm__("r0") = a; + register u32 r1 __asm__("r1") = b; + register u32 r2 __asm__("r2") = c; + register u32 r3 __asm__("r3") = d; + register u32 r4 __asm__("r4") = e; + __asm_syscall("r"(r6), "0"(r0), "r"(r1), "r"(r2), "r"(r3), "r"(r4)); +} + +#define __internal_syscall6(n, a1, a2, a3, a4, a5, a6) \ + (__internal_syscall)(n, (long)(a1), (long)(a2), (long)(a3), (long)(a4), \ + (long)(a5), (long)(a6)) + +static uptr __internal_syscall(long n, long a, long b, long c, long d, long e, + long f) { + register u32 r6 __asm__("r6") = n; + register u32 r0 __asm__("r0") = a; + register u32 r1 __asm__("r1") = b; + register u32 r2 __asm__("r2") = c; + register u32 r3 __asm__("r3") = d; + register u32 r4 __asm__("r4") = e; + register u32 r5 __asm__("r5") = f; + __asm_syscall("r"(r6), "0"(r0), "r"(r1), "r"(r2), "r"(r3), "r"(r4), "r"(r5)); +} + +#define __SYSCALL_NARGS_X(a1, a2, a3, a4, a5, a6, a7, a8, n, ...) n +#define __SYSCALL_NARGS(...) \ + __SYSCALL_NARGS_X(__VA_ARGS__, 7, 6, 5, 4, 3, 2, 1, 0, ) +#define __SYSCALL_CONCAT_X(a, b) a##b +#define __SYSCALL_CONCAT(a, b) __SYSCALL_CONCAT_X(a, b) +#define __SYSCALL_DISP(b, ...) \ + __SYSCALL_CONCAT(b, __SYSCALL_NARGS(__VA_ARGS__))(__VA_ARGS__) + +#define internal_syscall(...) __SYSCALL_DISP(__internal_syscall, __VA_ARGS__) + +// Helper function used to avoid clobbering of errno. +bool internal_iserror(uptr retval, int *rverrno) { + if (retval >= (uptr)-4095) { + if (rverrno) + *rverrno = -retval; + return true; + } + return false; +} diff --git a/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_syscall_linux_riscv64.inc b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_syscall_linux_riscv64.inc new file mode 100644 index 0000000000..89c1260205 --- /dev/null +++ b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_syscall_linux_riscv64.inc @@ -0,0 +1,174 @@ +//===-- sanitizer_syscall_linux_riscv64.inc ---------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// Implementations of internal_syscall and internal_iserror for Linux/riscv64. +// +//===----------------------------------------------------------------------===// + +// About local register variables: +// https://gcc.gnu.org/onlinedocs/gcc/Local-Register-Variables.html#Local-Register-Variables +// +// Kernel ABI... +// To my surprise I haven't found much information regarding it. +// Kernel source and internet browsing shows that: +// syscall number is passed in a7 +// (http://man7.org/linux/man-pages/man2/syscall.2.html) results are return in +// a0 and a1 (http://man7.org/linux/man-pages/man2/syscall.2.html) arguments +// are passed in: a0-a7 (see below) +// +// Regarding the arguments. The only "documentation" I could find is +// this comment (!!!) by Bruce Hold on google forums (!!!): +// https://groups.google.com/a/groups.riscv.org/forum/#!topic/sw-dev/exbrzM3GZDQ +// Confirmed by inspecting glibc sources. +// Great way to document things. +#define SYSCALL(name) __NR_##name + +#define INTERNAL_SYSCALL_CLOBBERS "memory" + +static uptr __internal_syscall(u64 nr) { + register u64 a7 asm("a7") = nr; + register u64 a0 asm("a0"); + __asm__ volatile("ecall\n\t" + : "=r"(a0) + : "r"(a7) + : INTERNAL_SYSCALL_CLOBBERS); + return a0; +} +#define __internal_syscall0(n) (__internal_syscall)(n) + +static uptr __internal_syscall(u64 nr, u64 arg1) { + register u64 a7 asm("a7") = nr; + register u64 a0 asm("a0") = arg1; + __asm__ volatile("ecall\n\t" + : "+r"(a0) + : "r"(a7) + : INTERNAL_SYSCALL_CLOBBERS); + return a0; +} +#define __internal_syscall1(n, a1) (__internal_syscall)(n, (u64)(a1)) + +static uptr __internal_syscall(u64 nr, u64 arg1, long arg2) { + register u64 a7 asm("a7") = nr; + register u64 a0 asm("a0") = arg1; + register u64 a1 asm("a1") = arg2; + __asm__ volatile("ecall\n\t" + : "+r"(a0) + : "r"(a7), "r"(a1) + : INTERNAL_SYSCALL_CLOBBERS); + return a0; +} +#define __internal_syscall2(n, a1, a2) \ + (__internal_syscall)(n, (u64)(a1), (long)(a2)) + +static uptr __internal_syscall(u64 nr, u64 arg1, long arg2, long arg3) { + register u64 a7 asm("a7") = nr; + register u64 a0 asm("a0") = arg1; + register u64 a1 asm("a1") = arg2; + register u64 a2 asm("a2") = arg3; + __asm__ volatile("ecall\n\t" + : "+r"(a0) + : "r"(a7), "r"(a1), "r"(a2) + : INTERNAL_SYSCALL_CLOBBERS); + return a0; +} +#define __internal_syscall3(n, a1, a2, a3) \ + (__internal_syscall)(n, (u64)(a1), (long)(a2), (long)(a3)) + +static uptr __internal_syscall(u64 nr, u64 arg1, long arg2, long arg3, + u64 arg4) { + register u64 a7 asm("a7") = nr; + register u64 a0 asm("a0") = arg1; + register u64 a1 asm("a1") = arg2; + register u64 a2 asm("a2") = arg3; + register u64 a3 asm("a3") = arg4; + __asm__ volatile("ecall\n\t" + : "+r"(a0) + : "r"(a7), "r"(a1), "r"(a2), "r"(a3) + : INTERNAL_SYSCALL_CLOBBERS); + return a0; +} +#define __internal_syscall4(n, a1, a2, a3, a4) \ + (__internal_syscall)(n, (u64)(a1), (long)(a2), (long)(a3), (long)(a4)) + +static uptr __internal_syscall(u64 nr, u64 arg1, long arg2, long arg3, u64 arg4, + long arg5) { + register u64 a7 asm("a7") = nr; + register u64 a0 asm("a0") = arg1; + register u64 a1 asm("a1") = arg2; + register u64 a2 asm("a2") = arg3; + register u64 a3 asm("a3") = arg4; + register u64 a4 asm("a4") = arg5; + __asm__ volatile("ecall\n\t" + : "+r"(a0) + : "r"(a7), "r"(a1), "r"(a2), "r"(a3), "r"(a4) + : INTERNAL_SYSCALL_CLOBBERS); + return a0; +} +#define __internal_syscall5(n, a1, a2, a3, a4, a5) \ + (__internal_syscall)(n, (u64)(a1), (long)(a2), (long)(a3), (long)(a4), \ + (u64)(a5)) + +static uptr __internal_syscall(u64 nr, u64 arg1, long arg2, long arg3, u64 arg4, + long arg5, long arg6) { + register u64 a7 asm("a7") = nr; + register u64 a0 asm("a0") = arg1; + register u64 a1 asm("a1") = arg2; + register u64 a2 asm("a2") = arg3; + register u64 a3 asm("a3") = arg4; + register u64 a4 asm("a4") = arg5; + register u64 a5 asm("a5") = arg6; + __asm__ volatile("ecall\n\t" + : "+r"(a0) + : "r"(a7), "r"(a1), "r"(a2), "r"(a3), "r"(a4), "r"(a5) + : INTERNAL_SYSCALL_CLOBBERS); + return a0; +} +#define __internal_syscall6(n, a1, a2, a3, a4, a5, a6) \ + (__internal_syscall)(n, (u64)(a1), (long)(a2), (long)(a3), (long)(a4), \ + (u64)(a5), (long)(a6)) + +static uptr __internal_syscall(u64 nr, u64 arg1, long arg2, long arg3, u64 arg4, + long arg5, long arg6, long arg7) { + register u64 a7 asm("a7") = nr; + register u64 a0 asm("a0") = arg1; + register u64 a1 asm("a1") = arg2; + register u64 a2 asm("a2") = arg3; + register u64 a3 asm("a3") = arg4; + register u64 a4 asm("a4") = arg5; + register u64 a5 asm("a5") = arg6; + register u64 a6 asm("a6") = arg7; + __asm__ volatile("ecall\n\t" + : "+r"(a0) + : "r"(a7), "r"(a1), "r"(a2), "r"(a3), "r"(a4), "r"(a5), + "r"(a6) + : INTERNAL_SYSCALL_CLOBBERS); + return a0; +} +#define __internal_syscall7(n, a1, a2, a3, a4, a5, a6, a7) \ + (__internal_syscall)(n, (u64)(a1), (long)(a2), (long)(a3), (long)(a4), \ + (u64)(a5), (long)(a6), (long)(a7)) + +#define __SYSCALL_NARGS_X(a1, a2, a3, a4, a5, a6, a7, a8, n, ...) n +#define __SYSCALL_NARGS(...) \ + __SYSCALL_NARGS_X(__VA_ARGS__, 7, 6, 5, 4, 3, 2, 1, 0, ) +#define __SYSCALL_CONCAT_X(a, b) a##b +#define __SYSCALL_CONCAT(a, b) __SYSCALL_CONCAT_X(a, b) +#define __SYSCALL_DISP(b, ...) \ + __SYSCALL_CONCAT(b, __SYSCALL_NARGS(__VA_ARGS__))(__VA_ARGS__) + +#define internal_syscall(...) __SYSCALL_DISP(__internal_syscall, __VA_ARGS__) + +// Helper function used to avoid clobbering of errno. +bool internal_iserror(uptr retval, int *rverrno) { + if (retval >= (uptr)-4095) { + if (rverrno) + *rverrno = -retval; + return true; + } + return false; +} diff --git a/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_syscall_linux_x86_64.inc b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_syscall_linux_x86_64.inc new file mode 100644 index 0000000000..67e8686d12 --- /dev/null +++ b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_syscall_linux_x86_64.inc @@ -0,0 +1,90 @@ +//===-- sanitizer_syscall_linux_x86_64.inc ----------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// Implementations of internal_syscall and internal_iserror for Linux/x86_64. +// +//===----------------------------------------------------------------------===// + +#define SYSCALL(name) __NR_ ## name + +static uptr internal_syscall(u64 nr) { + u64 retval; + asm volatile("syscall" : "=a"(retval) : "a"(nr) : "rcx", "r11", + "memory", "cc"); + return retval; +} + +template <typename T1> +static uptr internal_syscall(u64 nr, T1 arg1) { + u64 retval; + asm volatile("syscall" : "=a"(retval) : "a"(nr), "D"((u64)arg1) : + "rcx", "r11", "memory", "cc"); + return retval; +} + +template <typename T1, typename T2> +static uptr internal_syscall(u64 nr, T1 arg1, T2 arg2) { + u64 retval; + asm volatile("syscall" : "=a"(retval) : "a"(nr), "D"((u64)arg1), + "S"((u64)arg2) : "rcx", "r11", "memory", "cc"); + return retval; +} + +template <typename T1, typename T2, typename T3> +static uptr internal_syscall(u64 nr, T1 arg1, T2 arg2, T3 arg3) { + u64 retval; + asm volatile("syscall" : "=a"(retval) : "a"(nr), "D"((u64)arg1), + "S"((u64)arg2), "d"((u64)arg3) : "rcx", "r11", "memory", "cc"); + return retval; +} + +template <typename T1, typename T2, typename T3, typename T4> +static uptr internal_syscall(u64 nr, T1 arg1, T2 arg2, T3 arg3, T4 arg4) { + u64 retval; + asm volatile("mov %5, %%r10;" + "syscall" : "=a"(retval) : "a"(nr), "D"((u64)arg1), + "S"((u64)arg2), "d"((u64)arg3), "r"((u64)arg4) : + "rcx", "r11", "r10", "memory", "cc"); + return retval; +} + +template <typename T1, typename T2, typename T3, typename T4, typename T5> +static uptr internal_syscall(u64 nr, T1 arg1, T2 arg2, T3 arg3, T4 arg4, + T5 arg5) { + u64 retval; + asm volatile("mov %5, %%r10;" + "mov %6, %%r8;" + "syscall" : "=a"(retval) : "a"(nr), "D"((u64)arg1), + "S"((u64)arg2), "d"((u64)arg3), "r"((u64)arg4), "r"((u64)arg5) : + "rcx", "r11", "r10", "r8", "memory", "cc"); + return retval; +} + +template <typename T1, typename T2, typename T3, typename T4, typename T5, + typename T6> +static uptr internal_syscall(u64 nr, T1 arg1, T2 arg2, T3 arg3, T4 arg4, + T5 arg5, T6 arg6) { + u64 retval; + asm volatile("mov %5, %%r10;" + "mov %6, %%r8;" + "mov %7, %%r9;" + "syscall" : "=a"(retval) : "a"(nr), "D"((u64)arg1), + "S"((u64)arg2), "d"((u64)arg3), "r"((u64)arg4), "r"((u64)arg5), + "r"((u64)arg6) : "rcx", "r11", "r10", "r8", "r9", + "memory", "cc"); + return retval; +} + +bool internal_iserror(uptr retval, int *rverrno) { + if (retval >= (uptr)-4095) { + if (rverrno) + *rverrno = -retval; + return true; + } + return false; +} diff --git a/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_syscalls_netbsd.inc b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_syscalls_netbsd.inc new file mode 100644 index 0000000000..4ce5de0627 --- /dev/null +++ b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_syscalls_netbsd.inc @@ -0,0 +1,3944 @@ +//===-- sanitizer_syscalls_netbsd.inc ---------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// Common syscalls handlers for tools like AddressSanitizer, +// ThreadSanitizer, MemorySanitizer, etc. +// +// This file should be included into the tool's interceptor file, +// which has to define it's own macros: +// COMMON_SYSCALL_PRE_READ_RANGE +// Called in prehook for regions that will be read by the kernel and +// must be initialized. +// COMMON_SYSCALL_PRE_WRITE_RANGE +// Called in prehook for regions that will be written to by the kernel +// and must be addressable. The actual write range may be smaller than +// reported in the prehook. See POST_WRITE_RANGE. +// COMMON_SYSCALL_POST_READ_RANGE +// Called in posthook for regions that were read by the kernel. Does +// not make much sense. +// COMMON_SYSCALL_POST_WRITE_RANGE +// Called in posthook for regions that were written to by the kernel +// and are now initialized. +// COMMON_SYSCALL_ACQUIRE(addr) +// Acquire memory visibility from addr. +// COMMON_SYSCALL_RELEASE(addr) +// Release memory visibility to addr. +// COMMON_SYSCALL_FD_CLOSE(fd) +// Called before closing file descriptor fd. +// COMMON_SYSCALL_FD_ACQUIRE(fd) +// Acquire memory visibility from fd. +// COMMON_SYSCALL_FD_RELEASE(fd) +// Release memory visibility to fd. +// COMMON_SYSCALL_PRE_FORK() +// Called before fork syscall. +// COMMON_SYSCALL_POST_FORK(long long res) +// Called after fork syscall. +// +// DO NOT EDIT! THIS FILE HAS BEEN GENERATED! +// +// Generated with: generate_netbsd_syscalls.awk +// Generated date: 2020-09-10 +// Generated from: syscalls.master,v 1.306 2020/08/14 00:53:16 riastradh Exp +// +//===----------------------------------------------------------------------===// + +#include "sanitizer_platform.h" +#if SANITIZER_NETBSD + +#include "sanitizer_libc.h" + +#define PRE_SYSCALL(name) \ + SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_syscall_pre_impl_##name +#define PRE_READ(p, s) COMMON_SYSCALL_PRE_READ_RANGE(p, s) +#define PRE_WRITE(p, s) COMMON_SYSCALL_PRE_WRITE_RANGE(p, s) + +#define POST_SYSCALL(name) \ + SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_syscall_post_impl_##name +#define POST_READ(p, s) COMMON_SYSCALL_POST_READ_RANGE(p, s) +#define POST_WRITE(p, s) COMMON_SYSCALL_POST_WRITE_RANGE(p, s) + +#ifndef COMMON_SYSCALL_ACQUIRE +#define COMMON_SYSCALL_ACQUIRE(addr) ((void)(addr)) +#endif + +#ifndef COMMON_SYSCALL_RELEASE +#define COMMON_SYSCALL_RELEASE(addr) ((void)(addr)) +#endif + +#ifndef COMMON_SYSCALL_FD_CLOSE +#define COMMON_SYSCALL_FD_CLOSE(fd) ((void)(fd)) +#endif + +#ifndef COMMON_SYSCALL_FD_ACQUIRE +#define COMMON_SYSCALL_FD_ACQUIRE(fd) ((void)(fd)) +#endif + +#ifndef COMMON_SYSCALL_FD_RELEASE +#define COMMON_SYSCALL_FD_RELEASE(fd) ((void)(fd)) +#endif + +#ifndef COMMON_SYSCALL_PRE_FORK +#define COMMON_SYSCALL_PRE_FORK() \ + {} +#endif + +#ifndef COMMON_SYSCALL_POST_FORK +#define COMMON_SYSCALL_POST_FORK(res) \ + {} +#endif + +// FIXME: do some kind of PRE_READ for all syscall arguments (int(s) and such). + +extern "C" { +#define SYS_MAXSYSARGS 8 +PRE_SYSCALL(syscall)(long long code_, long long args_[SYS_MAXSYSARGS]) { + /* Nothing to do */ +} +POST_SYSCALL(syscall) +(long long res, long long code_, long long args_[SYS_MAXSYSARGS]) { + /* Nothing to do */ +} +PRE_SYSCALL(exit)(long long rval_) { /* Nothing to do */ } +POST_SYSCALL(exit)(long long res, long long rval_) { /* Nothing to do */ } +PRE_SYSCALL(fork)(void) { COMMON_SYSCALL_PRE_FORK(); } +POST_SYSCALL(fork)(long long res) { COMMON_SYSCALL_POST_FORK(res); } +PRE_SYSCALL(read)(long long fd_, void *buf_, long long nbyte_) { + if (buf_) { + PRE_WRITE(buf_, nbyte_); + } +} +POST_SYSCALL(read)(long long res, long long fd_, void *buf_, long long nbyte_) { + if (res > 0) { + POST_WRITE(buf_, res); + } +} +PRE_SYSCALL(write)(long long fd_, void *buf_, long long nbyte_) { + if (buf_) { + PRE_READ(buf_, nbyte_); + } +} +POST_SYSCALL(write) +(long long res, long long fd_, void *buf_, long long nbyte_) { + if (res > 0) { + POST_READ(buf_, res); + } +} +PRE_SYSCALL(open)(void *path_, long long flags_, long long mode_) { + const char *path = (const char *)path_; + if (path) { + PRE_READ(path, __sanitizer::internal_strlen(path) + 1); + } +} +POST_SYSCALL(open) +(long long res, void *path_, long long flags_, long long mode_) { + if (res > 0) { + const char *path = (const char *)path_; + if (path) { + POST_READ(path, __sanitizer::internal_strlen(path) + 1); + } + } +} +PRE_SYSCALL(close)(long long fd_) { COMMON_SYSCALL_FD_CLOSE((int)fd_); } +POST_SYSCALL(close)(long long res, long long fd_) { /* Nothing to do */ } +PRE_SYSCALL(compat_50_wait4) +(long long pid_, void *status_, long long options_, void *rusage_) { + /* TODO */ +} +POST_SYSCALL(compat_50_wait4) +(long long res, long long pid_, void *status_, long long options_, + void *rusage_) { + /* TODO */ +} +PRE_SYSCALL(compat_43_ocreat)(void *path_, long long mode_) { /* TODO */ } +POST_SYSCALL(compat_43_ocreat)(long long res, void *path_, long long mode_) { + /* TODO */ +} +PRE_SYSCALL(link)(void *path_, void *link_) { + const char *path = (const char *)path_; + const char *link = (const char *)link_; + if (path) { + PRE_READ(path, __sanitizer::internal_strlen(path) + 1); + } + if (link) { + PRE_READ(path, __sanitizer::internal_strlen(link) + 1); + } +} +POST_SYSCALL(link)(long long res, void *path_, void *link_) { + if (res == 0) { + const char *path = (const char *)path_; + const char *link = (const char *)link_; + if (path) { + POST_READ(path, __sanitizer::internal_strlen(path) + 1); + } + if (link) { + POST_READ(path, __sanitizer::internal_strlen(link) + 1); + } + } +} +PRE_SYSCALL(unlink)(void *path_) { + const char *path = (const char *)path_; + if (path) { + PRE_READ(path, __sanitizer::internal_strlen(path) + 1); + } +} +POST_SYSCALL(unlink)(long long res, void *path_) { + if (res == 0) { + const char *path = (const char *)path_; + if (path) { + POST_READ(path, __sanitizer::internal_strlen(path) + 1); + } + } +} +/* syscall 11 has been skipped */ +PRE_SYSCALL(chdir)(void *path_) { + const char *path = (const char *)path_; + if (path) { + PRE_READ(path, __sanitizer::internal_strlen(path) + 1); + } +} +POST_SYSCALL(chdir)(long long res, void *path_) { + if (res == 0) { + const char *path = (const char *)path_; + if (path) { + POST_READ(path, __sanitizer::internal_strlen(path) + 1); + } + } +} +PRE_SYSCALL(fchdir)(long long fd_) { /* Nothing to do */ } +POST_SYSCALL(fchdir)(long long res, long long fd_) { /* Nothing to do */ } +PRE_SYSCALL(compat_50_mknod)(void *path_, long long mode_, long long dev_) { + /* TODO */ +} +POST_SYSCALL(compat_50_mknod) +(long long res, void *path_, long long mode_, long long dev_) { + /* TODO */ +} +PRE_SYSCALL(chmod)(void *path_, long long mode_) { + const char *path = (const char *)path_; + if (path) { + PRE_READ(path, __sanitizer::internal_strlen(path) + 1); + } +} +POST_SYSCALL(chmod)(long long res, void *path_, long long mode_) { + if (res == 0) { + const char *path = (const char *)path_; + if (path) { + POST_READ(path, __sanitizer::internal_strlen(path) + 1); + } + } +} +PRE_SYSCALL(chown)(void *path_, long long uid_, long long gid_) { + const char *path = (const char *)path_; + if (path) { + PRE_READ(path, __sanitizer::internal_strlen(path) + 1); + } +} +POST_SYSCALL(chown) +(long long res, void *path_, long long uid_, long long gid_) { + if (res == 0) { + const char *path = (const char *)path_; + if (path) { + POST_READ(path, __sanitizer::internal_strlen(path) + 1); + } + } +} +PRE_SYSCALL(break)(void *nsize_) { /* Nothing to do */ } +POST_SYSCALL(break)(long long res, void *nsize_) { /* Nothing to do */ } +PRE_SYSCALL(compat_20_getfsstat) +(void *buf_, long long bufsize_, long long flags_) { + /* TODO */ +} +POST_SYSCALL(compat_20_getfsstat) +(long long res, void *buf_, long long bufsize_, long long flags_) { + /* TODO */ +} +PRE_SYSCALL(compat_43_olseek) +(long long fd_, long long offset_, long long whence_) { + /* TODO */ +} +POST_SYSCALL(compat_43_olseek) +(long long res, long long fd_, long long offset_, long long whence_) { + /* TODO */ +} +PRE_SYSCALL(getpid)(void) { /* Nothing to do */ } +POST_SYSCALL(getpid)(long long res) { /* Nothing to do */ } +PRE_SYSCALL(compat_40_mount) +(void *type_, void *path_, long long flags_, void *data_) { + /* TODO */ +} +POST_SYSCALL(compat_40_mount) +(long long res, void *type_, void *path_, long long flags_, void *data_) { + /* TODO */ +} +PRE_SYSCALL(unmount)(void *path_, long long flags_) { + const char *path = (const char *)path_; + if (path) { + PRE_READ(path, __sanitizer::internal_strlen(path) + 1); + } +} +POST_SYSCALL(unmount)(long long res, void *path_, long long flags_) { + if (res == 0) { + const char *path = (const char *)path_; + if (path) { + POST_READ(path, __sanitizer::internal_strlen(path) + 1); + } + } +} +PRE_SYSCALL(setuid)(long long uid_) { /* Nothing to do */ } +POST_SYSCALL(setuid)(long long res, long long uid_) { /* Nothing to do */ } +PRE_SYSCALL(getuid)(void) { /* Nothing to do */ } +POST_SYSCALL(getuid)(long long res) { /* Nothing to do */ } +PRE_SYSCALL(geteuid)(void) { /* Nothing to do */ } +POST_SYSCALL(geteuid)(long long res) { /* Nothing to do */ } +PRE_SYSCALL(ptrace) +(long long req_, long long pid_, void *addr_, long long data_) { + if (req_ == ptrace_pt_io) { + struct __sanitizer_ptrace_io_desc *addr = + (struct __sanitizer_ptrace_io_desc *)addr_; + PRE_READ(addr, struct_ptrace_ptrace_io_desc_struct_sz); + if (addr->piod_op == ptrace_piod_write_d || + addr->piod_op == ptrace_piod_write_i) { + PRE_READ(addr->piod_addr, addr->piod_len); + } + if (addr->piod_op == ptrace_piod_read_d || + addr->piod_op == ptrace_piod_read_i || + addr->piod_op == ptrace_piod_read_auxv) { + PRE_WRITE(addr->piod_addr, addr->piod_len); + } + } else if (req_ == ptrace_pt_lwpinfo) { + struct __sanitizer_ptrace_lwpinfo *addr = + (struct __sanitizer_ptrace_lwpinfo *)addr_; + PRE_READ(&addr->pl_lwpid, sizeof(__sanitizer_lwpid_t)); + PRE_WRITE(addr, struct_ptrace_ptrace_lwpinfo_struct_sz); + } else if (req_ == ptrace_pt_set_event_mask) { + PRE_READ(addr_, struct_ptrace_ptrace_event_struct_sz); + } else if (req_ == ptrace_pt_get_event_mask) { + PRE_WRITE(addr_, struct_ptrace_ptrace_event_struct_sz); + } else if (req_ == ptrace_pt_set_siginfo) { + PRE_READ(addr_, struct_ptrace_ptrace_siginfo_struct_sz); + } else if (req_ == ptrace_pt_get_siginfo) { + PRE_WRITE(addr_, struct_ptrace_ptrace_siginfo_struct_sz); + } else if (req_ == ptrace_pt_lwpstatus) { + struct __sanitizer_ptrace_lwpstatus *addr = + (struct __sanitizer_ptrace_lwpstatus *)addr_; + PRE_READ(&addr->pl_lwpid, sizeof(__sanitizer_lwpid_t)); + PRE_WRITE(addr, struct_ptrace_ptrace_lwpstatus_struct_sz); + } else if (req_ == ptrace_pt_lwpnext) { + struct __sanitizer_ptrace_lwpstatus *addr = + (struct __sanitizer_ptrace_lwpstatus *)addr_; + PRE_READ(&addr->pl_lwpid, sizeof(__sanitizer_lwpid_t)); + PRE_WRITE(addr, struct_ptrace_ptrace_lwpstatus_struct_sz); + } else if (req_ == ptrace_pt_setregs) { + PRE_READ(addr_, struct_ptrace_reg_struct_sz); + } else if (req_ == ptrace_pt_getregs) { + PRE_WRITE(addr_, struct_ptrace_reg_struct_sz); + } else if (req_ == ptrace_pt_setfpregs) { + PRE_READ(addr_, struct_ptrace_fpreg_struct_sz); + } else if (req_ == ptrace_pt_getfpregs) { + PRE_WRITE(addr_, struct_ptrace_fpreg_struct_sz); + } else if (req_ == ptrace_pt_setdbregs) { + PRE_READ(addr_, struct_ptrace_dbreg_struct_sz); + } else if (req_ == ptrace_pt_getdbregs) { + PRE_WRITE(addr_, struct_ptrace_dbreg_struct_sz); + } +} +POST_SYSCALL(ptrace) +(long long res, long long req_, long long pid_, void *addr_, long long data_) { + if (res == 0) { + if (req_ == ptrace_pt_io) { + struct __sanitizer_ptrace_io_desc *addr = + (struct __sanitizer_ptrace_io_desc *)addr_; + POST_READ(addr, struct_ptrace_ptrace_io_desc_struct_sz); + if (addr->piod_op == ptrace_piod_write_d || + addr->piod_op == ptrace_piod_write_i) { + POST_READ(addr->piod_addr, addr->piod_len); + } + if (addr->piod_op == ptrace_piod_read_d || + addr->piod_op == ptrace_piod_read_i || + addr->piod_op == ptrace_piod_read_auxv) { + POST_WRITE(addr->piod_addr, addr->piod_len); + } + } else if (req_ == ptrace_pt_lwpinfo) { + struct __sanitizer_ptrace_lwpinfo *addr = + (struct __sanitizer_ptrace_lwpinfo *)addr_; + POST_READ(&addr->pl_lwpid, sizeof(__sanitizer_lwpid_t)); + POST_WRITE(addr, struct_ptrace_ptrace_lwpinfo_struct_sz); + } else if (req_ == ptrace_pt_set_event_mask) { + POST_READ(addr_, struct_ptrace_ptrace_event_struct_sz); + } else if (req_ == ptrace_pt_get_event_mask) { + POST_WRITE(addr_, struct_ptrace_ptrace_event_struct_sz); + } else if (req_ == ptrace_pt_set_siginfo) { + POST_READ(addr_, struct_ptrace_ptrace_siginfo_struct_sz); + } else if (req_ == ptrace_pt_get_siginfo) { + POST_WRITE(addr_, struct_ptrace_ptrace_siginfo_struct_sz); + } else if (req_ == ptrace_pt_lwpstatus) { + struct __sanitizer_ptrace_lwpstatus *addr = + (struct __sanitizer_ptrace_lwpstatus *)addr_; + POST_READ(&addr->pl_lwpid, sizeof(__sanitizer_lwpid_t)); + POST_WRITE(addr, struct_ptrace_ptrace_lwpstatus_struct_sz); + } else if (req_ == ptrace_pt_lwpnext) { + struct __sanitizer_ptrace_lwpstatus *addr = + (struct __sanitizer_ptrace_lwpstatus *)addr_; + POST_READ(&addr->pl_lwpid, sizeof(__sanitizer_lwpid_t)); + POST_WRITE(addr, struct_ptrace_ptrace_lwpstatus_struct_sz); + } else if (req_ == ptrace_pt_setregs) { + POST_READ(addr_, struct_ptrace_reg_struct_sz); + } else if (req_ == ptrace_pt_getregs) { + POST_WRITE(addr_, struct_ptrace_reg_struct_sz); + } else if (req_ == ptrace_pt_setfpregs) { + POST_READ(addr_, struct_ptrace_fpreg_struct_sz); + } else if (req_ == ptrace_pt_getfpregs) { + POST_WRITE(addr_, struct_ptrace_fpreg_struct_sz); + } else if (req_ == ptrace_pt_setdbregs) { + POST_READ(addr_, struct_ptrace_dbreg_struct_sz); + } else if (req_ == ptrace_pt_getdbregs) { + POST_WRITE(addr_, struct_ptrace_dbreg_struct_sz); + } + } +} +PRE_SYSCALL(recvmsg)(long long s_, void *msg_, long long flags_) { + PRE_WRITE(msg_, sizeof(__sanitizer_msghdr)); +} +POST_SYSCALL(recvmsg) +(long long res, long long s_, void *msg_, long long flags_) { + if (res > 0) { + POST_WRITE(msg_, sizeof(__sanitizer_msghdr)); + } +} +PRE_SYSCALL(sendmsg)(long long s_, void *msg_, long long flags_) { + PRE_READ(msg_, sizeof(__sanitizer_msghdr)); +} +POST_SYSCALL(sendmsg) +(long long res, long long s_, void *msg_, long long flags_) { + if (res > 0) { + POST_READ(msg_, sizeof(__sanitizer_msghdr)); + } +} +PRE_SYSCALL(recvfrom) +(long long s_, void *buf_, long long len_, long long flags_, void *from_, + void *fromlenaddr_) { + PRE_WRITE(buf_, len_); + PRE_WRITE(from_, struct_sockaddr_sz); + PRE_WRITE(fromlenaddr_, sizeof(__sanitizer_socklen_t)); +} +POST_SYSCALL(recvfrom) +(long long res, long long s_, void *buf_, long long len_, long long flags_, + void *from_, void *fromlenaddr_) { + if (res >= 0) { + POST_WRITE(buf_, res); + POST_WRITE(from_, struct_sockaddr_sz); + POST_WRITE(fromlenaddr_, sizeof(__sanitizer_socklen_t)); + } +} +PRE_SYSCALL(accept)(long long s_, void *name_, void *anamelen_) { + PRE_WRITE(name_, struct_sockaddr_sz); + PRE_WRITE(anamelen_, sizeof(__sanitizer_socklen_t)); +} +POST_SYSCALL(accept) +(long long res, long long s_, void *name_, void *anamelen_) { + if (res == 0) { + POST_WRITE(name_, struct_sockaddr_sz); + POST_WRITE(anamelen_, sizeof(__sanitizer_socklen_t)); + } +} +PRE_SYSCALL(getpeername)(long long fdes_, void *asa_, void *alen_) { + PRE_WRITE(asa_, struct_sockaddr_sz); + PRE_WRITE(alen_, sizeof(__sanitizer_socklen_t)); +} +POST_SYSCALL(getpeername) +(long long res, long long fdes_, void *asa_, void *alen_) { + if (res == 0) { + POST_WRITE(asa_, struct_sockaddr_sz); + POST_WRITE(alen_, sizeof(__sanitizer_socklen_t)); + } +} +PRE_SYSCALL(getsockname)(long long fdes_, void *asa_, void *alen_) { + PRE_WRITE(asa_, struct_sockaddr_sz); + PRE_WRITE(alen_, sizeof(__sanitizer_socklen_t)); +} +POST_SYSCALL(getsockname) +(long long res, long long fdes_, void *asa_, void *alen_) { + if (res == 0) { + POST_WRITE(asa_, struct_sockaddr_sz); + POST_WRITE(alen_, sizeof(__sanitizer_socklen_t)); + } +} +PRE_SYSCALL(access)(void *path_, long long flags_) { + const char *path = (const char *)path_; + if (path) { + PRE_READ(path, __sanitizer::internal_strlen(path) + 1); + } +} +POST_SYSCALL(access)(long long res, void *path_, long long flags_) { + if (res == 0) { + const char *path = (const char *)path_; + if (path) { + POST_READ(path, __sanitizer::internal_strlen(path) + 1); + } + } +} +PRE_SYSCALL(chflags)(void *path_, long long flags_) { + const char *path = (const char *)path_; + if (path) { + PRE_READ(path, __sanitizer::internal_strlen(path) + 1); + } +} +POST_SYSCALL(chflags)(long long res, void *path_, long long flags_) { + if (res == 0) { + const char *path = (const char *)path_; + if (path) { + POST_READ(path, __sanitizer::internal_strlen(path) + 1); + } + } +} +PRE_SYSCALL(fchflags)(long long fd_, long long flags_) { /* Nothing to do */ } +POST_SYSCALL(fchflags)(long long res, long long fd_, long long flags_) { + /* Nothing to do */ +} +PRE_SYSCALL(sync)(void) { /* Nothing to do */ } +POST_SYSCALL(sync)(long long res) { /* Nothing to do */ } +PRE_SYSCALL(kill)(long long pid_, long long signum_) { /* Nothing to do */ } +POST_SYSCALL(kill)(long long res, long long pid_, long long signum_) { + /* Nothing to do */ +} +PRE_SYSCALL(compat_43_stat43)(void *path_, void *ub_) { /* TODO */ } +POST_SYSCALL(compat_43_stat43)(long long res, void *path_, void *ub_) { + /* TODO */ +} +PRE_SYSCALL(getppid)(void) { /* Nothing to do */ } +POST_SYSCALL(getppid)(long long res) { /* Nothing to do */ } +PRE_SYSCALL(compat_43_lstat43)(void *path_, void *ub_) { /* TODO */ } +POST_SYSCALL(compat_43_lstat43)(long long res, void *path_, void *ub_) { + /* TODO */ +} +PRE_SYSCALL(dup)(long long fd_) { /* Nothing to do */ } +POST_SYSCALL(dup)(long long res, long long fd_) { /* Nothing to do */ } +PRE_SYSCALL(pipe)(void) { + /* pipe returns two descriptors through two returned values */ +} +POST_SYSCALL(pipe)(long long res) { + /* pipe returns two descriptors through two returned values */ +} +PRE_SYSCALL(getegid)(void) { /* Nothing to do */ } +POST_SYSCALL(getegid)(long long res) { /* Nothing to do */ } +PRE_SYSCALL(profil) +(void *samples_, long long size_, long long offset_, long long scale_) { + if (samples_) { + PRE_WRITE(samples_, size_); + } +} +POST_SYSCALL(profil) +(long long res, void *samples_, long long size_, long long offset_, + long long scale_) { + if (res == 0) { + if (samples_) { + POST_WRITE(samples_, size_); + } + } +} +PRE_SYSCALL(ktrace) +(void *fname_, long long ops_, long long facs_, long long pid_) { + const char *fname = (const char *)fname_; + if (fname) { + PRE_READ(fname, __sanitizer::internal_strlen(fname) + 1); + } +} +POST_SYSCALL(ktrace) +(long long res, void *fname_, long long ops_, long long facs_, long long pid_) { + const char *fname = (const char *)fname_; + if (res == 0) { + if (fname) { + POST_READ(fname, __sanitizer::internal_strlen(fname) + 1); + } + } +} +PRE_SYSCALL(compat_13_sigaction13)(long long signum_, void *nsa_, void *osa_) { + /* TODO */ +} +POST_SYSCALL(compat_13_sigaction13) +(long long res, long long signum_, void *nsa_, void *osa_) { + /* TODO */ +} +PRE_SYSCALL(getgid)(void) { /* Nothing to do */ } +POST_SYSCALL(getgid)(long long res) { /* Nothing to do */ } +PRE_SYSCALL(compat_13_sigprocmask13)(long long how_, long long mask_) { + /* TODO */ +} +POST_SYSCALL(compat_13_sigprocmask13) +(long long res, long long how_, long long mask_) { + /* TODO */ +} +PRE_SYSCALL(__getlogin)(void *namebuf_, long long namelen_) { + if (namebuf_) { + PRE_WRITE(namebuf_, namelen_); + } +} +POST_SYSCALL(__getlogin)(long long res, void *namebuf_, long long namelen_) { + if (res == 0) { + if (namebuf_) { + POST_WRITE(namebuf_, namelen_); + } + } +} +PRE_SYSCALL(__setlogin)(void *namebuf_) { + const char *namebuf = (const char *)namebuf_; + if (namebuf) { + PRE_READ(namebuf, __sanitizer::internal_strlen(namebuf) + 1); + } +} +POST_SYSCALL(__setlogin)(long long res, void *namebuf_) { + if (res == 0) { + const char *namebuf = (const char *)namebuf_; + if (namebuf) { + POST_READ(namebuf, __sanitizer::internal_strlen(namebuf) + 1); + } + } +} +PRE_SYSCALL(acct)(void *path_) { + const char *path = (const char *)path_; + if (path) { + PRE_READ(path, __sanitizer::internal_strlen(path) + 1); + } +} +POST_SYSCALL(acct)(long long res, void *path_) { + if (res == 0) { + const char *path = (const char *)path_; + if (path) { + POST_READ(path, __sanitizer::internal_strlen(path) + 1); + } + } +} +PRE_SYSCALL(compat_13_sigpending13)(void) { /* TODO */ } +POST_SYSCALL(compat_13_sigpending13)(long long res) { /* TODO */ } +PRE_SYSCALL(compat_13_sigaltstack13)(void *nss_, void *oss_) { /* TODO */ } +POST_SYSCALL(compat_13_sigaltstack13)(long long res, void *nss_, void *oss_) { + /* TODO */ +} +PRE_SYSCALL(ioctl)(long long fd_, long long com_, void *data_) { + /* Nothing to do */ +} +POST_SYSCALL(ioctl)(long long res, long long fd_, long long com_, void *data_) { + /* Nothing to do */ +} +PRE_SYSCALL(compat_12_oreboot)(long long opt_) { /* TODO */ } +POST_SYSCALL(compat_12_oreboot)(long long res, long long opt_) { /* TODO */ } +PRE_SYSCALL(revoke)(void *path_) { + const char *path = (const char *)path_; + if (path) { + PRE_READ(path, __sanitizer::internal_strlen(path) + 1); + } +} +POST_SYSCALL(revoke)(long long res, void *path_) { + if (res == 0) { + const char *path = (const char *)path_; + if (path) { + POST_READ(path, __sanitizer::internal_strlen(path) + 1); + } + } +} +PRE_SYSCALL(symlink)(void *path_, void *link_) { + const char *path = (const char *)path_; + const char *link = (const char *)link_; + if (path) { + PRE_READ(path, __sanitizer::internal_strlen(path) + 1); + } + if (link) { + PRE_READ(link, __sanitizer::internal_strlen(link) + 1); + } +} +POST_SYSCALL(symlink)(long long res, void *path_, void *link_) { + if (res == 0) { + const char *path = (const char *)path_; + const char *link = (const char *)link_; + if (path) { + POST_READ(path, __sanitizer::internal_strlen(path) + 1); + } + if (link) { + POST_READ(link, __sanitizer::internal_strlen(link) + 1); + } + } +} +PRE_SYSCALL(readlink)(void *path_, void *buf_, long long count_) { + const char *path = (const char *)path_; + if (path) { + PRE_READ(path, __sanitizer::internal_strlen(path) + 1); + } + if (buf_) { + PRE_WRITE(buf_, count_); + } +} +POST_SYSCALL(readlink) +(long long res, void *path_, void *buf_, long long count_) { + if (res > 0) { + const char *path = (const char *)path_; + if (path) { + POST_READ(path, __sanitizer::internal_strlen(path) + 1); + } + if (buf_) { + PRE_WRITE(buf_, res); + } + } +} +PRE_SYSCALL(execve)(void *path_, void *argp_, void *envp_) { + const char *path = (const char *)path_; + char **argp = (char **)argp_; + char **envp = (char **)envp_; + if (path) { + PRE_READ(path, __sanitizer::internal_strlen(path) + 1); + } + if (argp && argp[0]) { + char *a = argp[0]; + while (a++) { + PRE_READ(a, __sanitizer::internal_strlen(a) + 1); + } + } + if (envp && envp[0]) { + char *e = envp[0]; + while (e++) { + PRE_READ(e, __sanitizer::internal_strlen(e) + 1); + } + } +} +POST_SYSCALL(execve)(long long res, void *path_, void *argp_, void *envp_) { + /* If we are here, something went wrong */ + const char *path = (const char *)path_; + char **argp = (char **)argp_; + char **envp = (char **)envp_; + if (path) { + POST_READ(path, __sanitizer::internal_strlen(path) + 1); + } + if (argp && argp[0]) { + char *a = argp[0]; + while (a++) { + POST_READ(a, __sanitizer::internal_strlen(a) + 1); + } + } + if (envp && envp[0]) { + char *e = envp[0]; + while (e++) { + POST_READ(e, __sanitizer::internal_strlen(e) + 1); + } + } +} +PRE_SYSCALL(umask)(long long newmask_) { /* Nothing to do */ } +POST_SYSCALL(umask)(long long res, long long newmask_) { /* Nothing to do */ } +PRE_SYSCALL(chroot)(void *path_) { + const char *path = (const char *)path_; + if (path) { + PRE_READ(path, __sanitizer::internal_strlen(path) + 1); + } +} +POST_SYSCALL(chroot)(long long res, void *path_) { + if (res == 0) { + const char *path = (const char *)path_; + if (path) { + POST_READ(path, __sanitizer::internal_strlen(path) + 1); + } + } +} +PRE_SYSCALL(compat_43_fstat43)(long long fd_, void *sb_) { /* TODO */ } +POST_SYSCALL(compat_43_fstat43)(long long res, long long fd_, void *sb_) { + /* TODO */ +} +PRE_SYSCALL(compat_43_ogetkerninfo) +(long long op_, void *where_, void *size_, long long arg_) { + /* TODO */ +} +POST_SYSCALL(compat_43_ogetkerninfo) +(long long res, long long op_, void *where_, void *size_, long long arg_) { + /* TODO */ +} +PRE_SYSCALL(compat_43_ogetpagesize)(void) { /* TODO */ } +POST_SYSCALL(compat_43_ogetpagesize)(long long res) { /* TODO */ } +PRE_SYSCALL(compat_12_msync)(void *addr_, long long len_) { /* TODO */ } +POST_SYSCALL(compat_12_msync)(long long res, void *addr_, long long len_) { + /* TODO */ +} +PRE_SYSCALL(vfork)(void) { /* Nothing to do */ } +POST_SYSCALL(vfork)(long long res) { /* Nothing to do */ } +/* syscall 67 has been skipped */ +/* syscall 68 has been skipped */ +/* syscall 69 has been skipped */ +/* syscall 70 has been skipped */ +PRE_SYSCALL(compat_43_ommap) +(void *addr_, long long len_, long long prot_, long long flags_, long long fd_, + long long pos_) { + /* TODO */ +} +POST_SYSCALL(compat_43_ommap) +(long long res, void *addr_, long long len_, long long prot_, long long flags_, + long long fd_, long long pos_) { + /* TODO */ +} +PRE_SYSCALL(vadvise)(long long anom_) { /* Nothing to do */ } +POST_SYSCALL(vadvise)(long long res, long long anom_) { /* Nothing to do */ } +PRE_SYSCALL(munmap)(void *addr_, long long len_) { /* Nothing to do */ } +POST_SYSCALL(munmap)(long long res, void *addr_, long long len_) { + /* Nothing to do */ +} +PRE_SYSCALL(mprotect)(void *addr_, long long len_, long long prot_) { + /* Nothing to do */ +} +POST_SYSCALL(mprotect) +(long long res, void *addr_, long long len_, long long prot_) { + /* Nothing to do */ +} +PRE_SYSCALL(madvise)(void *addr_, long long len_, long long behav_) { + /* Nothing to do */ +} +POST_SYSCALL(madvise) +(long long res, void *addr_, long long len_, long long behav_) { + /* Nothing to do */ +} +/* syscall 76 has been skipped */ +/* syscall 77 has been skipped */ +PRE_SYSCALL(mincore)(void *addr_, long long len_, void *vec_) { + /* Nothing to do */ +} +POST_SYSCALL(mincore)(long long res, void *addr_, long long len_, void *vec_) { + /* Nothing to do */ +} +PRE_SYSCALL(getgroups)(long long gidsetsize_, void *gidset_) { + unsigned int *gidset = (unsigned int *)gidset_; + if (gidset) { + PRE_WRITE(gidset, sizeof(*gidset) * gidsetsize_); + } +} +POST_SYSCALL(getgroups)(long long res, long long gidsetsize_, void *gidset_) { + if (res == 0) { + unsigned int *gidset = (unsigned int *)gidset_; + if (gidset) { + POST_WRITE(gidset, sizeof(*gidset) * gidsetsize_); + } + } +} +PRE_SYSCALL(setgroups)(long long gidsetsize_, void *gidset_) { + unsigned int *gidset = (unsigned int *)gidset_; + if (gidset) { + PRE_READ(gidset, sizeof(*gidset) * gidsetsize_); + } +} +POST_SYSCALL(setgroups)(long long res, long long gidsetsize_, void *gidset_) { + if (res == 0) { + unsigned int *gidset = (unsigned int *)gidset_; + if (gidset) { + POST_READ(gidset, sizeof(*gidset) * gidsetsize_); + } + } +} +PRE_SYSCALL(getpgrp)(void) { /* Nothing to do */ } +POST_SYSCALL(getpgrp)(long long res) { /* Nothing to do */ } +PRE_SYSCALL(setpgid)(long long pid_, long long pgid_) { /* Nothing to do */ } +POST_SYSCALL(setpgid)(long long res, long long pid_, long long pgid_) { + /* Nothing to do */ +} +PRE_SYSCALL(compat_50_setitimer)(long long which_, void *itv_, void *oitv_) { + /* TODO */ +} +POST_SYSCALL(compat_50_setitimer) +(long long res, long long which_, void *itv_, void *oitv_) { + /* TODO */ +} +PRE_SYSCALL(compat_43_owait)(void) { /* TODO */ } +POST_SYSCALL(compat_43_owait)(long long res) { /* TODO */ } +PRE_SYSCALL(compat_12_oswapon)(void *name_) { /* TODO */ } +POST_SYSCALL(compat_12_oswapon)(long long res, void *name_) { /* TODO */ } +PRE_SYSCALL(compat_50_getitimer)(long long which_, void *itv_) { /* TODO */ } +POST_SYSCALL(compat_50_getitimer)(long long res, long long which_, void *itv_) { + /* TODO */ +} +PRE_SYSCALL(compat_43_ogethostname)(void *hostname_, long long len_) { + /* TODO */ +} +POST_SYSCALL(compat_43_ogethostname) +(long long res, void *hostname_, long long len_) { + /* TODO */ +} +PRE_SYSCALL(compat_43_osethostname)(void *hostname_, long long len_) { + /* TODO */ +} +POST_SYSCALL(compat_43_osethostname) +(long long res, void *hostname_, long long len_) { + /* TODO */ +} +PRE_SYSCALL(compat_43_ogetdtablesize)(void) { /* TODO */ } +POST_SYSCALL(compat_43_ogetdtablesize)(long long res) { /* TODO */ } +PRE_SYSCALL(dup2)(long long from_, long long to_) { /* Nothing to do */ } +POST_SYSCALL(dup2)(long long res, long long from_, long long to_) { + /* Nothing to do */ +} +PRE_SYSCALL(getrandom)(void *buf_, long long buflen_, long long flags_) { + /* TODO */ +} +POST_SYSCALL(getrandom) +(long long res, void *buf_, long long buflen_, long long flags_) { + /* TODO */ +} +PRE_SYSCALL(fcntl)(long long fd_, long long cmd_, void *arg_) { + /* Nothing to do */ +} +POST_SYSCALL(fcntl)(long long res, long long fd_, long long cmd_, void *arg_) { + /* Nothing to do */ +} +PRE_SYSCALL(compat_50_select) +(long long nd_, void *in_, void *ou_, void *ex_, void *tv_) { + /* TODO */ +} +POST_SYSCALL(compat_50_select) +(long long res, long long nd_, void *in_, void *ou_, void *ex_, void *tv_) { + /* TODO */ +} +/* syscall 94 has been skipped */ +PRE_SYSCALL(fsync)(long long fd_) { /* Nothing to do */ } +POST_SYSCALL(fsync)(long long res, long long fd_) { /* Nothing to do */ } +PRE_SYSCALL(setpriority)(long long which_, long long who_, long long prio_) { + /* Nothing to do */ +} +POST_SYSCALL(setpriority) +(long long res, long long which_, long long who_, long long prio_) { + /* Nothing to do */ +} +PRE_SYSCALL(compat_30_socket) +(long long domain_, long long type_, long long protocol_) { + /* TODO */ +} +POST_SYSCALL(compat_30_socket) +(long long res, long long domain_, long long type_, long long protocol_) { + /* TODO */ +} +PRE_SYSCALL(connect)(long long s_, void *name_, long long namelen_) { + PRE_READ(name_, namelen_); +} +POST_SYSCALL(connect) +(long long res, long long s_, void *name_, long long namelen_) { + if (res == 0) { + POST_READ(name_, namelen_); + } +} +PRE_SYSCALL(compat_43_oaccept)(long long s_, void *name_, void *anamelen_) { + /* TODO */ +} +POST_SYSCALL(compat_43_oaccept) +(long long res, long long s_, void *name_, void *anamelen_) { + /* TODO */ +} +PRE_SYSCALL(getpriority)(long long which_, long long who_) { + /* Nothing to do */ +} +POST_SYSCALL(getpriority)(long long res, long long which_, long long who_) { + /* Nothing to do */ +} +PRE_SYSCALL(compat_43_osend) +(long long s_, void *buf_, long long len_, long long flags_) { + /* TODO */ +} +POST_SYSCALL(compat_43_osend) +(long long res, long long s_, void *buf_, long long len_, long long flags_) { + /* TODO */ +} +PRE_SYSCALL(compat_43_orecv) +(long long s_, void *buf_, long long len_, long long flags_) { + /* TODO */ +} +POST_SYSCALL(compat_43_orecv) +(long long res, long long s_, void *buf_, long long len_, long long flags_) { + /* TODO */ +} +PRE_SYSCALL(compat_13_sigreturn13)(void *sigcntxp_) { /* TODO */ } +POST_SYSCALL(compat_13_sigreturn13)(long long res, void *sigcntxp_) { + /* TODO */ +} +PRE_SYSCALL(bind)(long long s_, void *name_, long long namelen_) { + PRE_READ(name_, namelen_); +} +POST_SYSCALL(bind) +(long long res, long long s_, void *name_, long long namelen_) { + if (res == 0) { + PRE_READ(name_, namelen_); + } +} +PRE_SYSCALL(setsockopt) +(long long s_, long long level_, long long name_, void *val_, + long long valsize_) { + if (val_) { + PRE_READ(val_, valsize_); + } +} +POST_SYSCALL(setsockopt) +(long long res, long long s_, long long level_, long long name_, void *val_, + long long valsize_) { + if (res == 0) { + if (val_) { + POST_READ(val_, valsize_); + } + } +} +PRE_SYSCALL(listen)(long long s_, long long backlog_) { /* Nothing to do */ } +POST_SYSCALL(listen)(long long res, long long s_, long long backlog_) { + /* Nothing to do */ +} +/* syscall 107 has been skipped */ +PRE_SYSCALL(compat_43_osigvec)(long long signum_, void *nsv_, void *osv_) { + /* TODO */ +} +POST_SYSCALL(compat_43_osigvec) +(long long res, long long signum_, void *nsv_, void *osv_) { + /* TODO */ +} +PRE_SYSCALL(compat_43_osigblock)(long long mask_) { /* TODO */ } +POST_SYSCALL(compat_43_osigblock)(long long res, long long mask_) { /* TODO */ } +PRE_SYSCALL(compat_43_osigsetmask)(long long mask_) { /* TODO */ } +POST_SYSCALL(compat_43_osigsetmask)(long long res, long long mask_) { + /* TODO */ +} +PRE_SYSCALL(compat_13_sigsuspend13)(long long mask_) { /* TODO */ } +POST_SYSCALL(compat_13_sigsuspend13)(long long res, long long mask_) { + /* TODO */ +} +PRE_SYSCALL(compat_43_osigstack)(void *nss_, void *oss_) { /* TODO */ } +POST_SYSCALL(compat_43_osigstack)(long long res, void *nss_, void *oss_) { + /* TODO */ +} +PRE_SYSCALL(compat_43_orecvmsg)(long long s_, void *msg_, long long flags_) { + /* TODO */ +} +POST_SYSCALL(compat_43_orecvmsg) +(long long res, long long s_, void *msg_, long long flags_) { + /* TODO */ +} +PRE_SYSCALL(compat_43_osendmsg)(long long s_, void *msg_, long long flags_) { + /* TODO */ +} +POST_SYSCALL(compat_43_osendmsg) +(long long res, long long s_, void *msg_, long long flags_) { + /* TODO */ +} +/* syscall 115 has been skipped */ +PRE_SYSCALL(compat_50_gettimeofday)(void *tp_, void *tzp_) { /* TODO */ } +POST_SYSCALL(compat_50_gettimeofday)(long long res, void *tp_, void *tzp_) { + /* TODO */ +} +PRE_SYSCALL(compat_50_getrusage)(long long who_, void *rusage_) { /* TODO */ } +POST_SYSCALL(compat_50_getrusage) +(long long res, long long who_, void *rusage_) { + /* TODO */ +} +PRE_SYSCALL(getsockopt) +(long long s_, long long level_, long long name_, void *val_, void *avalsize_) { + /* TODO */ +} +POST_SYSCALL(getsockopt) +(long long res, long long s_, long long level_, long long name_, void *val_, + void *avalsize_) { + /* TODO */ +} +/* syscall 119 has been skipped */ +PRE_SYSCALL(readv)(long long fd_, void *iovp_, long long iovcnt_) { + struct __sanitizer_iovec *iovp = (struct __sanitizer_iovec *)iovp_; + int i; + if (iovp) { + PRE_READ(iovp, sizeof(struct __sanitizer_iovec) * iovcnt_); + for (i = 0; i < iovcnt_; i++) { + PRE_WRITE(iovp[i].iov_base, iovp[i].iov_len); + } + } +} +POST_SYSCALL(readv) +(long long res, long long fd_, void *iovp_, long long iovcnt_) { + struct __sanitizer_iovec *iovp = (struct __sanitizer_iovec *)iovp_; + int i; + uptr m, n = res; + if (res > 0) { + if (iovp) { + POST_READ(iovp, sizeof(struct __sanitizer_iovec) * iovcnt_); + for (i = 0; i < iovcnt_ && n > 0; i++) { + m = n > iovp[i].iov_len ? iovp[i].iov_len : n; + POST_WRITE(iovp[i].iov_base, m); + n -= m; + } + } + } +} +PRE_SYSCALL(writev)(long long fd_, void *iovp_, long long iovcnt_) { + struct __sanitizer_iovec *iovp = (struct __sanitizer_iovec *)iovp_; + int i; + if (iovp) { + PRE_READ(iovp, sizeof(struct __sanitizer_iovec) * iovcnt_); + for (i = 0; i < iovcnt_; i++) { + PRE_READ(iovp[i].iov_base, iovp[i].iov_len); + } + } +} +POST_SYSCALL(writev) +(long long res, long long fd_, void *iovp_, long long iovcnt_) { + struct __sanitizer_iovec *iovp = (struct __sanitizer_iovec *)iovp_; + int i; + uptr m, n = res; + if (res > 0) { + if (iovp) { + POST_READ(iovp, sizeof(struct __sanitizer_iovec) * iovcnt_); + for (i = 0; i < iovcnt_ && n > 0; i++) { + m = n > iovp[i].iov_len ? iovp[i].iov_len : n; + POST_READ(iovp[i].iov_base, m); + n -= m; + } + } + } +} +PRE_SYSCALL(compat_50_settimeofday)(void *tv_, void *tzp_) { /* TODO */ } +POST_SYSCALL(compat_50_settimeofday)(long long res, void *tv_, void *tzp_) { + /* TODO */ +} +PRE_SYSCALL(fchown)(long long fd_, long long uid_, long long gid_) { + /* Nothing to do */ +} +POST_SYSCALL(fchown) +(long long res, long long fd_, long long uid_, long long gid_) { + /* Nothing to do */ +} +PRE_SYSCALL(fchmod)(long long fd_, long long mode_) { /* Nothing to do */ } +POST_SYSCALL(fchmod)(long long res, long long fd_, long long mode_) { + /* Nothing to do */ +} +PRE_SYSCALL(compat_43_orecvfrom) +(long long s_, void *buf_, long long len_, long long flags_, void *from_, + void *fromlenaddr_) { + /* TODO */ +} +POST_SYSCALL(compat_43_orecvfrom) +(long long res, long long s_, void *buf_, long long len_, long long flags_, + void *from_, void *fromlenaddr_) { + /* TODO */ +} +PRE_SYSCALL(setreuid)(long long ruid_, long long euid_) { /* Nothing to do */ } +POST_SYSCALL(setreuid)(long long res, long long ruid_, long long euid_) { + /* Nothing to do */ +} +PRE_SYSCALL(setregid)(long long rgid_, long long egid_) { /* Nothing to do */ } +POST_SYSCALL(setregid)(long long res, long long rgid_, long long egid_) { + /* Nothing to do */ +} +PRE_SYSCALL(rename)(void *from_, void *to_) { + const char *from = (const char *)from_; + const char *to = (const char *)to_; + if (from) { + PRE_READ(from, __sanitizer::internal_strlen(from) + 1); + } + if (to) { + PRE_READ(to, __sanitizer::internal_strlen(to) + 1); + } +} +POST_SYSCALL(rename)(long long res, void *from_, void *to_) { + if (res == 0) { + const char *from = (const char *)from_; + const char *to = (const char *)to_; + if (from) { + POST_READ(from, __sanitizer::internal_strlen(from) + 1); + } + if (to) { + POST_READ(to, __sanitizer::internal_strlen(to) + 1); + } + } +} +PRE_SYSCALL(compat_43_otruncate)(void *path_, long long length_) { /* TODO */ } +POST_SYSCALL(compat_43_otruncate) +(long long res, void *path_, long long length_) { + /* TODO */ +} +PRE_SYSCALL(compat_43_oftruncate)(long long fd_, long long length_) { + /* TODO */ +} +POST_SYSCALL(compat_43_oftruncate) +(long long res, long long fd_, long long length_) { + /* TODO */ +} +PRE_SYSCALL(flock)(long long fd_, long long how_) { /* Nothing to do */ } +POST_SYSCALL(flock)(long long res, long long fd_, long long how_) { + /* Nothing to do */ +} +PRE_SYSCALL(mkfifo)(void *path_, long long mode_) { + const char *path = (const char *)path_; + if (path) { + PRE_READ(path, __sanitizer::internal_strlen(path) + 1); + } +} +POST_SYSCALL(mkfifo)(long long res, void *path_, long long mode_) { + if (res == 0) { + const char *path = (const char *)path_; + if (path) { + POST_READ(path, __sanitizer::internal_strlen(path) + 1); + } + } +} +PRE_SYSCALL(sendto) +(long long s_, void *buf_, long long len_, long long flags_, void *to_, + long long tolen_) { + PRE_READ(buf_, len_); + PRE_READ(to_, tolen_); +} +POST_SYSCALL(sendto) +(long long res, long long s_, void *buf_, long long len_, long long flags_, + void *to_, long long tolen_) { + if (res >= 0) { + POST_READ(buf_, len_); + POST_READ(to_, tolen_); + } +} +PRE_SYSCALL(shutdown)(long long s_, long long how_) { /* Nothing to do */ } +POST_SYSCALL(shutdown)(long long res, long long s_, long long how_) { + /* Nothing to do */ +} +PRE_SYSCALL(socketpair) +(long long domain_, long long type_, long long protocol_, void *rsv_) { + PRE_WRITE(rsv_, 2 * sizeof(int)); +} +POST_SYSCALL(socketpair) +(long long res, long long domain_, long long type_, long long protocol_, + void *rsv_) { + if (res == 0) { + POST_WRITE(rsv_, 2 * sizeof(int)); + } +} +PRE_SYSCALL(mkdir)(void *path_, long long mode_) { + const char *path = (const char *)path_; + if (path) { + PRE_READ(path, __sanitizer::internal_strlen(path) + 1); + } +} +POST_SYSCALL(mkdir)(long long res, void *path_, long long mode_) { + if (res == 0) { + const char *path = (const char *)path_; + if (path) { + POST_READ(path, __sanitizer::internal_strlen(path) + 1); + } + } +} +PRE_SYSCALL(rmdir)(void *path_) { + const char *path = (const char *)path_; + if (path) { + PRE_READ(path, __sanitizer::internal_strlen(path) + 1); + } +} +POST_SYSCALL(rmdir)(long long res, void *path_) { + if (res == 0) { + const char *path = (const char *)path_; + if (path) { + POST_READ(path, __sanitizer::internal_strlen(path) + 1); + } + } +} +PRE_SYSCALL(compat_50_utimes)(void *path_, void *tptr_) { /* TODO */ } +POST_SYSCALL(compat_50_utimes)(long long res, void *path_, void *tptr_) { + /* TODO */ +} +/* syscall 139 has been skipped */ +PRE_SYSCALL(compat_50_adjtime)(void *delta_, void *olddelta_) { /* TODO */ } +POST_SYSCALL(compat_50_adjtime)(long long res, void *delta_, void *olddelta_) { + /* TODO */ +} +PRE_SYSCALL(compat_43_ogetpeername)(long long fdes_, void *asa_, void *alen_) { + /* TODO */ +} +POST_SYSCALL(compat_43_ogetpeername) +(long long res, long long fdes_, void *asa_, void *alen_) { + /* TODO */ +} +PRE_SYSCALL(compat_43_ogethostid)(void) { /* TODO */ } +POST_SYSCALL(compat_43_ogethostid)(long long res) { /* TODO */ } +PRE_SYSCALL(compat_43_osethostid)(long long hostid_) { /* TODO */ } +POST_SYSCALL(compat_43_osethostid)(long long res, long long hostid_) { + /* TODO */ +} +PRE_SYSCALL(compat_43_ogetrlimit)(long long which_, void *rlp_) { /* TODO */ } +POST_SYSCALL(compat_43_ogetrlimit) +(long long res, long long which_, void *rlp_) { + /* TODO */ +} +PRE_SYSCALL(compat_43_osetrlimit)(long long which_, void *rlp_) { /* TODO */ } +POST_SYSCALL(compat_43_osetrlimit) +(long long res, long long which_, void *rlp_) { + /* TODO */ +} +PRE_SYSCALL(compat_43_okillpg)(long long pgid_, long long signum_) { + /* TODO */ +} +POST_SYSCALL(compat_43_okillpg) +(long long res, long long pgid_, long long signum_) { + /* TODO */ +} +PRE_SYSCALL(setsid)(void) { /* Nothing to do */ } +POST_SYSCALL(setsid)(long long res) { /* Nothing to do */ } +PRE_SYSCALL(compat_50_quotactl) +(void *path_, long long cmd_, long long uid_, void *arg_) { + /* TODO */ +} +POST_SYSCALL(compat_50_quotactl) +(long long res, void *path_, long long cmd_, long long uid_, void *arg_) { + /* TODO */ +} +PRE_SYSCALL(compat_43_oquota)(void) { /* TODO */ } +POST_SYSCALL(compat_43_oquota)(long long res) { /* TODO */ } +PRE_SYSCALL(compat_43_ogetsockname)(long long fdec_, void *asa_, void *alen_) { + /* TODO */ +} +POST_SYSCALL(compat_43_ogetsockname) +(long long res, long long fdec_, void *asa_, void *alen_) { + /* TODO */ +} +/* syscall 151 has been skipped */ +/* syscall 152 has been skipped */ +/* syscall 153 has been skipped */ +/* syscall 154 has been skipped */ +PRE_SYSCALL(nfssvc)(long long flag_, void *argp_) { /* Nothing to do */ } +POST_SYSCALL(nfssvc)(long long res, long long flag_, void *argp_) { + /* Nothing to do */ +} +PRE_SYSCALL(compat_43_ogetdirentries) +(long long fd_, void *buf_, long long count_, void *basep_) { + /* TODO */ +} +POST_SYSCALL(compat_43_ogetdirentries) +(long long res, long long fd_, void *buf_, long long count_, void *basep_) { + /* TODO */ +} +PRE_SYSCALL(compat_20_statfs)(void *path_, void *buf_) { /* TODO */ } +POST_SYSCALL(compat_20_statfs)(long long res, void *path_, void *buf_) { + /* TODO */ +} +PRE_SYSCALL(compat_20_fstatfs)(long long fd_, void *buf_) { /* TODO */ } +POST_SYSCALL(compat_20_fstatfs)(long long res, long long fd_, void *buf_) { + /* TODO */ +} +/* syscall 159 has been skipped */ +/* syscall 160 has been skipped */ +PRE_SYSCALL(compat_30_getfh)(void *fname_, void *fhp_) { /* TODO */ } +POST_SYSCALL(compat_30_getfh)(long long res, void *fname_, void *fhp_) { + /* TODO */ +} +PRE_SYSCALL(compat_09_ogetdomainname)(void *domainname_, long long len_) { + /* TODO */ +} +POST_SYSCALL(compat_09_ogetdomainname) +(long long res, void *domainname_, long long len_) { + /* TODO */ +} +PRE_SYSCALL(compat_09_osetdomainname)(void *domainname_, long long len_) { + /* TODO */ +} +POST_SYSCALL(compat_09_osetdomainname) +(long long res, void *domainname_, long long len_) { + /* TODO */ +} +PRE_SYSCALL(compat_09_ouname)(void *name_) { /* TODO */ } +POST_SYSCALL(compat_09_ouname)(long long res, void *name_) { /* TODO */ } +PRE_SYSCALL(sysarch)(long long op_, void *parms_) { /* TODO */ } +POST_SYSCALL(sysarch)(long long res, long long op_, void *parms_) { /* TODO */ } +PRE_SYSCALL(__futex) +(void *uaddr_, long long op_, long long val_, void *timeout_, void *uaddr2_, + long long val2_, long long val3_) { + /* TODO */ +} +POST_SYSCALL(__futex) +(long long res, void *uaddr_, long long op_, long long val_, void *timeout_, + void *uaddr2_, long long val2_, long long val3_) { + /* TODO */ +} +PRE_SYSCALL(__futex_set_robust_list)(void *head_, long long len_) { /* TODO */ } +POST_SYSCALL(__futex_set_robust_list) +(long long res, void *head_, long long len_) { + /* TODO */ +} +PRE_SYSCALL(__futex_get_robust_list) +(long long lwpid_, void **headp_, void *lenp_) { + /* TODO */ +} +POST_SYSCALL(__futex_get_robust_list) +(long long res, long long lwpid_, void **headp_, void *lenp_) { + /* TODO */ +} +#if !defined(_LP64) +PRE_SYSCALL(compat_10_osemsys) +(long long which_, long long a2_, long long a3_, long long a4_, long long a5_) { + /* TODO */ +} +POST_SYSCALL(compat_10_osemsys) +(long long res, long long which_, long long a2_, long long a3_, long long a4_, + long long a5_) { + /* TODO */ +} +#else +/* syscall 169 has been skipped */ +#endif +#if !defined(_LP64) +PRE_SYSCALL(compat_10_omsgsys) +(long long which_, long long a2_, long long a3_, long long a4_, long long a5_, + long long a6_) { + /* TODO */ +} +POST_SYSCALL(compat_10_omsgsys) +(long long res, long long which_, long long a2_, long long a3_, long long a4_, + long long a5_, long long a6_) { + /* TODO */ +} +#else +/* syscall 170 has been skipped */ +#endif +#if !defined(_LP64) +PRE_SYSCALL(compat_10_oshmsys) +(long long which_, long long a2_, long long a3_, long long a4_) { + /* TODO */ +} +POST_SYSCALL(compat_10_oshmsys) +(long long res, long long which_, long long a2_, long long a3_, long long a4_) { + /* TODO */ +} +#else +/* syscall 171 has been skipped */ +#endif +/* syscall 172 has been skipped */ +PRE_SYSCALL(pread) +(long long fd_, void *buf_, long long nbyte_, long long PAD_, + long long offset_) { + if (buf_) { + PRE_WRITE(buf_, nbyte_); + } +} +POST_SYSCALL(pread) +(long long res, long long fd_, void *buf_, long long nbyte_, long long PAD_, + long long offset_) { + if (res > 0) { + POST_WRITE(buf_, res); + } +} +PRE_SYSCALL(pwrite) +(long long fd_, void *buf_, long long nbyte_, long long PAD_, + long long offset_) { + if (buf_) { + PRE_READ(buf_, nbyte_); + } +} +POST_SYSCALL(pwrite) +(long long res, long long fd_, void *buf_, long long nbyte_, long long PAD_, + long long offset_) { + if (res > 0) { + POST_READ(buf_, res); + } +} +PRE_SYSCALL(compat_30_ntp_gettime)(void *ntvp_) { /* TODO */ } +POST_SYSCALL(compat_30_ntp_gettime)(long long res, void *ntvp_) { /* TODO */ } +#if defined(NTP) || !defined(_KERNEL_OPT) +PRE_SYSCALL(ntp_adjtime)(void *tp_) { /* Nothing to do */ } +POST_SYSCALL(ntp_adjtime)(long long res, void *tp_) { /* Nothing to do */ } +#else +/* syscall 176 has been skipped */ +#endif +/* syscall 177 has been skipped */ +/* syscall 178 has been skipped */ +/* syscall 179 has been skipped */ +/* syscall 180 has been skipped */ +PRE_SYSCALL(setgid)(long long gid_) { /* Nothing to do */ } +POST_SYSCALL(setgid)(long long res, long long gid_) { /* Nothing to do */ } +PRE_SYSCALL(setegid)(long long egid_) { /* Nothing to do */ } +POST_SYSCALL(setegid)(long long res, long long egid_) { /* Nothing to do */ } +PRE_SYSCALL(seteuid)(long long euid_) { /* Nothing to do */ } +POST_SYSCALL(seteuid)(long long res, long long euid_) { /* Nothing to do */ } +PRE_SYSCALL(lfs_bmapv)(void *fsidp_, void *blkiov_, long long blkcnt_) { + /* TODO */ +} +POST_SYSCALL(lfs_bmapv) +(long long res, void *fsidp_, void *blkiov_, long long blkcnt_) { + /* TODO */ +} +PRE_SYSCALL(lfs_markv)(void *fsidp_, void *blkiov_, long long blkcnt_) { + /* TODO */ +} +POST_SYSCALL(lfs_markv) +(long long res, void *fsidp_, void *blkiov_, long long blkcnt_) { + /* TODO */ +} +PRE_SYSCALL(lfs_segclean)(void *fsidp_, long long segment_) { /* TODO */ } +POST_SYSCALL(lfs_segclean)(long long res, void *fsidp_, long long segment_) { + /* TODO */ +} +PRE_SYSCALL(compat_50_lfs_segwait)(void *fsidp_, void *tv_) { /* TODO */ } +POST_SYSCALL(compat_50_lfs_segwait)(long long res, void *fsidp_, void *tv_) { + /* TODO */ +} +PRE_SYSCALL(compat_12_stat12)(void *path_, void *ub_) { /* TODO */ } +POST_SYSCALL(compat_12_stat12)(long long res, void *path_, void *ub_) { + /* TODO */ +} +PRE_SYSCALL(compat_12_fstat12)(long long fd_, void *sb_) { /* TODO */ } +POST_SYSCALL(compat_12_fstat12)(long long res, long long fd_, void *sb_) { + /* TODO */ +} +PRE_SYSCALL(compat_12_lstat12)(void *path_, void *ub_) { /* TODO */ } +POST_SYSCALL(compat_12_lstat12)(long long res, void *path_, void *ub_) { + /* TODO */ +} +PRE_SYSCALL(pathconf)(void *path_, long long name_) { + const char *path = (const char *)path_; + if (path) { + PRE_READ(path, __sanitizer::internal_strlen(path) + 1); + } +} +POST_SYSCALL(pathconf)(long long res, void *path_, long long name_) { + if (res != -1) { + const char *path = (const char *)path_; + if (path) { + POST_READ(path, __sanitizer::internal_strlen(path) + 1); + } + } +} +PRE_SYSCALL(fpathconf)(long long fd_, long long name_) { /* Nothing to do */ } +POST_SYSCALL(fpathconf)(long long res, long long fd_, long long name_) { + /* Nothing to do */ +} +PRE_SYSCALL(getsockopt2) +(long long s_, long long level_, long long name_, void *val_, void *avalsize_) { + /* TODO */ +} +POST_SYSCALL(getsockopt2) +(long long res, long long s_, long long level_, long long name_, void *val_, + void *avalsize_) { + /* TODO */ +} +PRE_SYSCALL(getrlimit)(long long which_, void *rlp_) { + PRE_WRITE(rlp_, struct_rlimit_sz); +} +POST_SYSCALL(getrlimit)(long long res, long long which_, void *rlp_) { + if (res == 0) { + POST_WRITE(rlp_, struct_rlimit_sz); + } +} +PRE_SYSCALL(setrlimit)(long long which_, void *rlp_) { + PRE_READ(rlp_, struct_rlimit_sz); +} +POST_SYSCALL(setrlimit)(long long res, long long which_, void *rlp_) { + if (res == 0) { + POST_READ(rlp_, struct_rlimit_sz); + } +} +PRE_SYSCALL(compat_12_getdirentries) +(long long fd_, void *buf_, long long count_, void *basep_) { + /* TODO */ +} +POST_SYSCALL(compat_12_getdirentries) +(long long res, long long fd_, void *buf_, long long count_, void *basep_) { + /* TODO */ +} +PRE_SYSCALL(mmap) +(void *addr_, long long len_, long long prot_, long long flags_, long long fd_, + long long PAD_, long long pos_) { + /* Nothing to do */ +} +POST_SYSCALL(mmap) +(long long res, void *addr_, long long len_, long long prot_, long long flags_, + long long fd_, long long PAD_, long long pos_) { + /* Nothing to do */ +} +PRE_SYSCALL(__syscall)(long long code_, long long args_[SYS_MAXSYSARGS]) { + /* Nothing to do */ +} +POST_SYSCALL(__syscall) +(long long res, long long code_, long long args_[SYS_MAXSYSARGS]) { + /* Nothing to do */ +} +PRE_SYSCALL(lseek) +(long long fd_, long long PAD_, long long offset_, long long whence_) { + /* Nothing to do */ +} +POST_SYSCALL(lseek) +(long long res, long long fd_, long long PAD_, long long offset_, + long long whence_) { + /* Nothing to do */ +} +PRE_SYSCALL(truncate)(void *path_, long long PAD_, long long length_) { + const char *path = (const char *)path_; + if (path) { + PRE_READ(path, __sanitizer::internal_strlen(path) + 1); + } +} +POST_SYSCALL(truncate) +(long long res, void *path_, long long PAD_, long long length_) { + if (res == 0) { + const char *path = (const char *)path_; + if (path) { + POST_READ(path, __sanitizer::internal_strlen(path) + 1); + } + } +} +PRE_SYSCALL(ftruncate)(long long fd_, long long PAD_, long long length_) { + /* Nothing to do */ +} +POST_SYSCALL(ftruncate) +(long long res, long long fd_, long long PAD_, long long length_) { + /* Nothing to do */ +} +PRE_SYSCALL(__sysctl) +(void *name_, long long namelen_, void *oldv_, void *oldlenp_, void *newv_, + long long newlen_) { + const int *name = (const int *)name_; + if (name) { + PRE_READ(name, namelen_ * sizeof(*name)); + } + if (newv_) { + PRE_READ(name, newlen_); + } +} +POST_SYSCALL(__sysctl) +(long long res, void *name_, long long namelen_, void *oldv_, void *oldlenp_, + void *newv_, long long newlen_) { + if (res == 0) { + const int *name = (const int *)name_; + if (name) { + POST_READ(name, namelen_ * sizeof(*name)); + } + if (newv_) { + POST_READ(name, newlen_); + } + } +} +PRE_SYSCALL(mlock)(void *addr_, long long len_) { /* Nothing to do */ } +POST_SYSCALL(mlock)(long long res, void *addr_, long long len_) { + /* Nothing to do */ +} +PRE_SYSCALL(munlock)(void *addr_, long long len_) { /* Nothing to do */ } +POST_SYSCALL(munlock)(long long res, void *addr_, long long len_) { + /* Nothing to do */ +} +PRE_SYSCALL(undelete)(void *path_) { + const char *path = (const char *)path_; + if (path) { + PRE_READ(path, __sanitizer::internal_strlen(path) + 1); + } +} +POST_SYSCALL(undelete)(long long res, void *path_) { + if (res == 0) { + const char *path = (const char *)path_; + if (path) { + POST_READ(path, __sanitizer::internal_strlen(path) + 1); + } + } +} +PRE_SYSCALL(compat_50_futimes)(long long fd_, void *tptr_) { /* TODO */ } +POST_SYSCALL(compat_50_futimes)(long long res, long long fd_, void *tptr_) { + /* TODO */ +} +PRE_SYSCALL(getpgid)(long long pid_) { /* Nothing to do */ } +POST_SYSCALL(getpgid)(long long res, long long pid_) { /* Nothing to do */ } +PRE_SYSCALL(reboot)(long long opt_, void *bootstr_) { + const char *bootstr = (const char *)bootstr_; + if (bootstr) { + PRE_READ(bootstr, __sanitizer::internal_strlen(bootstr) + 1); + } +} +POST_SYSCALL(reboot)(long long res, long long opt_, void *bootstr_) { + /* This call should never return */ + const char *bootstr = (const char *)bootstr_; + if (bootstr) { + POST_READ(bootstr, __sanitizer::internal_strlen(bootstr) + 1); + } +} +PRE_SYSCALL(poll)(void *fds_, long long nfds_, long long timeout_) { + /* Nothing to do */ +} +POST_SYSCALL(poll) +(long long res, void *fds_, long long nfds_, long long timeout_) { + /* Nothing to do */ +} +PRE_SYSCALL(afssys) +(long long id_, long long a1_, long long a2_, long long a3_, long long a4_, + long long a5_, long long a6_) { + /* TODO */ +} +POST_SYSCALL(afssys) +(long long res, long long id_, long long a1_, long long a2_, long long a3_, + long long a4_, long long a5_, long long a6_) { + /* TODO */ +} +/* syscall 211 has been skipped */ +/* syscall 212 has been skipped */ +/* syscall 213 has been skipped */ +/* syscall 214 has been skipped */ +/* syscall 215 has been skipped */ +/* syscall 216 has been skipped */ +/* syscall 217 has been skipped */ +/* syscall 218 has been skipped */ +/* syscall 219 has been skipped */ +PRE_SYSCALL(compat_14___semctl) +(long long semid_, long long semnum_, long long cmd_, void *arg_) { + /* TODO */ +} +POST_SYSCALL(compat_14___semctl) +(long long res, long long semid_, long long semnum_, long long cmd_, + void *arg_) { + /* TODO */ +} +PRE_SYSCALL(semget)(long long key_, long long nsems_, long long semflg_) { + /* Nothing to do */ +} +POST_SYSCALL(semget) +(long long res, long long key_, long long nsems_, long long semflg_) { + /* Nothing to do */ +} +PRE_SYSCALL(semop)(long long semid_, void *sops_, long long nsops_) { + if (sops_) { + PRE_READ(sops_, nsops_ * struct_sembuf_sz); + } +} +POST_SYSCALL(semop) +(long long res, long long semid_, void *sops_, long long nsops_) { + if (res == 0) { + if (sops_) { + POST_READ(sops_, nsops_ * struct_sembuf_sz); + } + } +} +PRE_SYSCALL(semconfig)(long long flag_) { /* Nothing to do */ } +POST_SYSCALL(semconfig)(long long res, long long flag_) { /* Nothing to do */ } +PRE_SYSCALL(compat_14_msgctl)(long long msqid_, long long cmd_, void *buf_) { + /* TODO */ +} +POST_SYSCALL(compat_14_msgctl) +(long long res, long long msqid_, long long cmd_, void *buf_) { + /* TODO */ +} +PRE_SYSCALL(msgget)(long long key_, long long msgflg_) { /* Nothing to do */ } +POST_SYSCALL(msgget)(long long res, long long key_, long long msgflg_) { + /* Nothing to do */ +} +PRE_SYSCALL(msgsnd) +(long long msqid_, void *msgp_, long long msgsz_, long long msgflg_) { + if (msgp_) { + PRE_READ(msgp_, msgsz_); + } +} +POST_SYSCALL(msgsnd) +(long long res, long long msqid_, void *msgp_, long long msgsz_, + long long msgflg_) { + if (res == 0) { + if (msgp_) { + POST_READ(msgp_, msgsz_); + } + } +} +PRE_SYSCALL(msgrcv) +(long long msqid_, void *msgp_, long long msgsz_, long long msgtyp_, + long long msgflg_) { + /* Nothing to do */ +} +POST_SYSCALL(msgrcv) +(long long res, long long msqid_, void *msgp_, long long msgsz_, + long long msgtyp_, long long msgflg_) { + /* Nothing to do */ +} +PRE_SYSCALL(shmat)(long long shmid_, void *shmaddr_, long long shmflg_) { + /* Nothing to do */ +} +POST_SYSCALL(shmat) +(long long res, long long shmid_, void *shmaddr_, long long shmflg_) { + /* Nothing to do */ +} +PRE_SYSCALL(compat_14_shmctl)(long long shmid_, long long cmd_, void *buf_) { + /* TODO */ +} +POST_SYSCALL(compat_14_shmctl) +(long long res, long long shmid_, long long cmd_, void *buf_) { + /* TODO */ +} +PRE_SYSCALL(shmdt)(void *shmaddr_) { /* Nothing to do */ } +POST_SYSCALL(shmdt)(long long res, void *shmaddr_) { /* Nothing to do */ } +PRE_SYSCALL(shmget)(long long key_, long long size_, long long shmflg_) { + /* Nothing to do */ +} +POST_SYSCALL(shmget) +(long long res, long long key_, long long size_, long long shmflg_) { + /* Nothing to do */ +} +PRE_SYSCALL(compat_50_clock_gettime)(long long clock_id_, void *tp_) { + /* TODO */ +} +POST_SYSCALL(compat_50_clock_gettime) +(long long res, long long clock_id_, void *tp_) { + /* TODO */ +} +PRE_SYSCALL(compat_50_clock_settime)(long long clock_id_, void *tp_) { + /* TODO */ +} +POST_SYSCALL(compat_50_clock_settime) +(long long res, long long clock_id_, void *tp_) { + /* TODO */ +} +PRE_SYSCALL(compat_50_clock_getres)(long long clock_id_, void *tp_) { + /* TODO */ +} +POST_SYSCALL(compat_50_clock_getres) +(long long res, long long clock_id_, void *tp_) { + /* TODO */ +} +PRE_SYSCALL(timer_create)(long long clock_id_, void *evp_, void *timerid_) { + /* Nothing to do */ +} +POST_SYSCALL(timer_create) +(long long res, long long clock_id_, void *evp_, void *timerid_) { + /* Nothing to do */ +} +PRE_SYSCALL(timer_delete)(long long timerid_) { /* Nothing to do */ } +POST_SYSCALL(timer_delete)(long long res, long long timerid_) { + /* Nothing to do */ +} +PRE_SYSCALL(compat_50_timer_settime) +(long long timerid_, long long flags_, void *value_, void *ovalue_) { + /* TODO */ +} +POST_SYSCALL(compat_50_timer_settime) +(long long res, long long timerid_, long long flags_, void *value_, + void *ovalue_) { + /* TODO */ +} +PRE_SYSCALL(compat_50_timer_gettime)(long long timerid_, void *value_) { + /* TODO */ +} +POST_SYSCALL(compat_50_timer_gettime) +(long long res, long long timerid_, void *value_) { + /* TODO */ +} +PRE_SYSCALL(timer_getoverrun)(long long timerid_) { /* Nothing to do */ } +POST_SYSCALL(timer_getoverrun)(long long res, long long timerid_) { + /* Nothing to do */ +} +PRE_SYSCALL(compat_50_nanosleep)(void *rqtp_, void *rmtp_) { /* TODO */ } +POST_SYSCALL(compat_50_nanosleep)(long long res, void *rqtp_, void *rmtp_) { + /* TODO */ +} +PRE_SYSCALL(fdatasync)(long long fd_) { /* Nothing to do */ } +POST_SYSCALL(fdatasync)(long long res, long long fd_) { /* Nothing to do */ } +PRE_SYSCALL(mlockall)(long long flags_) { /* Nothing to do */ } +POST_SYSCALL(mlockall)(long long res, long long flags_) { /* Nothing to do */ } +PRE_SYSCALL(munlockall)(void) { /* Nothing to do */ } +POST_SYSCALL(munlockall)(long long res) { /* Nothing to do */ } +PRE_SYSCALL(compat_50___sigtimedwait)(void *set_, void *info_, void *timeout_) { + /* TODO */ +} +POST_SYSCALL(compat_50___sigtimedwait) +(long long res, void *set_, void *info_, void *timeout_) { + /* TODO */ +} +PRE_SYSCALL(sigqueueinfo)(long long pid_, void *info_) { + if (info_) { + PRE_READ(info_, siginfo_t_sz); + } +} +POST_SYSCALL(sigqueueinfo)(long long res, long long pid_, void *info_) {} +PRE_SYSCALL(modctl)(long long cmd_, void *arg_) { /* TODO */ } +POST_SYSCALL(modctl)(long long res, long long cmd_, void *arg_) { /* TODO */ } +PRE_SYSCALL(_ksem_init)(long long value_, void *idp_) { /* Nothing to do */ } +POST_SYSCALL(_ksem_init)(long long res, long long value_, void *idp_) { + /* Nothing to do */ +} +PRE_SYSCALL(_ksem_open) +(void *name_, long long oflag_, long long mode_, long long value_, void *idp_) { + const char *name = (const char *)name_; + if (name) { + PRE_READ(name, __sanitizer::internal_strlen(name) + 1); + } +} +POST_SYSCALL(_ksem_open) +(long long res, void *name_, long long oflag_, long long mode_, + long long value_, void *idp_) { + const char *name = (const char *)name_; + if (name) { + POST_READ(name, __sanitizer::internal_strlen(name) + 1); + } +} +PRE_SYSCALL(_ksem_unlink)(void *name_) { + const char *name = (const char *)name_; + if (name) { + PRE_READ(name, __sanitizer::internal_strlen(name) + 1); + } +} +POST_SYSCALL(_ksem_unlink)(long long res, void *name_) { + const char *name = (const char *)name_; + if (name) { + POST_READ(name, __sanitizer::internal_strlen(name) + 1); + } +} +PRE_SYSCALL(_ksem_close)(long long id_) { /* Nothing to do */ } +POST_SYSCALL(_ksem_close)(long long res, long long id_) { /* Nothing to do */ } +PRE_SYSCALL(_ksem_post)(long long id_) { /* Nothing to do */ } +POST_SYSCALL(_ksem_post)(long long res, long long id_) { /* Nothing to do */ } +PRE_SYSCALL(_ksem_wait)(long long id_) { /* Nothing to do */ } +POST_SYSCALL(_ksem_wait)(long long res, long long id_) { /* Nothing to do */ } +PRE_SYSCALL(_ksem_trywait)(long long id_) { /* Nothing to do */ } +POST_SYSCALL(_ksem_trywait)(long long res, long long id_) { + /* Nothing to do */ +} +PRE_SYSCALL(_ksem_getvalue)(long long id_, void *value_) { /* Nothing to do */ } +POST_SYSCALL(_ksem_getvalue)(long long res, long long id_, void *value_) { + /* Nothing to do */ +} +PRE_SYSCALL(_ksem_destroy)(long long id_) { /* Nothing to do */ } +POST_SYSCALL(_ksem_destroy)(long long res, long long id_) { + /* Nothing to do */ +} +PRE_SYSCALL(_ksem_timedwait)(long long id_, void *abstime_) { + if (abstime_) { + PRE_READ(abstime_, struct_timespec_sz); + } +} +POST_SYSCALL(_ksem_timedwait)(long long res, long long id_, void *abstime_) {} +PRE_SYSCALL(mq_open) +(void *name_, long long oflag_, long long mode_, void *attr_) { + const char *name = (const char *)name_; + if (name) { + PRE_READ(name, __sanitizer::internal_strlen(name) + 1); + } +} +POST_SYSCALL(mq_open) +(long long res, void *name_, long long oflag_, long long mode_, void *attr_) { + const char *name = (const char *)name_; + if (name) { + POST_READ(name, __sanitizer::internal_strlen(name) + 1); + } +} +PRE_SYSCALL(mq_close)(long long mqdes_) { /* Nothing to do */ } +POST_SYSCALL(mq_close)(long long res, long long mqdes_) { /* Nothing to do */ } +PRE_SYSCALL(mq_unlink)(void *name_) { + const char *name = (const char *)name_; + if (name) { + PRE_READ(name, __sanitizer::internal_strlen(name) + 1); + } +} +POST_SYSCALL(mq_unlink)(long long res, void *name_) { + const char *name = (const char *)name_; + if (name) { + POST_READ(name, __sanitizer::internal_strlen(name) + 1); + } +} +PRE_SYSCALL(mq_getattr)(long long mqdes_, void *mqstat_) { /* Nothing to do */ } +POST_SYSCALL(mq_getattr)(long long res, long long mqdes_, void *mqstat_) { + /* Nothing to do */ +} +PRE_SYSCALL(mq_setattr)(long long mqdes_, void *mqstat_, void *omqstat_) { + if (mqstat_) { + PRE_READ(mqstat_, struct_mq_attr_sz); + } +} +POST_SYSCALL(mq_setattr) +(long long res, long long mqdes_, void *mqstat_, void *omqstat_) {} +PRE_SYSCALL(mq_notify)(long long mqdes_, void *notification_) { + if (notification_) { + PRE_READ(notification_, struct_sigevent_sz); + } +} +POST_SYSCALL(mq_notify)(long long res, long long mqdes_, void *notification_) {} +PRE_SYSCALL(mq_send) +(long long mqdes_, void *msg_ptr_, long long msg_len_, long long msg_prio_) { + if (msg_ptr_) { + PRE_READ(msg_ptr_, msg_len_); + } +} +POST_SYSCALL(mq_send) +(long long res, long long mqdes_, void *msg_ptr_, long long msg_len_, + long long msg_prio_) {} +PRE_SYSCALL(mq_receive) +(long long mqdes_, void *msg_ptr_, long long msg_len_, void *msg_prio_) { + /* Nothing to do */ +} +POST_SYSCALL(mq_receive) +(long long res, long long mqdes_, void *msg_ptr_, long long msg_len_, + void *msg_prio_) { + /* Nothing to do */ +} +PRE_SYSCALL(compat_50_mq_timedsend) +(long long mqdes_, void *msg_ptr_, long long msg_len_, long long msg_prio_, + void *abs_timeout_) { + /* TODO */ +} +POST_SYSCALL(compat_50_mq_timedsend) +(long long res, long long mqdes_, void *msg_ptr_, long long msg_len_, + long long msg_prio_, void *abs_timeout_) { + /* TODO */ +} +PRE_SYSCALL(compat_50_mq_timedreceive) +(long long mqdes_, void *msg_ptr_, long long msg_len_, void *msg_prio_, + void *abs_timeout_) { + /* TODO */ +} +POST_SYSCALL(compat_50_mq_timedreceive) +(long long res, long long mqdes_, void *msg_ptr_, long long msg_len_, + void *msg_prio_, void *abs_timeout_) { + /* TODO */ +} +/* syscall 267 has been skipped */ +/* syscall 268 has been skipped */ +/* syscall 269 has been skipped */ +PRE_SYSCALL(__posix_rename)(void *from_, void *to_) { + const char *from = (const char *)from_; + const char *to = (const char *)to_; + if (from_) { + PRE_READ(from, __sanitizer::internal_strlen(from) + 1); + } + if (to) { + PRE_READ(to, __sanitizer::internal_strlen(to) + 1); + } +} +POST_SYSCALL(__posix_rename)(long long res, void *from_, void *to_) { + const char *from = (const char *)from_; + const char *to = (const char *)to_; + if (from) { + POST_READ(from, __sanitizer::internal_strlen(from) + 1); + } + if (to) { + POST_READ(to, __sanitizer::internal_strlen(to) + 1); + } +} +PRE_SYSCALL(swapctl)(long long cmd_, void *arg_, long long misc_) { /* TODO */ } +POST_SYSCALL(swapctl) +(long long res, long long cmd_, void *arg_, long long misc_) { + /* TODO */ +} +PRE_SYSCALL(compat_30_getdents)(long long fd_, void *buf_, long long count_) { + /* TODO */ +} +POST_SYSCALL(compat_30_getdents) +(long long res, long long fd_, void *buf_, long long count_) { + /* TODO */ +} +PRE_SYSCALL(minherit)(void *addr_, long long len_, long long inherit_) { + /* Nothing to do */ +} +POST_SYSCALL(minherit) +(long long res, void *addr_, long long len_, long long inherit_) { + /* Nothing to do */ +} +PRE_SYSCALL(lchmod)(void *path_, long long mode_) { + const char *path = (const char *)path_; + if (path) { + PRE_READ(path, __sanitizer::internal_strlen(path) + 1); + } +} +POST_SYSCALL(lchmod)(long long res, void *path_, long long mode_) { + const char *path = (const char *)path_; + if (path) { + POST_READ(path, __sanitizer::internal_strlen(path) + 1); + } +} +PRE_SYSCALL(lchown)(void *path_, long long uid_, long long gid_) { + const char *path = (const char *)path_; + if (path) { + PRE_READ(path, __sanitizer::internal_strlen(path) + 1); + } +} +POST_SYSCALL(lchown) +(long long res, void *path_, long long uid_, long long gid_) { + const char *path = (const char *)path_; + if (path) { + POST_READ(path, __sanitizer::internal_strlen(path) + 1); + } +} +PRE_SYSCALL(compat_50_lutimes)(void *path_, void *tptr_) { /* TODO */ } +POST_SYSCALL(compat_50_lutimes)(long long res, void *path_, void *tptr_) { + /* TODO */ +} +PRE_SYSCALL(__msync13)(void *addr_, long long len_, long long flags_) { + /* Nothing to do */ +} +POST_SYSCALL(__msync13) +(long long res, void *addr_, long long len_, long long flags_) { + /* Nothing to do */ +} +PRE_SYSCALL(compat_30___stat13)(void *path_, void *ub_) { /* TODO */ } +POST_SYSCALL(compat_30___stat13)(long long res, void *path_, void *ub_) { + /* TODO */ +} +PRE_SYSCALL(compat_30___fstat13)(long long fd_, void *sb_) { /* TODO */ } +POST_SYSCALL(compat_30___fstat13)(long long res, long long fd_, void *sb_) { + /* TODO */ +} +PRE_SYSCALL(compat_30___lstat13)(void *path_, void *ub_) { /* TODO */ } +POST_SYSCALL(compat_30___lstat13)(long long res, void *path_, void *ub_) { + /* TODO */ +} +PRE_SYSCALL(__sigaltstack14)(void *nss_, void *oss_) { + if (nss_) { + PRE_READ(nss_, struct_sigaltstack_sz); + } + if (oss_) { + PRE_READ(oss_, struct_sigaltstack_sz); + } +} +POST_SYSCALL(__sigaltstack14)(long long res, void *nss_, void *oss_) {} +PRE_SYSCALL(__vfork14)(void) { /* Nothing to do */ } +POST_SYSCALL(__vfork14)(long long res) { /* Nothing to do */ } +PRE_SYSCALL(__posix_chown)(void *path_, long long uid_, long long gid_) { + const char *path = (const char *)path_; + if (path) { + PRE_READ(path, __sanitizer::internal_strlen(path) + 1); + } +} +POST_SYSCALL(__posix_chown) +(long long res, void *path_, long long uid_, long long gid_) { + const char *path = (const char *)path_; + if (path) { + POST_READ(path, __sanitizer::internal_strlen(path) + 1); + } +} +PRE_SYSCALL(__posix_fchown)(long long fd_, long long uid_, long long gid_) { + /* Nothing to do */ +} +POST_SYSCALL(__posix_fchown) +(long long res, long long fd_, long long uid_, long long gid_) { + /* Nothing to do */ +} +PRE_SYSCALL(__posix_lchown)(void *path_, long long uid_, long long gid_) { + const char *path = (const char *)path_; + if (path) { + PRE_READ(path, __sanitizer::internal_strlen(path) + 1); + } +} +POST_SYSCALL(__posix_lchown) +(long long res, void *path_, long long uid_, long long gid_) { + const char *path = (const char *)path_; + if (path) { + POST_READ(path, __sanitizer::internal_strlen(path) + 1); + } +} +PRE_SYSCALL(getsid)(long long pid_) { /* Nothing to do */ } +POST_SYSCALL(getsid)(long long res, long long pid_) { /* Nothing to do */ } +PRE_SYSCALL(__clone)(long long flags_, void *stack_) { /* Nothing to do */ } +POST_SYSCALL(__clone)(long long res, long long flags_, void *stack_) { + /* Nothing to do */ +} +PRE_SYSCALL(fktrace) +(long long fd_, long long ops_, long long facs_, long long pid_) { + /* Nothing to do */ +} +POST_SYSCALL(fktrace) +(long long res, long long fd_, long long ops_, long long facs_, + long long pid_) { + /* Nothing to do */ +} +PRE_SYSCALL(preadv) +(long long fd_, void *iovp_, long long iovcnt_, long long PAD_, + long long offset_) { + /* Nothing to do */ +} +POST_SYSCALL(preadv) +(long long res, long long fd_, void *iovp_, long long iovcnt_, long long PAD_, + long long offset_) { + /* Nothing to do */ +} +PRE_SYSCALL(pwritev) +(long long fd_, void *iovp_, long long iovcnt_, long long PAD_, + long long offset_) { + /* Nothing to do */ +} +POST_SYSCALL(pwritev) +(long long res, long long fd_, void *iovp_, long long iovcnt_, long long PAD_, + long long offset_) { + /* Nothing to do */ +} +PRE_SYSCALL(compat_16___sigaction14) +(long long signum_, void *nsa_, void *osa_) { + /* TODO */ +} +POST_SYSCALL(compat_16___sigaction14) +(long long res, long long signum_, void *nsa_, void *osa_) { + /* TODO */ +} +PRE_SYSCALL(__sigpending14)(void *set_) { /* Nothing to do */ } +POST_SYSCALL(__sigpending14)(long long res, void *set_) { /* Nothing to do */ } +PRE_SYSCALL(__sigprocmask14)(long long how_, void *set_, void *oset_) { + /* Nothing to do */ +} +POST_SYSCALL(__sigprocmask14) +(long long res, long long how_, void *set_, void *oset_) { + /* Nothing to do */ +} +PRE_SYSCALL(__sigsuspend14)(void *set_) { + if (set_) { + PRE_READ(set_, sizeof(__sanitizer_sigset_t)); + } +} +POST_SYSCALL(__sigsuspend14)(long long res, void *set_) { + if (set_) { + PRE_READ(set_, sizeof(__sanitizer_sigset_t)); + } +} +PRE_SYSCALL(compat_16___sigreturn14)(void *sigcntxp_) { /* TODO */ } +POST_SYSCALL(compat_16___sigreturn14)(long long res, void *sigcntxp_) { + /* TODO */ +} +PRE_SYSCALL(__getcwd)(void *bufp_, long long length_) { /* Nothing to do */ } +POST_SYSCALL(__getcwd)(long long res, void *bufp_, long long length_) { + /* Nothing to do */ +} +PRE_SYSCALL(fchroot)(long long fd_) { /* Nothing to do */ } +POST_SYSCALL(fchroot)(long long res, long long fd_) { /* Nothing to do */ } +PRE_SYSCALL(compat_30_fhopen)(void *fhp_, long long flags_) { /* TODO */ } +POST_SYSCALL(compat_30_fhopen)(long long res, void *fhp_, long long flags_) { + /* TODO */ +} +PRE_SYSCALL(compat_30_fhstat)(void *fhp_, void *sb_) { /* TODO */ } +POST_SYSCALL(compat_30_fhstat)(long long res, void *fhp_, void *sb_) { + /* TODO */ +} +PRE_SYSCALL(compat_20_fhstatfs)(void *fhp_, void *buf_) { /* TODO */ } +POST_SYSCALL(compat_20_fhstatfs)(long long res, void *fhp_, void *buf_) { + /* TODO */ +} +PRE_SYSCALL(compat_50_____semctl13) +(long long semid_, long long semnum_, long long cmd_, void *arg_) { + /* TODO */ +} +POST_SYSCALL(compat_50_____semctl13) +(long long res, long long semid_, long long semnum_, long long cmd_, + void *arg_) { + /* TODO */ +} +PRE_SYSCALL(compat_50___msgctl13) +(long long msqid_, long long cmd_, void *buf_) { + /* TODO */ +} +POST_SYSCALL(compat_50___msgctl13) +(long long res, long long msqid_, long long cmd_, void *buf_) { + /* TODO */ +} +PRE_SYSCALL(compat_50___shmctl13) +(long long shmid_, long long cmd_, void *buf_) { + /* TODO */ +} +POST_SYSCALL(compat_50___shmctl13) +(long long res, long long shmid_, long long cmd_, void *buf_) { + /* TODO */ +} +PRE_SYSCALL(lchflags)(void *path_, long long flags_) { + const char *path = (const char *)path_; + if (path) { + PRE_READ(path, __sanitizer::internal_strlen(path) + 1); + } +} +POST_SYSCALL(lchflags)(long long res, void *path_, long long flags_) { + const char *path = (const char *)path_; + if (path) { + POST_READ(path, __sanitizer::internal_strlen(path) + 1); + } +} +PRE_SYSCALL(issetugid)(void) { /* Nothing to do */ } +POST_SYSCALL(issetugid)(long long res) { /* Nothing to do */ } +PRE_SYSCALL(utrace)(void *label_, void *addr_, long long len_) { + const char *label = (const char *)label_; + if (label) { + PRE_READ(label, __sanitizer::internal_strlen(label) + 1); + } + if (addr_) { + PRE_READ(addr_, len_); + } +} +POST_SYSCALL(utrace)(long long res, void *label_, void *addr_, long long len_) { + const char *label = (const char *)label_; + if (label) { + POST_READ(label, __sanitizer::internal_strlen(label) + 1); + } + if (addr_) { + POST_READ(addr_, len_); + } +} +PRE_SYSCALL(getcontext)(void *ucp_) { /* Nothing to do */ } +POST_SYSCALL(getcontext)(long long res, void *ucp_) { /* Nothing to do */ } +PRE_SYSCALL(setcontext)(void *ucp_) { + if (ucp_) { + PRE_READ(ucp_, ucontext_t_sz(ucp_)); + } +} +POST_SYSCALL(setcontext)(long long res, void *ucp_) {} +PRE_SYSCALL(_lwp_create)(void *ucp_, long long flags_, void *new_lwp_) { + if (ucp_) { + PRE_READ(ucp_, ucontext_t_sz(ucp_)); + } +} +POST_SYSCALL(_lwp_create) +(long long res, void *ucp_, long long flags_, void *new_lwp_) {} +PRE_SYSCALL(_lwp_exit)(void) { /* Nothing to do */ } +POST_SYSCALL(_lwp_exit)(long long res) { /* Nothing to do */ } +PRE_SYSCALL(_lwp_self)(void) { /* Nothing to do */ } +POST_SYSCALL(_lwp_self)(long long res) { /* Nothing to do */ } +PRE_SYSCALL(_lwp_wait)(long long wait_for_, void *departed_) { + /* Nothing to do */ +} +POST_SYSCALL(_lwp_wait)(long long res, long long wait_for_, void *departed_) { + /* Nothing to do */ +} +PRE_SYSCALL(_lwp_suspend)(long long target_) { /* Nothing to do */ } +POST_SYSCALL(_lwp_suspend)(long long res, long long target_) { + /* Nothing to do */ +} +PRE_SYSCALL(_lwp_continue)(long long target_) { /* Nothing to do */ } +POST_SYSCALL(_lwp_continue)(long long res, long long target_) { + /* Nothing to do */ +} +PRE_SYSCALL(_lwp_wakeup)(long long target_) { /* Nothing to do */ } +POST_SYSCALL(_lwp_wakeup)(long long res, long long target_) { + /* Nothing to do */ +} +PRE_SYSCALL(_lwp_getprivate)(void) { /* Nothing to do */ } +POST_SYSCALL(_lwp_getprivate)(long long res) { /* Nothing to do */ } +PRE_SYSCALL(_lwp_setprivate)(void *ptr_) { /* Nothing to do */ } +POST_SYSCALL(_lwp_setprivate)(long long res, void *ptr_) { /* Nothing to do */ } +PRE_SYSCALL(_lwp_kill)(long long target_, long long signo_) { + /* Nothing to do */ +} +POST_SYSCALL(_lwp_kill)(long long res, long long target_, long long signo_) { + /* Nothing to do */ +} +PRE_SYSCALL(_lwp_detach)(long long target_) { /* Nothing to do */ } +POST_SYSCALL(_lwp_detach)(long long res, long long target_) { + /* Nothing to do */ +} +PRE_SYSCALL(compat_50__lwp_park) +(void *ts_, long long unpark_, void *hint_, void *unparkhint_) { + /* TODO */ +} +POST_SYSCALL(compat_50__lwp_park) +(long long res, void *ts_, long long unpark_, void *hint_, void *unparkhint_) { + /* TODO */ +} +PRE_SYSCALL(_lwp_unpark)(long long target_, void *hint_) { /* Nothing to do */ } +POST_SYSCALL(_lwp_unpark)(long long res, long long target_, void *hint_) { + /* Nothing to do */ +} +PRE_SYSCALL(_lwp_unpark_all)(void *targets_, long long ntargets_, void *hint_) { + if (targets_) { + PRE_READ(targets_, ntargets_ * sizeof(__sanitizer_lwpid_t)); + } +} +POST_SYSCALL(_lwp_unpark_all) +(long long res, void *targets_, long long ntargets_, void *hint_) {} +PRE_SYSCALL(_lwp_setname)(long long target_, void *name_) { + const char *name = (const char *)name_; + if (name) { + PRE_READ(name, __sanitizer::internal_strlen(name) + 1); + } +} +POST_SYSCALL(_lwp_setname)(long long res, long long target_, void *name_) { + const char *name = (const char *)name_; + if (name) { + POST_READ(name, __sanitizer::internal_strlen(name) + 1); + } +} +PRE_SYSCALL(_lwp_getname)(long long target_, void *name_, long long len_) { + /* Nothing to do */ +} +POST_SYSCALL(_lwp_getname) +(long long res, long long target_, void *name_, long long len_) { + /* Nothing to do */ +} +PRE_SYSCALL(_lwp_ctl)(long long features_, void **address_) { + /* Nothing to do */ +} +POST_SYSCALL(_lwp_ctl)(long long res, long long features_, void **address_) { + /* Nothing to do */ +} +/* syscall 326 has been skipped */ +/* syscall 327 has been skipped */ +/* syscall 328 has been skipped */ +/* syscall 329 has been skipped */ +PRE_SYSCALL(compat_60_sa_register) +(void *newv_, void **oldv_, long long flags_, long long stackinfo_offset_) { + /* TODO */ +} +POST_SYSCALL(compat_60_sa_register) +(long long res, void *newv_, void **oldv_, long long flags_, + long long stackinfo_offset_) { + /* TODO */ +} +PRE_SYSCALL(compat_60_sa_stacks)(long long num_, void *stacks_) { /* TODO */ } +POST_SYSCALL(compat_60_sa_stacks) +(long long res, long long num_, void *stacks_) { + /* TODO */ +} +PRE_SYSCALL(compat_60_sa_enable)(void) { /* TODO */ } +POST_SYSCALL(compat_60_sa_enable)(long long res) { /* TODO */ } +PRE_SYSCALL(compat_60_sa_setconcurrency)(long long concurrency_) { /* TODO */ } +POST_SYSCALL(compat_60_sa_setconcurrency) +(long long res, long long concurrency_) { + /* TODO */ +} +PRE_SYSCALL(compat_60_sa_yield)(void) { /* TODO */ } +POST_SYSCALL(compat_60_sa_yield)(long long res) { /* TODO */ } +PRE_SYSCALL(compat_60_sa_preempt)(long long sa_id_) { /* TODO */ } +POST_SYSCALL(compat_60_sa_preempt)(long long res, long long sa_id_) { + /* TODO */ +} +/* syscall 336 has been skipped */ +/* syscall 337 has been skipped */ +/* syscall 338 has been skipped */ +/* syscall 339 has been skipped */ +PRE_SYSCALL(__sigaction_sigtramp) +(long long signum_, void *nsa_, void *osa_, void *tramp_, long long vers_) { + if (nsa_) { + PRE_READ(nsa_, sizeof(__sanitizer_sigaction)); + } +} +POST_SYSCALL(__sigaction_sigtramp) +(long long res, long long signum_, void *nsa_, void *osa_, void *tramp_, + long long vers_) { + if (nsa_) { + PRE_READ(nsa_, sizeof(__sanitizer_sigaction)); + } +} +/* syscall 341 has been skipped */ +/* syscall 342 has been skipped */ +PRE_SYSCALL(rasctl)(void *addr_, long long len_, long long op_) { + /* Nothing to do */ +} +POST_SYSCALL(rasctl) +(long long res, void *addr_, long long len_, long long op_) { + /* Nothing to do */ +} +PRE_SYSCALL(kqueue)(void) { /* Nothing to do */ } +POST_SYSCALL(kqueue)(long long res) { /* Nothing to do */ } +PRE_SYSCALL(compat_50_kevent) +(long long fd_, void *changelist_, long long nchanges_, void *eventlist_, + long long nevents_, void *timeout_) { + /* TODO */ +} +POST_SYSCALL(compat_50_kevent) +(long long res, long long fd_, void *changelist_, long long nchanges_, + void *eventlist_, long long nevents_, void *timeout_) { + /* TODO */ +} +PRE_SYSCALL(_sched_setparam) +(long long pid_, long long lid_, long long policy_, void *params_) { + if (params_) { + PRE_READ(params_, struct_sched_param_sz); + } +} +POST_SYSCALL(_sched_setparam) +(long long res, long long pid_, long long lid_, long long policy_, + void *params_) { + if (params_) { + PRE_READ(params_, struct_sched_param_sz); + } +} +PRE_SYSCALL(_sched_getparam) +(long long pid_, long long lid_, void *policy_, void *params_) { + /* Nothing to do */ +} +POST_SYSCALL(_sched_getparam) +(long long res, long long pid_, long long lid_, void *policy_, void *params_) { + /* Nothing to do */ +} +PRE_SYSCALL(_sched_setaffinity) +(long long pid_, long long lid_, long long size_, void *cpuset_) { + if (cpuset_) { + PRE_READ(cpuset_, size_); + } +} +POST_SYSCALL(_sched_setaffinity) +(long long res, long long pid_, long long lid_, long long size_, + void *cpuset_) { + if (cpuset_) { + PRE_READ(cpuset_, size_); + } +} +PRE_SYSCALL(_sched_getaffinity) +(long long pid_, long long lid_, long long size_, void *cpuset_) { + /* Nothing to do */ +} +POST_SYSCALL(_sched_getaffinity) +(long long res, long long pid_, long long lid_, long long size_, + void *cpuset_) { + /* Nothing to do */ +} +PRE_SYSCALL(sched_yield)(void) { /* Nothing to do */ } +POST_SYSCALL(sched_yield)(long long res) { /* Nothing to do */ } +PRE_SYSCALL(_sched_protect)(long long priority_) { /* Nothing to do */ } +POST_SYSCALL(_sched_protect)(long long res, long long priority_) { + /* Nothing to do */ +} +/* syscall 352 has been skipped */ +/* syscall 353 has been skipped */ +PRE_SYSCALL(fsync_range) +(long long fd_, long long flags_, long long start_, long long length_) { + /* Nothing to do */ +} +POST_SYSCALL(fsync_range) +(long long res, long long fd_, long long flags_, long long start_, + long long length_) { + /* Nothing to do */ +} +PRE_SYSCALL(uuidgen)(void *store_, long long count_) { /* Nothing to do */ } +POST_SYSCALL(uuidgen)(long long res, void *store_, long long count_) { + /* Nothing to do */ +} +PRE_SYSCALL(compat_90_getvfsstat) +(void *buf_, long long bufsize_, long long flags_) { + /* Nothing to do */ +} +POST_SYSCALL(compat_90_getvfsstat) +(long long res, void *buf_, long long bufsize_, long long flags_) { + /* Nothing to do */ +} +PRE_SYSCALL(compat_90_statvfs1)(void *path_, void *buf_, long long flags_) { + const char *path = (const char *)path_; + if (path) { + PRE_READ(path, __sanitizer::internal_strlen(path) + 1); + } +} +POST_SYSCALL(compat_90_statvfs1) +(long long res, void *path_, void *buf_, long long flags_) { + const char *path = (const char *)path_; + if (path) { + POST_READ(path, __sanitizer::internal_strlen(path) + 1); + } +} +PRE_SYSCALL(compat_90_fstatvfs1)(long long fd_, void *buf_, long long flags_) { + /* Nothing to do */ +} +POST_SYSCALL(compat_90_fstatvfs1) +(long long res, long long fd_, void *buf_, long long flags_) { + /* Nothing to do */ +} +PRE_SYSCALL(compat_30_fhstatvfs1)(void *fhp_, void *buf_, long long flags_) { + /* TODO */ +} +POST_SYSCALL(compat_30_fhstatvfs1) +(long long res, void *fhp_, void *buf_, long long flags_) { + /* TODO */ +} +PRE_SYSCALL(extattrctl) +(void *path_, long long cmd_, void *filename_, long long attrnamespace_, + void *attrname_) { + const char *path = (const char *)path_; + if (path) { + PRE_READ(path, __sanitizer::internal_strlen(path) + 1); + } +} +POST_SYSCALL(extattrctl) +(long long res, void *path_, long long cmd_, void *filename_, + long long attrnamespace_, void *attrname_) { + const char *path = (const char *)path_; + if (path) { + POST_READ(path, __sanitizer::internal_strlen(path) + 1); + } +} +PRE_SYSCALL(extattr_set_file) +(void *path_, long long attrnamespace_, void *attrname_, void *data_, + long long nbytes_) { + const char *path = (const char *)path_; + if (path) { + PRE_READ(path, __sanitizer::internal_strlen(path) + 1); + } +} +POST_SYSCALL(extattr_set_file) +(long long res, void *path_, long long attrnamespace_, void *attrname_, + void *data_, long long nbytes_) { + const char *path = (const char *)path_; + if (path) { + POST_READ(path, __sanitizer::internal_strlen(path) + 1); + } +} +PRE_SYSCALL(extattr_get_file) +(void *path_, long long attrnamespace_, void *attrname_, void *data_, + long long nbytes_) { + const char *path = (const char *)path_; + if (path) { + PRE_READ(path, __sanitizer::internal_strlen(path) + 1); + } +} +POST_SYSCALL(extattr_get_file) +(long long res, void *path_, long long attrnamespace_, void *attrname_, + void *data_, long long nbytes_) { + const char *path = (const char *)path_; + if (path) { + POST_READ(path, __sanitizer::internal_strlen(path) + 1); + } +} +PRE_SYSCALL(extattr_delete_file) +(void *path_, long long attrnamespace_, void *attrname_) { + const char *path = (const char *)path_; + if (path) { + PRE_READ(path, __sanitizer::internal_strlen(path) + 1); + } +} +POST_SYSCALL(extattr_delete_file) +(long long res, void *path_, long long attrnamespace_, void *attrname_) { + const char *path = (const char *)path_; + if (path) { + POST_READ(path, __sanitizer::internal_strlen(path) + 1); + } +} +PRE_SYSCALL(extattr_set_fd) +(long long fd_, long long attrnamespace_, void *attrname_, void *data_, + long long nbytes_) { + /* TODO */ +} +POST_SYSCALL(extattr_set_fd) +(long long res, long long fd_, long long attrnamespace_, void *attrname_, + void *data_, long long nbytes_) { + /* TODO */ +} +PRE_SYSCALL(extattr_get_fd) +(long long fd_, long long attrnamespace_, void *attrname_, void *data_, + long long nbytes_) { + /* TODO */ +} +POST_SYSCALL(extattr_get_fd) +(long long res, long long fd_, long long attrnamespace_, void *attrname_, + void *data_, long long nbytes_) { + /* TODO */ +} +PRE_SYSCALL(extattr_delete_fd) +(long long fd_, long long attrnamespace_, void *attrname_) { + /* TODO */ +} +POST_SYSCALL(extattr_delete_fd) +(long long res, long long fd_, long long attrnamespace_, void *attrname_) { + /* TODO */ +} +PRE_SYSCALL(extattr_set_link) +(void *path_, long long attrnamespace_, void *attrname_, void *data_, + long long nbytes_) { + const char *path = (const char *)path_; + if (path) { + PRE_READ(path, __sanitizer::internal_strlen(path) + 1); + } +} +POST_SYSCALL(extattr_set_link) +(long long res, void *path_, long long attrnamespace_, void *attrname_, + void *data_, long long nbytes_) { + const char *path = (const char *)path_; + if (path) { + POST_READ(path, __sanitizer::internal_strlen(path) + 1); + } +} +PRE_SYSCALL(extattr_get_link) +(void *path_, long long attrnamespace_, void *attrname_, void *data_, + long long nbytes_) { + const char *path = (const char *)path_; + if (path) { + PRE_READ(path, __sanitizer::internal_strlen(path) + 1); + } +} +POST_SYSCALL(extattr_get_link) +(long long res, void *path_, long long attrnamespace_, void *attrname_, + void *data_, long long nbytes_) { + const char *path = (const char *)path_; + if (path) { + POST_READ(path, __sanitizer::internal_strlen(path) + 1); + } +} +PRE_SYSCALL(extattr_delete_link) +(void *path_, long long attrnamespace_, void *attrname_) { + const char *path = (const char *)path_; + if (path) { + PRE_READ(path, __sanitizer::internal_strlen(path) + 1); + } +} +POST_SYSCALL(extattr_delete_link) +(long long res, void *path_, long long attrnamespace_, void *attrname_) { + const char *path = (const char *)path_; + if (path) { + POST_READ(path, __sanitizer::internal_strlen(path) + 1); + } +} +PRE_SYSCALL(extattr_list_fd) +(long long fd_, long long attrnamespace_, void *data_, long long nbytes_) { + /* TODO */ +} +POST_SYSCALL(extattr_list_fd) +(long long res, long long fd_, long long attrnamespace_, void *data_, + long long nbytes_) { + /* TODO */ +} +PRE_SYSCALL(extattr_list_file) +(void *path_, long long attrnamespace_, void *data_, long long nbytes_) { + const char *path = (const char *)path_; + if (path) { + PRE_READ(path, __sanitizer::internal_strlen(path) + 1); + } +} +POST_SYSCALL(extattr_list_file) +(long long res, void *path_, long long attrnamespace_, void *data_, + long long nbytes_) { + const char *path = (const char *)path_; + if (path) { + POST_READ(path, __sanitizer::internal_strlen(path) + 1); + } +} +PRE_SYSCALL(extattr_list_link) +(void *path_, long long attrnamespace_, void *data_, long long nbytes_) { + const char *path = (const char *)path_; + if (path) { + PRE_READ(path, __sanitizer::internal_strlen(path) + 1); + } +} +POST_SYSCALL(extattr_list_link) +(long long res, void *path_, long long attrnamespace_, void *data_, + long long nbytes_) { + const char *path = (const char *)path_; + if (path) { + POST_READ(path, __sanitizer::internal_strlen(path) + 1); + } +} +PRE_SYSCALL(compat_50_pselect) +(long long nd_, void *in_, void *ou_, void *ex_, void *ts_, void *mask_) { + /* TODO */ +} +POST_SYSCALL(compat_50_pselect) +(long long res, long long nd_, void *in_, void *ou_, void *ex_, void *ts_, + void *mask_) { + /* TODO */ +} +PRE_SYSCALL(compat_50_pollts) +(void *fds_, long long nfds_, void *ts_, void *mask_) { + /* TODO */ +} +POST_SYSCALL(compat_50_pollts) +(long long res, void *fds_, long long nfds_, void *ts_, void *mask_) { + /* TODO */ +} +PRE_SYSCALL(setxattr) +(void *path_, void *name_, void *value_, long long size_, long long flags_) { + const char *path = (const char *)path_; + if (path) { + PRE_READ(path, __sanitizer::internal_strlen(path) + 1); + } +} +POST_SYSCALL(setxattr) +(long long res, void *path_, void *name_, void *value_, long long size_, + long long flags_) { + const char *path = (const char *)path_; + if (path) { + POST_READ(path, __sanitizer::internal_strlen(path) + 1); + } +} +PRE_SYSCALL(lsetxattr) +(void *path_, void *name_, void *value_, long long size_, long long flags_) { + const char *path = (const char *)path_; + if (path) { + PRE_READ(path, __sanitizer::internal_strlen(path) + 1); + } +} +POST_SYSCALL(lsetxattr) +(long long res, void *path_, void *name_, void *value_, long long size_, + long long flags_) { + const char *path = (const char *)path_; + if (path) { + POST_READ(path, __sanitizer::internal_strlen(path) + 1); + } +} +PRE_SYSCALL(fsetxattr) +(long long fd_, void *name_, void *value_, long long size_, long long flags_) { + /* Nothing to do */ +} +POST_SYSCALL(fsetxattr) +(long long res, long long fd_, void *name_, void *value_, long long size_, + long long flags_) { + /* Nothing to do */ +} +PRE_SYSCALL(getxattr)(void *path_, void *name_, void *value_, long long size_) { + const char *path = (const char *)path_; + if (path) { + PRE_READ(path, __sanitizer::internal_strlen(path) + 1); + } +} +POST_SYSCALL(getxattr) +(long long res, void *path_, void *name_, void *value_, long long size_) { + const char *path = (const char *)path_; + if (path) { + POST_READ(path, __sanitizer::internal_strlen(path) + 1); + } +} +PRE_SYSCALL(lgetxattr) +(void *path_, void *name_, void *value_, long long size_) { + const char *path = (const char *)path_; + if (path) { + PRE_READ(path, __sanitizer::internal_strlen(path) + 1); + } +} +POST_SYSCALL(lgetxattr) +(long long res, void *path_, void *name_, void *value_, long long size_) { + const char *path = (const char *)path_; + if (path) { + POST_READ(path, __sanitizer::internal_strlen(path) + 1); + } +} +PRE_SYSCALL(fgetxattr) +(long long fd_, void *name_, void *value_, long long size_) { + /* Nothing to do */ +} +POST_SYSCALL(fgetxattr) +(long long res, long long fd_, void *name_, void *value_, long long size_) { + /* Nothing to do */ +} +PRE_SYSCALL(listxattr)(void *path_, void *list_, long long size_) { + const char *path = (const char *)path_; + if (path) { + PRE_READ(path, __sanitizer::internal_strlen(path) + 1); + } +} +POST_SYSCALL(listxattr) +(long long res, void *path_, void *list_, long long size_) { + const char *path = (const char *)path_; + if (path) { + POST_READ(path, __sanitizer::internal_strlen(path) + 1); + } +} +PRE_SYSCALL(llistxattr)(void *path_, void *list_, long long size_) { + const char *path = (const char *)path_; + if (path) { + PRE_READ(path, __sanitizer::internal_strlen(path) + 1); + } +} +POST_SYSCALL(llistxattr) +(long long res, void *path_, void *list_, long long size_) { + const char *path = (const char *)path_; + if (path) { + POST_READ(path, __sanitizer::internal_strlen(path) + 1); + } +} +PRE_SYSCALL(flistxattr)(long long fd_, void *list_, long long size_) { + /* TODO */ +} +POST_SYSCALL(flistxattr) +(long long res, long long fd_, void *list_, long long size_) { + /* TODO */ +} +PRE_SYSCALL(removexattr)(void *path_, void *name_) { + const char *path = (const char *)path_; + if (path) { + PRE_READ(path, __sanitizer::internal_strlen(path) + 1); + } +} +POST_SYSCALL(removexattr)(long long res, void *path_, void *name_) { + const char *path = (const char *)path_; + if (path) { + POST_READ(path, __sanitizer::internal_strlen(path) + 1); + } +} +PRE_SYSCALL(lremovexattr)(void *path_, void *name_) { + const char *path = (const char *)path_; + if (path) { + PRE_READ(path, __sanitizer::internal_strlen(path) + 1); + } +} +POST_SYSCALL(lremovexattr)(long long res, void *path_, void *name_) { + const char *path = (const char *)path_; + if (path) { + POST_READ(path, __sanitizer::internal_strlen(path) + 1); + } +} +PRE_SYSCALL(fremovexattr)(long long fd_, void *name_) { /* TODO */ } +POST_SYSCALL(fremovexattr)(long long res, long long fd_, void *name_) { + /* TODO */ +} +PRE_SYSCALL(compat_50___stat30)(void *path_, void *ub_) { /* TODO */ } +POST_SYSCALL(compat_50___stat30)(long long res, void *path_, void *ub_) { + /* TODO */ +} +PRE_SYSCALL(compat_50___fstat30)(long long fd_, void *sb_) { /* TODO */ } +POST_SYSCALL(compat_50___fstat30)(long long res, long long fd_, void *sb_) { + /* TODO */ +} +PRE_SYSCALL(compat_50___lstat30)(void *path_, void *ub_) { /* TODO */ } +POST_SYSCALL(compat_50___lstat30)(long long res, void *path_, void *ub_) { + /* TODO */ +} +PRE_SYSCALL(__getdents30)(long long fd_, void *buf_, long long count_) { + /* Nothing to do */ +} +POST_SYSCALL(__getdents30) +(long long res, long long fd_, void *buf_, long long count_) { + /* Nothing to do */ +} +PRE_SYSCALL(posix_fadvise)(long long) { /* Nothing to do */ } +POST_SYSCALL(posix_fadvise)(long long res, long long) { /* Nothing to do */ } +PRE_SYSCALL(compat_30___fhstat30)(void *fhp_, void *sb_) { /* TODO */ } +POST_SYSCALL(compat_30___fhstat30)(long long res, void *fhp_, void *sb_) { + /* TODO */ +} +PRE_SYSCALL(compat_50___ntp_gettime30)(void *ntvp_) { /* TODO */ } +POST_SYSCALL(compat_50___ntp_gettime30)(long long res, void *ntvp_) { + /* TODO */ +} +PRE_SYSCALL(__socket30) +(long long domain_, long long type_, long long protocol_) { + /* Nothing to do */ +} +POST_SYSCALL(__socket30) +(long long res, long long domain_, long long type_, long long protocol_) { + /* Nothing to do */ +} +PRE_SYSCALL(__getfh30)(void *fname_, void *fhp_, void *fh_size_) { + const char *fname = (const char *)fname_; + if (fname) { + PRE_READ(fname, __sanitizer::internal_strlen(fname) + 1); + } +} +POST_SYSCALL(__getfh30) +(long long res, void *fname_, void *fhp_, void *fh_size_) { + const char *fname = (const char *)fname_; + if (res == 0) { + if (fname) { + POST_READ(fname, __sanitizer::internal_strlen(fname) + 1); + } + } +} +PRE_SYSCALL(__fhopen40)(void *fhp_, long long fh_size_, long long flags_) { + if (fhp_) { + PRE_READ(fhp_, fh_size_); + } +} +POST_SYSCALL(__fhopen40) +(long long res, void *fhp_, long long fh_size_, long long flags_) {} +PRE_SYSCALL(compat_90_fhstatvfs1) +(void *fhp_, long long fh_size_, void *buf_, long long flags_) { + if (fhp_) { + PRE_READ(fhp_, fh_size_); + } +} +POST_SYSCALL(compat_90_fhstatvfs1) +(long long res, void *fhp_, long long fh_size_, void *buf_, long long flags_) {} +PRE_SYSCALL(compat_50___fhstat40)(void *fhp_, long long fh_size_, void *sb_) { + if (fhp_) { + PRE_READ(fhp_, fh_size_); + } +} +POST_SYSCALL(compat_50___fhstat40) +(long long res, void *fhp_, long long fh_size_, void *sb_) {} +PRE_SYSCALL(aio_cancel)(long long fildes_, void *aiocbp_) { + if (aiocbp_) { + PRE_READ(aiocbp_, sizeof(struct __sanitizer_aiocb)); + } +} +POST_SYSCALL(aio_cancel)(long long res, long long fildes_, void *aiocbp_) {} +PRE_SYSCALL(aio_error)(void *aiocbp_) { + if (aiocbp_) { + PRE_READ(aiocbp_, sizeof(struct __sanitizer_aiocb)); + } +} +POST_SYSCALL(aio_error)(long long res, void *aiocbp_) {} +PRE_SYSCALL(aio_fsync)(long long op_, void *aiocbp_) { + if (aiocbp_) { + PRE_READ(aiocbp_, sizeof(struct __sanitizer_aiocb)); + } +} +POST_SYSCALL(aio_fsync)(long long res, long long op_, void *aiocbp_) {} +PRE_SYSCALL(aio_read)(void *aiocbp_) { + if (aiocbp_) { + PRE_READ(aiocbp_, sizeof(struct __sanitizer_aiocb)); + } +} +POST_SYSCALL(aio_read)(long long res, void *aiocbp_) {} +PRE_SYSCALL(aio_return)(void *aiocbp_) { + if (aiocbp_) { + PRE_READ(aiocbp_, sizeof(struct __sanitizer_aiocb)); + } +} +POST_SYSCALL(aio_return)(long long res, void *aiocbp_) {} +PRE_SYSCALL(compat_50_aio_suspend) +(void *list_, long long nent_, void *timeout_) { + /* TODO */ +} +POST_SYSCALL(compat_50_aio_suspend) +(long long res, void *list_, long long nent_, void *timeout_) { + /* TODO */ +} +PRE_SYSCALL(aio_write)(void *aiocbp_) { + if (aiocbp_) { + PRE_READ(aiocbp_, sizeof(struct __sanitizer_aiocb)); + } +} +POST_SYSCALL(aio_write)(long long res, void *aiocbp_) {} +PRE_SYSCALL(lio_listio) +(long long mode_, void *list_, long long nent_, void *sig_) { + /* Nothing to do */ +} +POST_SYSCALL(lio_listio) +(long long res, long long mode_, void *list_, long long nent_, void *sig_) { + /* Nothing to do */ +} +/* syscall 407 has been skipped */ +/* syscall 408 has been skipped */ +/* syscall 409 has been skipped */ +PRE_SYSCALL(__mount50) +(void *type_, void *path_, long long flags_, void *data_, long long data_len_) { + const char *type = (const char *)type_; + const char *path = (const char *)path_; + if (type) { + PRE_READ(type, __sanitizer::internal_strlen(type) + 1); + } + if (path) { + PRE_READ(path, __sanitizer::internal_strlen(path) + 1); + } + if (data_) { + PRE_READ(data_, data_len_); + } +} +POST_SYSCALL(__mount50) +(long long res, void *type_, void *path_, long long flags_, void *data_, + long long data_len_) { + const char *type = (const char *)type_; + const char *path = (const char *)path_; + if (type) { + POST_READ(type, __sanitizer::internal_strlen(type) + 1); + } + if (path) { + POST_READ(path, __sanitizer::internal_strlen(path) + 1); + } + if (data_) { + POST_READ(data_, data_len_); + } +} +PRE_SYSCALL(mremap) +(void *old_address_, long long old_size_, void *new_address_, + long long new_size_, long long flags_) { + /* Nothing to do */ +} +POST_SYSCALL(mremap) +(long long res, void *old_address_, long long old_size_, void *new_address_, + long long new_size_, long long flags_) { + /* Nothing to do */ +} +PRE_SYSCALL(pset_create)(void *psid_) { /* Nothing to do */ } +POST_SYSCALL(pset_create)(long long res, void *psid_) { /* Nothing to do */ } +PRE_SYSCALL(pset_destroy)(long long psid_) { /* Nothing to do */ } +POST_SYSCALL(pset_destroy)(long long res, long long psid_) { + /* Nothing to do */ +} +PRE_SYSCALL(pset_assign)(long long psid_, long long cpuid_, void *opsid_) { + /* Nothing to do */ +} +POST_SYSCALL(pset_assign) +(long long res, long long psid_, long long cpuid_, void *opsid_) { + /* Nothing to do */ +} +PRE_SYSCALL(_pset_bind) +(long long idtype_, long long first_id_, long long second_id_, long long psid_, + void *opsid_) { + /* Nothing to do */ +} +POST_SYSCALL(_pset_bind) +(long long res, long long idtype_, long long first_id_, long long second_id_, + long long psid_, void *opsid_) { + /* Nothing to do */ +} +PRE_SYSCALL(__posix_fadvise50) +(long long fd_, long long PAD_, long long offset_, long long len_, + long long advice_) { + /* Nothing to do */ +} +POST_SYSCALL(__posix_fadvise50) +(long long res, long long fd_, long long PAD_, long long offset_, + long long len_, long long advice_) { + /* Nothing to do */ +} +PRE_SYSCALL(__select50) +(long long nd_, void *in_, void *ou_, void *ex_, void *tv_) { + /* Nothing to do */ +} +POST_SYSCALL(__select50) +(long long res, long long nd_, void *in_, void *ou_, void *ex_, void *tv_) { + /* Nothing to do */ +} +PRE_SYSCALL(__gettimeofday50)(void *tp_, void *tzp_) { /* Nothing to do */ } +POST_SYSCALL(__gettimeofday50)(long long res, void *tp_, void *tzp_) { + /* Nothing to do */ +} +PRE_SYSCALL(__settimeofday50)(void *tv_, void *tzp_) { + if (tv_) { + PRE_READ(tv_, timeval_sz); + } + if (tzp_) { + PRE_READ(tzp_, struct_timezone_sz); + } +} +POST_SYSCALL(__settimeofday50)(long long res, void *tv_, void *tzp_) {} +PRE_SYSCALL(__utimes50)(void *path_, void *tptr_) { + struct __sanitizer_timespec **tptr = (struct __sanitizer_timespec **)tptr_; + const char *path = (const char *)path_; + if (path) { + PRE_READ(path, __sanitizer::internal_strlen(path) + 1); + } + if (tptr) { + PRE_READ(tptr[0], struct_timespec_sz); + PRE_READ(tptr[1], struct_timespec_sz); + } +} +POST_SYSCALL(__utimes50)(long long res, void *path_, void *tptr_) {} +PRE_SYSCALL(__adjtime50)(void *delta_, void *olddelta_) { + if (delta_) { + PRE_READ(delta_, timeval_sz); + } +} +POST_SYSCALL(__adjtime50)(long long res, void *delta_, void *olddelta_) {} +PRE_SYSCALL(__lfs_segwait50)(void *fsidp_, void *tv_) { /* TODO */ } +POST_SYSCALL(__lfs_segwait50)(long long res, void *fsidp_, void *tv_) { + /* TODO */ +} +PRE_SYSCALL(__futimes50)(long long fd_, void *tptr_) { + struct __sanitizer_timespec **tptr = (struct __sanitizer_timespec **)tptr_; + if (tptr) { + PRE_READ(tptr[0], struct_timespec_sz); + PRE_READ(tptr[1], struct_timespec_sz); + } +} +POST_SYSCALL(__futimes50)(long long res, long long fd_, void *tptr_) {} +PRE_SYSCALL(__lutimes50)(void *path_, void *tptr_) { + struct __sanitizer_timespec **tptr = (struct __sanitizer_timespec **)tptr_; + const char *path = (const char *)path_; + if (path) { + PRE_READ(path, __sanitizer::internal_strlen(path) + 1); + } + if (tptr) { + PRE_READ(tptr[0], struct_timespec_sz); + PRE_READ(tptr[1], struct_timespec_sz); + } +} +POST_SYSCALL(__lutimes50)(long long res, void *path_, void *tptr_) { + struct __sanitizer_timespec **tptr = (struct __sanitizer_timespec **)tptr_; + const char *path = (const char *)path_; + if (path) { + POST_READ(path, __sanitizer::internal_strlen(path) + 1); + } + if (tptr) { + POST_READ(tptr[0], struct_timespec_sz); + POST_READ(tptr[1], struct_timespec_sz); + } +} +PRE_SYSCALL(__setitimer50)(long long which_, void *itv_, void *oitv_) { + struct __sanitizer_itimerval *itv = (struct __sanitizer_itimerval *)itv_; + if (itv) { + PRE_READ(&itv->it_interval.tv_sec, sizeof(__sanitizer_time_t)); + PRE_READ(&itv->it_interval.tv_usec, sizeof(__sanitizer_suseconds_t)); + PRE_READ(&itv->it_value.tv_sec, sizeof(__sanitizer_time_t)); + PRE_READ(&itv->it_value.tv_usec, sizeof(__sanitizer_suseconds_t)); + } +} +POST_SYSCALL(__setitimer50) +(long long res, long long which_, void *itv_, void *oitv_) {} +PRE_SYSCALL(__getitimer50)(long long which_, void *itv_) { /* Nothing to do */ } +POST_SYSCALL(__getitimer50)(long long res, long long which_, void *itv_) { + /* Nothing to do */ +} +PRE_SYSCALL(__clock_gettime50)(long long clock_id_, void *tp_) { + /* Nothing to do */ +} +POST_SYSCALL(__clock_gettime50)(long long res, long long clock_id_, void *tp_) { + /* Nothing to do */ +} +PRE_SYSCALL(__clock_settime50)(long long clock_id_, void *tp_) { + if (tp_) { + PRE_READ(tp_, struct_timespec_sz); + } +} +POST_SYSCALL(__clock_settime50) +(long long res, long long clock_id_, void *tp_) {} +PRE_SYSCALL(__clock_getres50)(long long clock_id_, void *tp_) { + /* Nothing to do */ +} +POST_SYSCALL(__clock_getres50)(long long res, long long clock_id_, void *tp_) { + /* Nothing to do */ +} +PRE_SYSCALL(__nanosleep50)(void *rqtp_, void *rmtp_) { + if (rqtp_) { + PRE_READ(rqtp_, struct_timespec_sz); + } +} +POST_SYSCALL(__nanosleep50)(long long res, void *rqtp_, void *rmtp_) {} +PRE_SYSCALL(____sigtimedwait50)(void *set_, void *info_, void *timeout_) { + if (set_) { + PRE_READ(set_, sizeof(__sanitizer_sigset_t)); + } + if (timeout_) { + PRE_READ(timeout_, struct_timespec_sz); + } +} +POST_SYSCALL(____sigtimedwait50) +(long long res, void *set_, void *info_, void *timeout_) {} +PRE_SYSCALL(__mq_timedsend50) +(long long mqdes_, void *msg_ptr_, long long msg_len_, long long msg_prio_, + void *abs_timeout_) { + if (msg_ptr_) { + PRE_READ(msg_ptr_, msg_len_); + } + if (abs_timeout_) { + PRE_READ(abs_timeout_, struct_timespec_sz); + } +} +POST_SYSCALL(__mq_timedsend50) +(long long res, long long mqdes_, void *msg_ptr_, long long msg_len_, + long long msg_prio_, void *abs_timeout_) {} +PRE_SYSCALL(__mq_timedreceive50) +(long long mqdes_, void *msg_ptr_, long long msg_len_, void *msg_prio_, + void *abs_timeout_) { + if (msg_ptr_) { + PRE_READ(msg_ptr_, msg_len_); + } + if (abs_timeout_) { + PRE_READ(abs_timeout_, struct_timespec_sz); + } +} +POST_SYSCALL(__mq_timedreceive50) +(long long res, long long mqdes_, void *msg_ptr_, long long msg_len_, + void *msg_prio_, void *abs_timeout_) {} +PRE_SYSCALL(compat_60__lwp_park) +(void *ts_, long long unpark_, void *hint_, void *unparkhint_) { + /* TODO */ +} +POST_SYSCALL(compat_60__lwp_park) +(long long res, void *ts_, long long unpark_, void *hint_, void *unparkhint_) { + /* TODO */ +} +PRE_SYSCALL(__kevent50) +(long long fd_, void *changelist_, long long nchanges_, void *eventlist_, + long long nevents_, void *timeout_) { + if (changelist_) { + PRE_READ(changelist_, nchanges_ * struct_kevent_sz); + } + if (timeout_) { + PRE_READ(timeout_, struct_timespec_sz); + } +} +POST_SYSCALL(__kevent50) +(long long res, long long fd_, void *changelist_, long long nchanges_, + void *eventlist_, long long nevents_, void *timeout_) {} +PRE_SYSCALL(__pselect50) +(long long nd_, void *in_, void *ou_, void *ex_, void *ts_, void *mask_) { + if (ts_) { + PRE_READ(ts_, struct_timespec_sz); + } + if (mask_) { + PRE_READ(mask_, sizeof(struct __sanitizer_sigset_t)); + } +} +POST_SYSCALL(__pselect50) +(long long res, long long nd_, void *in_, void *ou_, void *ex_, void *ts_, + void *mask_) {} +PRE_SYSCALL(__pollts50)(void *fds_, long long nfds_, void *ts_, void *mask_) { + if (ts_) { + PRE_READ(ts_, struct_timespec_sz); + } + if (mask_) { + PRE_READ(mask_, sizeof(struct __sanitizer_sigset_t)); + } +} +POST_SYSCALL(__pollts50) +(long long res, void *fds_, long long nfds_, void *ts_, void *mask_) {} +PRE_SYSCALL(__aio_suspend50)(void *list_, long long nent_, void *timeout_) { + int i; + const struct aiocb *const *list = (const struct aiocb *const *)list_; + if (list) { + for (i = 0; i < nent_; i++) { + if (list[i]) { + PRE_READ(list[i], sizeof(struct __sanitizer_aiocb)); + } + } + } + if (timeout_) { + PRE_READ(timeout_, struct_timespec_sz); + } +} +POST_SYSCALL(__aio_suspend50) +(long long res, void *list_, long long nent_, void *timeout_) {} +PRE_SYSCALL(__stat50)(void *path_, void *ub_) { + const char *path = (const char *)path_; + if (path) { + PRE_READ(path, __sanitizer::internal_strlen(path) + 1); + } +} +POST_SYSCALL(__stat50)(long long res, void *path_, void *ub_) { + const char *path = (const char *)path_; + if (res == 0) { + if (path) { + POST_READ(path, __sanitizer::internal_strlen(path) + 1); + } + } +} +PRE_SYSCALL(__fstat50)(long long fd_, void *sb_) { /* Nothing to do */ } +POST_SYSCALL(__fstat50)(long long res, long long fd_, void *sb_) { + /* Nothing to do */ +} +PRE_SYSCALL(__lstat50)(void *path_, void *ub_) { + const char *path = (const char *)path_; + if (path) { + PRE_READ(path, __sanitizer::internal_strlen(path) + 1); + } +} +POST_SYSCALL(__lstat50)(long long res, void *path_, void *ub_) { + const char *path = (const char *)path_; + if (res == 0) { + if (path) { + POST_READ(path, __sanitizer::internal_strlen(path) + 1); + } + } +} +PRE_SYSCALL(____semctl50) +(long long semid_, long long semnum_, long long cmd_, void *arg_) { + /* Nothing to do */ +} +POST_SYSCALL(____semctl50) +(long long res, long long semid_, long long semnum_, long long cmd_, + void *arg_) { + /* Nothing to do */ +} +PRE_SYSCALL(__shmctl50)(long long shmid_, long long cmd_, void *buf_) { + /* Nothing to do */ +} +POST_SYSCALL(__shmctl50) +(long long res, long long shmid_, long long cmd_, void *buf_) { + /* Nothing to do */ +} +PRE_SYSCALL(__msgctl50)(long long msqid_, long long cmd_, void *buf_) { + /* Nothing to do */ +} +POST_SYSCALL(__msgctl50) +(long long res, long long msqid_, long long cmd_, void *buf_) { + /* Nothing to do */ +} +PRE_SYSCALL(__getrusage50)(long long who_, void *rusage_) { + /* Nothing to do */ +} +POST_SYSCALL(__getrusage50)(long long res, long long who_, void *rusage_) { + /* Nothing to do */ +} +PRE_SYSCALL(__timer_settime50) +(long long timerid_, long long flags_, void *value_, void *ovalue_) { + struct __sanitizer_itimerval *value = (struct __sanitizer_itimerval *)value_; + if (value) { + PRE_READ(&value->it_interval.tv_sec, sizeof(__sanitizer_time_t)); + PRE_READ(&value->it_interval.tv_usec, sizeof(__sanitizer_suseconds_t)); + PRE_READ(&value->it_value.tv_sec, sizeof(__sanitizer_time_t)); + PRE_READ(&value->it_value.tv_usec, sizeof(__sanitizer_suseconds_t)); + } +} +POST_SYSCALL(__timer_settime50) +(long long res, long long timerid_, long long flags_, void *value_, + void *ovalue_) { + struct __sanitizer_itimerval *value = (struct __sanitizer_itimerval *)value_; + if (res == 0) { + if (value) { + POST_READ(&value->it_interval.tv_sec, sizeof(__sanitizer_time_t)); + POST_READ(&value->it_interval.tv_usec, sizeof(__sanitizer_suseconds_t)); + POST_READ(&value->it_value.tv_sec, sizeof(__sanitizer_time_t)); + POST_READ(&value->it_value.tv_usec, sizeof(__sanitizer_suseconds_t)); + } + } +} +PRE_SYSCALL(__timer_gettime50)(long long timerid_, void *value_) { + /* Nothing to do */ +} +POST_SYSCALL(__timer_gettime50) +(long long res, long long timerid_, void *value_) { + /* Nothing to do */ +} +#if defined(NTP) || !defined(_KERNEL_OPT) +PRE_SYSCALL(__ntp_gettime50)(void *ntvp_) { /* Nothing to do */ } +POST_SYSCALL(__ntp_gettime50)(long long res, void *ntvp_) { + /* Nothing to do */ +} +#else +/* syscall 448 has been skipped */ +#endif +PRE_SYSCALL(__wait450) +(long long pid_, void *status_, long long options_, void *rusage_) { + /* Nothing to do */ +} +POST_SYSCALL(__wait450) +(long long res, long long pid_, void *status_, long long options_, + void *rusage_) { + /* Nothing to do */ +} +PRE_SYSCALL(__mknod50)(void *path_, long long mode_, long long dev_) { + const char *path = (const char *)path_; + if (path) { + PRE_READ(path, __sanitizer::internal_strlen(path) + 1); + } +} +POST_SYSCALL(__mknod50) +(long long res, void *path_, long long mode_, long long dev_) { + const char *path = (const char *)path_; + if (res == 0) { + if (path) { + POST_READ(path, __sanitizer::internal_strlen(path) + 1); + } + } +} +PRE_SYSCALL(__fhstat50)(void *fhp_, long long fh_size_, void *sb_) { + if (fhp_) { + PRE_READ(fhp_, fh_size_); + } +} +POST_SYSCALL(__fhstat50) +(long long res, void *fhp_, long long fh_size_, void *sb_) { + if (res == 0) { + if (fhp_) { + POST_READ(fhp_, fh_size_); + } + } +} +/* syscall 452 has been skipped */ +PRE_SYSCALL(pipe2)(void *fildes_, long long flags_) { /* Nothing to do */ } +POST_SYSCALL(pipe2)(long long res, void *fildes_, long long flags_) { + /* Nothing to do */ +} +PRE_SYSCALL(dup3)(long long from_, long long to_, long long flags_) { + /* Nothing to do */ +} +POST_SYSCALL(dup3) +(long long res, long long from_, long long to_, long long flags_) { + /* Nothing to do */ +} +PRE_SYSCALL(kqueue1)(long long flags_) { /* Nothing to do */ } +POST_SYSCALL(kqueue1)(long long res, long long flags_) { /* Nothing to do */ } +PRE_SYSCALL(paccept) +(long long s_, void *name_, void *anamelen_, void *mask_, long long flags_) { + if (mask_) { + PRE_READ(mask_, sizeof(__sanitizer_sigset_t)); + } +} +POST_SYSCALL(paccept) +(long long res, long long s_, void *name_, void *anamelen_, void *mask_, + long long flags_) { + if (res >= 0) { + if (mask_) { + PRE_READ(mask_, sizeof(__sanitizer_sigset_t)); + } + } +} +PRE_SYSCALL(linkat) +(long long fd1_, void *name1_, long long fd2_, void *name2_, long long flags_) { + const char *name1 = (const char *)name1_; + const char *name2 = (const char *)name2_; + if (name1) { + PRE_READ(name1, __sanitizer::internal_strlen(name1) + 1); + } + if (name2) { + PRE_READ(name2, __sanitizer::internal_strlen(name2) + 1); + } +} +POST_SYSCALL(linkat) +(long long res, long long fd1_, void *name1_, long long fd2_, void *name2_, + long long flags_) { + const char *name1 = (const char *)name1_; + const char *name2 = (const char *)name2_; + if (res == 0) { + if (name1) { + POST_READ(name1, __sanitizer::internal_strlen(name1) + 1); + } + if (name2) { + POST_READ(name2, __sanitizer::internal_strlen(name2) + 1); + } + } +} +PRE_SYSCALL(renameat) +(long long fromfd_, void *from_, long long tofd_, void *to_) { + const char *from = (const char *)from_; + const char *to = (const char *)to_; + if (from) { + PRE_READ(from, __sanitizer::internal_strlen(from) + 1); + } + if (to) { + PRE_READ(to, __sanitizer::internal_strlen(to) + 1); + } +} +POST_SYSCALL(renameat) +(long long res, long long fromfd_, void *from_, long long tofd_, void *to_) { + const char *from = (const char *)from_; + const char *to = (const char *)to_; + if (res == 0) { + if (from) { + POST_READ(from, __sanitizer::internal_strlen(from) + 1); + } + if (to) { + POST_READ(to, __sanitizer::internal_strlen(to) + 1); + } + } +} +PRE_SYSCALL(mkfifoat)(long long fd_, void *path_, long long mode_) { + const char *path = (const char *)path_; + if (path) { + PRE_READ(path, __sanitizer::internal_strlen(path) + 1); + } +} +POST_SYSCALL(mkfifoat) +(long long res, long long fd_, void *path_, long long mode_) { + const char *path = (const char *)path_; + if (res == 0) { + if (path) { + POST_READ(path, __sanitizer::internal_strlen(path) + 1); + } + } +} +PRE_SYSCALL(mknodat) +(long long fd_, void *path_, long long mode_, long long PAD_, long long dev_) { + const char *path = (const char *)path_; + if (path) { + PRE_READ(path, __sanitizer::internal_strlen(path) + 1); + } +} +POST_SYSCALL(mknodat) +(long long res, long long fd_, void *path_, long long mode_, long long PAD_, + long long dev_) { + const char *path = (const char *)path_; + if (res == 0) { + if (path) { + POST_READ(path, __sanitizer::internal_strlen(path) + 1); + } + } +} +PRE_SYSCALL(mkdirat)(long long fd_, void *path_, long long mode_) { + const char *path = (const char *)path_; + if (path) { + PRE_READ(path, __sanitizer::internal_strlen(path) + 1); + } +} +POST_SYSCALL(mkdirat) +(long long res, long long fd_, void *path_, long long mode_) { + const char *path = (const char *)path_; + if (res == 0) { + if (path) { + POST_READ(path, __sanitizer::internal_strlen(path) + 1); + } + } +} +PRE_SYSCALL(faccessat) +(long long fd_, void *path_, long long amode_, long long flag_) { + const char *path = (const char *)path_; + if (path) { + PRE_READ(path, __sanitizer::internal_strlen(path) + 1); + } +} +POST_SYSCALL(faccessat) +(long long res, long long fd_, void *path_, long long amode_, long long flag_) { + const char *path = (const char *)path_; + if (res == 0) { + if (path) { + POST_READ(path, __sanitizer::internal_strlen(path) + 1); + } + } +} +PRE_SYSCALL(fchmodat) +(long long fd_, void *path_, long long mode_, long long flag_) { + const char *path = (const char *)path_; + if (path) { + PRE_READ(path, __sanitizer::internal_strlen(path) + 1); + } +} +POST_SYSCALL(fchmodat) +(long long res, long long fd_, void *path_, long long mode_, long long flag_) { + const char *path = (const char *)path_; + if (res == 0) { + if (path) { + POST_READ(path, __sanitizer::internal_strlen(path) + 1); + } + } +} +PRE_SYSCALL(fchownat) +(long long fd_, void *path_, long long owner_, long long group_, + long long flag_) { + const char *path = (const char *)path_; + if (path) { + PRE_READ(path, __sanitizer::internal_strlen(path) + 1); + } +} +POST_SYSCALL(fchownat) +(long long res, long long fd_, void *path_, long long owner_, long long group_, + long long flag_) { + const char *path = (const char *)path_; + if (res == 0) { + if (path) { + POST_READ(path, __sanitizer::internal_strlen(path) + 1); + } + } +} +PRE_SYSCALL(fexecve)(long long fd_, void *argp_, void *envp_) { /* TODO */ } +POST_SYSCALL(fexecve)(long long res, long long fd_, void *argp_, void *envp_) { + /* TODO */ +} +PRE_SYSCALL(fstatat)(long long fd_, void *path_, void *buf_, long long flag_) { + const char *path = (const char *)path_; + if (path) { + PRE_READ(path, __sanitizer::internal_strlen(path) + 1); + } +} +POST_SYSCALL(fstatat) +(long long res, long long fd_, void *path_, void *buf_, long long flag_) { + const char *path = (const char *)path_; + if (path) { + POST_READ(path, __sanitizer::internal_strlen(path) + 1); + } +} +PRE_SYSCALL(utimensat) +(long long fd_, void *path_, void *tptr_, long long flag_) { + const char *path = (const char *)path_; + if (path) { + PRE_READ(path, __sanitizer::internal_strlen(path) + 1); + } + if (tptr_) { + PRE_READ(tptr_, struct_timespec_sz); + } +} +POST_SYSCALL(utimensat) +(long long res, long long fd_, void *path_, void *tptr_, long long flag_) { + const char *path = (const char *)path_; + if (res > 0) { + if (path) { + POST_READ(path, __sanitizer::internal_strlen(path) + 1); + } + if (tptr_) { + POST_READ(tptr_, struct_timespec_sz); + } + } +} +PRE_SYSCALL(openat) +(long long fd_, void *path_, long long oflags_, long long mode_) { + const char *path = (const char *)path_; + if (path) { + PRE_READ(path, __sanitizer::internal_strlen(path) + 1); + } +} +POST_SYSCALL(openat) +(long long res, long long fd_, void *path_, long long oflags_, + long long mode_) { + const char *path = (const char *)path_; + if (res > 0) { + if (path) { + POST_READ(path, __sanitizer::internal_strlen(path) + 1); + } + } +} +PRE_SYSCALL(readlinkat) +(long long fd_, void *path_, void *buf_, long long bufsize_) { + const char *path = (const char *)path_; + if (path) { + PRE_READ(path, __sanitizer::internal_strlen(path) + 1); + } +} +POST_SYSCALL(readlinkat) +(long long res, long long fd_, void *path_, void *buf_, long long bufsize_) { + const char *path = (const char *)path_; + if (res > 0) { + if (path) { + POST_READ(path, __sanitizer::internal_strlen(path) + 1); + } + } +} +PRE_SYSCALL(symlinkat)(void *path1_, long long fd_, void *path2_) { + const char *path1 = (const char *)path1_; + const char *path2 = (const char *)path2_; + if (path1) { + PRE_READ(path1, __sanitizer::internal_strlen(path1) + 1); + } + if (path2) { + PRE_READ(path2, __sanitizer::internal_strlen(path2) + 1); + } +} +POST_SYSCALL(symlinkat) +(long long res, void *path1_, long long fd_, void *path2_) { + const char *path1 = (const char *)path1_; + const char *path2 = (const char *)path2_; + if (res == 0) { + if (path1) { + POST_READ(path1, __sanitizer::internal_strlen(path1) + 1); + } + if (path2) { + POST_READ(path2, __sanitizer::internal_strlen(path2) + 1); + } + } +} +PRE_SYSCALL(unlinkat)(long long fd_, void *path_, long long flag_) { + const char *path = (const char *)path_; + if (path) { + PRE_READ(path, __sanitizer::internal_strlen(path) + 1); + } +} +POST_SYSCALL(unlinkat) +(long long res, long long fd_, void *path_, long long flag_) { + const char *path = (const char *)path_; + if (res == 0) { + if (path) { + POST_READ(path, __sanitizer::internal_strlen(path) + 1); + } + } +} +PRE_SYSCALL(futimens)(long long fd_, void *tptr_) { + struct __sanitizer_timespec **tptr = (struct __sanitizer_timespec **)tptr_; + if (tptr) { + PRE_READ(tptr[0], struct_timespec_sz); + PRE_READ(tptr[1], struct_timespec_sz); + } +} +POST_SYSCALL(futimens)(long long res, long long fd_, void *tptr_) { + struct __sanitizer_timespec **tptr = (struct __sanitizer_timespec **)tptr_; + if (res == 0) { + if (tptr) { + POST_READ(tptr[0], struct_timespec_sz); + POST_READ(tptr[1], struct_timespec_sz); + } + } +} +PRE_SYSCALL(__quotactl)(void *path_, void *args_) { + const char *path = (const char *)path_; + if (path) { + PRE_READ(path, __sanitizer::internal_strlen(path) + 1); + } +} +POST_SYSCALL(__quotactl)(long long res, void *path_, void *args_) { + const char *path = (const char *)path_; + if (res == 0) { + if (path) { + POST_READ(path, __sanitizer::internal_strlen(path) + 1); + } + } +} +PRE_SYSCALL(posix_spawn) +(void *pid_, void *path_, void *file_actions_, void *attrp_, void *argv_, + void *envp_) { + const char *path = (const char *)path_; + if (path) { + PRE_READ(path, __sanitizer::internal_strlen(path) + 1); + } +} +POST_SYSCALL(posix_spawn) +(long long res, void *pid_, void *path_, void *file_actions_, void *attrp_, + void *argv_, void *envp_) { + const char *path = (const char *)path_; + if (pid_) { + if (path) { + POST_READ(path, __sanitizer::internal_strlen(path) + 1); + } + } +} +PRE_SYSCALL(recvmmsg) +(long long s_, void *mmsg_, long long vlen_, long long flags_, void *timeout_) { + if (timeout_) { + PRE_READ(timeout_, struct_timespec_sz); + } +} +POST_SYSCALL(recvmmsg) +(long long res, long long s_, void *mmsg_, long long vlen_, long long flags_, + void *timeout_) { + if (res >= 0) { + if (timeout_) { + POST_READ(timeout_, struct_timespec_sz); + } + } +} +PRE_SYSCALL(sendmmsg) +(long long s_, void *mmsg_, long long vlen_, long long flags_) { + struct __sanitizer_mmsghdr *mmsg = (struct __sanitizer_mmsghdr *)mmsg_; + if (mmsg) { + PRE_READ(mmsg, sizeof(struct __sanitizer_mmsghdr) * + (vlen_ > 1024 ? 1024 : vlen_)); + } +} +POST_SYSCALL(sendmmsg) +(long long res, long long s_, void *mmsg_, long long vlen_, long long flags_) { + struct __sanitizer_mmsghdr *mmsg = (struct __sanitizer_mmsghdr *)mmsg_; + if (res >= 0) { + if (mmsg) { + POST_READ(mmsg, sizeof(struct __sanitizer_mmsghdr) * + (vlen_ > 1024 ? 1024 : vlen_)); + } + } +} +PRE_SYSCALL(clock_nanosleep) +(long long clock_id_, long long flags_, void *rqtp_, void *rmtp_) { + if (rqtp_) { + PRE_READ(rqtp_, struct_timespec_sz); + } +} +POST_SYSCALL(clock_nanosleep) +(long long res, long long clock_id_, long long flags_, void *rqtp_, + void *rmtp_) { + if (rqtp_) { + POST_READ(rqtp_, struct_timespec_sz); + } +} +PRE_SYSCALL(___lwp_park60) +(long long clock_id_, long long flags_, void *ts_, long long unpark_, + void *hint_, void *unparkhint_) { + if (ts_) { + PRE_READ(ts_, struct_timespec_sz); + } +} +POST_SYSCALL(___lwp_park60) +(long long res, long long clock_id_, long long flags_, void *ts_, + long long unpark_, void *hint_, void *unparkhint_) { + if (res == 0) { + if (ts_) { + POST_READ(ts_, struct_timespec_sz); + } + } +} +PRE_SYSCALL(posix_fallocate) +(long long fd_, long long PAD_, long long pos_, long long len_) { + /* Nothing to do */ +} +POST_SYSCALL(posix_fallocate) +(long long res, long long fd_, long long PAD_, long long pos_, long long len_) { + /* Nothing to do */ +} +PRE_SYSCALL(fdiscard) +(long long fd_, long long PAD_, long long pos_, long long len_) { + /* Nothing to do */ +} +POST_SYSCALL(fdiscard) +(long long res, long long fd_, long long PAD_, long long pos_, long long len_) { + /* Nothing to do */ +} +PRE_SYSCALL(wait6) +(long long idtype_, long long id_, void *status_, long long options_, + void *wru_, void *info_) { + /* Nothing to do */ +} +POST_SYSCALL(wait6) +(long long res, long long idtype_, long long id_, void *status_, + long long options_, void *wru_, void *info_) { + /* Nothing to do */ +} +PRE_SYSCALL(clock_getcpuclockid2) +(long long idtype_, long long id_, void *clock_id_) { + /* Nothing to do */ +} +POST_SYSCALL(clock_getcpuclockid2) +(long long res, long long idtype_, long long id_, void *clock_id_) { + /* Nothing to do */ +} +PRE_SYSCALL(__getvfsstat90)(void *buf_, long long bufsize_, long long flags_) { + /* Nothing to do */ +} +POST_SYSCALL(__getvfsstat90) +(long long res, void *buf_, long long bufsize_, long long flags_) { + /* Nothing to do */ +} +PRE_SYSCALL(__statvfs190)(void *path_, void *buf_, long long flags_) { + const char *path = (const char *)path_; + if (path) { + PRE_READ(path, __sanitizer::internal_strlen(path) + 1); + } +} +POST_SYSCALL(__statvfs190) +(long long res, void *path_, void *buf_, long long flags_) { + const char *path = (const char *)path_; + if (path) { + POST_READ(path, __sanitizer::internal_strlen(path) + 1); + } +} +PRE_SYSCALL(__fstatvfs190)(long long fd_, void *buf_, long long flags_) { + /* Nothing to do */ +} +POST_SYSCALL(__fstatvfs190) +(long long res, long long fd_, void *buf_, long long flags_) { + /* Nothing to do */ +} +PRE_SYSCALL(__fhstatvfs190) +(void *fhp_, long long fh_size_, void *buf_, long long flags_) { + if (fhp_) { + PRE_READ(fhp_, fh_size_); + } +} +POST_SYSCALL(__fhstatvfs190) +(long long res, void *fhp_, long long fh_size_, void *buf_, long long flags_) {} +PRE_SYSCALL(__acl_get_link)(void *path_, long long type_, void *aclp_) { + /* TODO */ +} +POST_SYSCALL(__acl_get_link) +(long long res, void *path_, long long type_, void *aclp_) { + /* TODO */ +} +PRE_SYSCALL(__acl_set_link)(void *path_, long long type_, void *aclp_) { + /* TODO */ +} +POST_SYSCALL(__acl_set_link) +(long long res, void *path_, long long type_, void *aclp_) { + /* TODO */ +} +PRE_SYSCALL(__acl_delete_link)(void *path_, long long type_) { /* TODO */ } +POST_SYSCALL(__acl_delete_link)(long long res, void *path_, long long type_) { + /* TODO */ +} +PRE_SYSCALL(__acl_aclcheck_link)(void *path_, long long type_, void *aclp_) { + /* TODO */ +} +POST_SYSCALL(__acl_aclcheck_link) +(long long res, void *path_, long long type_, void *aclp_) { + /* TODO */ +} +PRE_SYSCALL(__acl_get_file)(void *path_, long long type_, void *aclp_) { + /* TODO */ +} +POST_SYSCALL(__acl_get_file) +(long long res, void *path_, long long type_, void *aclp_) { + /* TODO */ +} +PRE_SYSCALL(__acl_set_file)(void *path_, long long type_, void *aclp_) { + /* TODO */ +} +POST_SYSCALL(__acl_set_file) +(long long res, void *path_, long long type_, void *aclp_) { + /* TODO */ +} +PRE_SYSCALL(__acl_get_fd)(long long filedes_, long long type_, void *aclp_) { + /* TODO */ +} +POST_SYSCALL(__acl_get_fd) +(long long res, long long filedes_, long long type_, void *aclp_) { + /* TODO */ +} +PRE_SYSCALL(__acl_set_fd)(long long filedes_, long long type_, void *aclp_) { + /* TODO */ +} +POST_SYSCALL(__acl_set_fd) +(long long res, long long filedes_, long long type_, void *aclp_) { + /* TODO */ +} +PRE_SYSCALL(__acl_delete_file)(void *path_, long long type_) { /* TODO */ } +POST_SYSCALL(__acl_delete_file)(long long res, void *path_, long long type_) { + /* TODO */ +} +PRE_SYSCALL(__acl_delete_fd)(long long filedes_, long long type_) { /* TODO */ } +POST_SYSCALL(__acl_delete_fd) +(long long res, long long filedes_, long long type_) { + /* TODO */ +} +PRE_SYSCALL(__acl_aclcheck_file)(void *path_, long long type_, void *aclp_) { + /* TODO */ +} +POST_SYSCALL(__acl_aclcheck_file) +(long long res, void *path_, long long type_, void *aclp_) { + /* TODO */ +} +PRE_SYSCALL(__acl_aclcheck_fd) +(long long filedes_, long long type_, void *aclp_) { + /* TODO */ +} +POST_SYSCALL(__acl_aclcheck_fd) +(long long res, long long filedes_, long long type_, void *aclp_) { + /* TODO */ +} +PRE_SYSCALL(lpathconf)(void *path_, long long name_) { /* TODO */ } +POST_SYSCALL(lpathconf)(long long res, void *path_, long long name_) { + /* TODO */ +} +#undef SYS_MAXSYSARGS +} // extern "C" + +#undef PRE_SYSCALL +#undef PRE_READ +#undef PRE_WRITE +#undef POST_SYSCALL +#undef POST_READ +#undef POST_WRITE + +#endif // SANITIZER_NETBSD diff --git a/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_termination.cpp b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_termination.cpp new file mode 100644 index 0000000000..6a54734353 --- /dev/null +++ b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_termination.cpp @@ -0,0 +1,99 @@ +//===-- sanitizer_termination.cpp -------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +/// +/// This file contains the Sanitizer termination functions CheckFailed and Die, +/// and the callback functionalities associated with them. +/// +//===----------------------------------------------------------------------===// + +#include "sanitizer_common.h" +#include "sanitizer_libc.h" + +namespace __sanitizer { + +static const int kMaxNumOfInternalDieCallbacks = 5; +static DieCallbackType InternalDieCallbacks[kMaxNumOfInternalDieCallbacks]; + +bool AddDieCallback(DieCallbackType callback) { + for (int i = 0; i < kMaxNumOfInternalDieCallbacks; i++) { + if (InternalDieCallbacks[i] == nullptr) { + InternalDieCallbacks[i] = callback; + return true; + } + } + return false; +} + +bool RemoveDieCallback(DieCallbackType callback) { + for (int i = 0; i < kMaxNumOfInternalDieCallbacks; i++) { + if (InternalDieCallbacks[i] == callback) { + internal_memmove(&InternalDieCallbacks[i], &InternalDieCallbacks[i + 1], + sizeof(InternalDieCallbacks[0]) * + (kMaxNumOfInternalDieCallbacks - i - 1)); + InternalDieCallbacks[kMaxNumOfInternalDieCallbacks - 1] = nullptr; + return true; + } + } + return false; +} + +static DieCallbackType UserDieCallback; +void SetUserDieCallback(DieCallbackType callback) { + UserDieCallback = callback; +} + +void NORETURN Die() { + if (UserDieCallback) + UserDieCallback(); + for (int i = kMaxNumOfInternalDieCallbacks - 1; i >= 0; i--) { + if (InternalDieCallbacks[i]) + InternalDieCallbacks[i](); + } + if (common_flags()->abort_on_error) + Abort(); + internal__exit(common_flags()->exitcode); +} + +static void (*CheckUnwindCallback)(); +void SetCheckUnwindCallback(void (*callback)()) { + CheckUnwindCallback = callback; +} + +void NORETURN CheckFailed(const char *file, int line, const char *cond, + u64 v1, u64 v2) { + u32 tid = GetTid(); + Printf("%s: CHECK failed: %s:%d \"%s\" (0x%zx, 0x%zx) (tid=%u)\n", + SanitizerToolName, StripModuleName(file), line, cond, (uptr)v1, + (uptr)v2, tid); + static atomic_uint32_t first_tid; + u32 cmp = 0; + if (!atomic_compare_exchange_strong(&first_tid, &cmp, tid, + memory_order_relaxed)) { + if (cmp == tid) { + // Recursing into CheckFailed. + } else { + // Another thread fails already, let it print the stack and terminate. + SleepForSeconds(2); + } + Trap(); + } + if (CheckUnwindCallback) + CheckUnwindCallback(); + Die(); +} + +} // namespace __sanitizer + +using namespace __sanitizer; + +extern "C" { +SANITIZER_INTERFACE_ATTRIBUTE +void __sanitizer_set_death_callback(void (*callback)(void)) { + SetUserDieCallback(callback); +} +} // extern "C" diff --git a/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_thread_registry.cpp b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_thread_registry.cpp new file mode 100644 index 0000000000..278f6defca --- /dev/null +++ b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_thread_registry.cpp @@ -0,0 +1,384 @@ +//===-- sanitizer_thread_registry.cpp -------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file is shared between sanitizer tools. +// +// General thread bookkeeping functionality. +//===----------------------------------------------------------------------===// + +#include "sanitizer_thread_registry.h" + +#include "sanitizer_placement_new.h" + +namespace __sanitizer { + +ThreadContextBase::ThreadContextBase(u32 tid) + : tid(tid), unique_id(0), reuse_count(), os_id(0), user_id(0), + status(ThreadStatusInvalid), detached(false), + thread_type(ThreadType::Regular), parent_tid(0), next(0) { + name[0] = '\0'; + atomic_store(&thread_destroyed, 0, memory_order_release); +} + +ThreadContextBase::~ThreadContextBase() { + // ThreadContextBase should never be deleted. + CHECK(0); +} + +void ThreadContextBase::SetName(const char *new_name) { + name[0] = '\0'; + if (new_name) { + internal_strncpy(name, new_name, sizeof(name)); + name[sizeof(name) - 1] = '\0'; + } +} + +void ThreadContextBase::SetDead() { + CHECK(status == ThreadStatusRunning || + status == ThreadStatusFinished); + status = ThreadStatusDead; + user_id = 0; + OnDead(); +} + +void ThreadContextBase::SetDestroyed() { + atomic_store(&thread_destroyed, 1, memory_order_release); +} + +bool ThreadContextBase::GetDestroyed() { + return !!atomic_load(&thread_destroyed, memory_order_acquire); +} + +void ThreadContextBase::SetJoined(void *arg) { + // FIXME(dvyukov): print message and continue (it's user error). + CHECK_EQ(false, detached); + CHECK_EQ(ThreadStatusFinished, status); + status = ThreadStatusDead; + user_id = 0; + OnJoined(arg); +} + +void ThreadContextBase::SetFinished() { + // ThreadRegistry::FinishThread calls here in ThreadStatusCreated state + // for a thread that never actually started. In that case the thread + // should go to ThreadStatusFinished regardless of whether it was created + // as detached. + if (!detached || status == ThreadStatusCreated) status = ThreadStatusFinished; + OnFinished(); +} + +void ThreadContextBase::SetStarted(tid_t _os_id, ThreadType _thread_type, + void *arg) { + status = ThreadStatusRunning; + os_id = _os_id; + thread_type = _thread_type; + OnStarted(arg); +} + +void ThreadContextBase::SetCreated(uptr _user_id, u64 _unique_id, + bool _detached, u32 _parent_tid, void *arg) { + status = ThreadStatusCreated; + user_id = _user_id; + unique_id = _unique_id; + detached = _detached; + // Parent tid makes no sense for the main thread. + if (tid != kMainTid) + parent_tid = _parent_tid; + OnCreated(arg); +} + +void ThreadContextBase::Reset() { + status = ThreadStatusInvalid; + SetName(0); + atomic_store(&thread_destroyed, 0, memory_order_release); + OnReset(); +} + +// ThreadRegistry implementation. + +ThreadRegistry::ThreadRegistry(ThreadContextFactory factory) + : ThreadRegistry(factory, UINT32_MAX, UINT32_MAX, 0) {} + +ThreadRegistry::ThreadRegistry(ThreadContextFactory factory, u32 max_threads, + u32 thread_quarantine_size, u32 max_reuse) + : context_factory_(factory), + max_threads_(max_threads), + thread_quarantine_size_(thread_quarantine_size), + max_reuse_(max_reuse), + mtx_(MutexThreadRegistry), + total_threads_(0), + alive_threads_(0), + max_alive_threads_(0), + running_threads_(0) { + dead_threads_.clear(); + invalid_threads_.clear(); +} + +void ThreadRegistry::GetNumberOfThreads(uptr *total, uptr *running, + uptr *alive) { + ThreadRegistryLock l(this); + if (total) + *total = threads_.size(); + if (running) *running = running_threads_; + if (alive) *alive = alive_threads_; +} + +uptr ThreadRegistry::GetMaxAliveThreads() { + ThreadRegistryLock l(this); + return max_alive_threads_; +} + +u32 ThreadRegistry::CreateThread(uptr user_id, bool detached, u32 parent_tid, + void *arg) { + ThreadRegistryLock l(this); + u32 tid = kInvalidTid; + ThreadContextBase *tctx = QuarantinePop(); + if (tctx) { + tid = tctx->tid; + } else if (threads_.size() < max_threads_) { + // Allocate new thread context and tid. + tid = threads_.size(); + tctx = context_factory_(tid); + threads_.push_back(tctx); + } else { +#if !SANITIZER_GO + Report("%s: Thread limit (%u threads) exceeded. Dying.\n", + SanitizerToolName, max_threads_); +#else + Printf("race: limit on %u simultaneously alive goroutines is exceeded," + " dying\n", max_threads_); +#endif + Die(); + } + CHECK_NE(tctx, 0); + CHECK_NE(tid, kInvalidTid); + CHECK_LT(tid, max_threads_); + CHECK_EQ(tctx->status, ThreadStatusInvalid); + alive_threads_++; + if (max_alive_threads_ < alive_threads_) { + max_alive_threads_++; + CHECK_EQ(alive_threads_, max_alive_threads_); + } + if (user_id) { + // Ensure that user_id is unique. If it's not the case we are screwed. + // Ignoring this situation may lead to very hard to debug false + // positives later (e.g. if we join a wrong thread). + CHECK(live_.try_emplace(user_id, tid).second); + } + tctx->SetCreated(user_id, total_threads_++, detached, + parent_tid, arg); + return tid; +} + +void ThreadRegistry::RunCallbackForEachThreadLocked(ThreadCallback cb, + void *arg) { + CheckLocked(); + for (u32 tid = 0; tid < threads_.size(); tid++) { + ThreadContextBase *tctx = threads_[tid]; + if (tctx == 0) + continue; + cb(tctx, arg); + } +} + +u32 ThreadRegistry::FindThread(FindThreadCallback cb, void *arg) { + ThreadRegistryLock l(this); + for (u32 tid = 0; tid < threads_.size(); tid++) { + ThreadContextBase *tctx = threads_[tid]; + if (tctx != 0 && cb(tctx, arg)) + return tctx->tid; + } + return kInvalidTid; +} + +ThreadContextBase * +ThreadRegistry::FindThreadContextLocked(FindThreadCallback cb, void *arg) { + CheckLocked(); + for (u32 tid = 0; tid < threads_.size(); tid++) { + ThreadContextBase *tctx = threads_[tid]; + if (tctx != 0 && cb(tctx, arg)) + return tctx; + } + return 0; +} + +static bool FindThreadContextByOsIdCallback(ThreadContextBase *tctx, + void *arg) { + return (tctx->os_id == (uptr)arg && tctx->status != ThreadStatusInvalid && + tctx->status != ThreadStatusDead); +} + +ThreadContextBase *ThreadRegistry::FindThreadContextByOsIDLocked(tid_t os_id) { + return FindThreadContextLocked(FindThreadContextByOsIdCallback, + (void *)os_id); +} + +void ThreadRegistry::SetThreadName(u32 tid, const char *name) { + ThreadRegistryLock l(this); + ThreadContextBase *tctx = threads_[tid]; + CHECK_NE(tctx, 0); + CHECK_EQ(SANITIZER_FUCHSIA ? ThreadStatusCreated : ThreadStatusRunning, + tctx->status); + tctx->SetName(name); +} + +void ThreadRegistry::SetThreadNameByUserId(uptr user_id, const char *name) { + ThreadRegistryLock l(this); + if (const auto *tid = live_.find(user_id)) + threads_[tid->second]->SetName(name); +} + +void ThreadRegistry::DetachThread(u32 tid, void *arg) { + ThreadRegistryLock l(this); + ThreadContextBase *tctx = threads_[tid]; + CHECK_NE(tctx, 0); + if (tctx->status == ThreadStatusInvalid) { + Report("%s: Detach of non-existent thread\n", SanitizerToolName); + return; + } + tctx->OnDetached(arg); + if (tctx->status == ThreadStatusFinished) { + if (tctx->user_id) + live_.erase(tctx->user_id); + tctx->SetDead(); + QuarantinePush(tctx); + } else { + tctx->detached = true; + } +} + +void ThreadRegistry::JoinThread(u32 tid, void *arg) { + bool destroyed = false; + do { + { + ThreadRegistryLock l(this); + ThreadContextBase *tctx = threads_[tid]; + CHECK_NE(tctx, 0); + if (tctx->status == ThreadStatusInvalid) { + Report("%s: Join of non-existent thread\n", SanitizerToolName); + return; + } + if ((destroyed = tctx->GetDestroyed())) { + if (tctx->user_id) + live_.erase(tctx->user_id); + tctx->SetJoined(arg); + QuarantinePush(tctx); + } + } + if (!destroyed) + internal_sched_yield(); + } while (!destroyed); +} + +// Normally this is called when the thread is about to exit. If +// called in ThreadStatusCreated state, then this thread was never +// really started. We just did CreateThread for a prospective new +// thread before trying to create it, and then failed to actually +// create it, and so never called StartThread. +ThreadStatus ThreadRegistry::FinishThread(u32 tid) { + ThreadRegistryLock l(this); + CHECK_GT(alive_threads_, 0); + alive_threads_--; + ThreadContextBase *tctx = threads_[tid]; + CHECK_NE(tctx, 0); + bool dead = tctx->detached; + ThreadStatus prev_status = tctx->status; + if (tctx->status == ThreadStatusRunning) { + CHECK_GT(running_threads_, 0); + running_threads_--; + } else { + // The thread never really existed. + CHECK_EQ(tctx->status, ThreadStatusCreated); + dead = true; + } + tctx->SetFinished(); + if (dead) { + if (tctx->user_id) + live_.erase(tctx->user_id); + tctx->SetDead(); + QuarantinePush(tctx); + } + tctx->SetDestroyed(); + return prev_status; +} + +void ThreadRegistry::StartThread(u32 tid, tid_t os_id, ThreadType thread_type, + void *arg) { + ThreadRegistryLock l(this); + running_threads_++; + ThreadContextBase *tctx = threads_[tid]; + CHECK_NE(tctx, 0); + CHECK_EQ(ThreadStatusCreated, tctx->status); + tctx->SetStarted(os_id, thread_type, arg); +} + +void ThreadRegistry::QuarantinePush(ThreadContextBase *tctx) { + if (tctx->tid == 0) + return; // Don't reuse the main thread. It's a special snowflake. + dead_threads_.push_back(tctx); + if (dead_threads_.size() <= thread_quarantine_size_) + return; + tctx = dead_threads_.front(); + dead_threads_.pop_front(); + CHECK_EQ(tctx->status, ThreadStatusDead); + tctx->Reset(); + tctx->reuse_count++; + if (max_reuse_ > 0 && tctx->reuse_count >= max_reuse_) + return; + invalid_threads_.push_back(tctx); +} + +ThreadContextBase *ThreadRegistry::QuarantinePop() { + if (invalid_threads_.size() == 0) + return 0; + ThreadContextBase *tctx = invalid_threads_.front(); + invalid_threads_.pop_front(); + return tctx; +} + +u32 ThreadRegistry::ConsumeThreadUserId(uptr user_id) { + ThreadRegistryLock l(this); + u32 tid; + auto *t = live_.find(user_id); + CHECK(t); + tid = t->second; + live_.erase(t); + auto *tctx = threads_[tid]; + CHECK_EQ(tctx->user_id, user_id); + tctx->user_id = 0; + return tid; +} + +void ThreadRegistry::SetThreadUserId(u32 tid, uptr user_id) { + ThreadRegistryLock l(this); + ThreadContextBase *tctx = threads_[tid]; + CHECK_NE(tctx, 0); + CHECK_NE(tctx->status, ThreadStatusInvalid); + CHECK_NE(tctx->status, ThreadStatusDead); + CHECK_EQ(tctx->user_id, 0); + tctx->user_id = user_id; + CHECK(live_.try_emplace(user_id, tctx->tid).second); +} + +u32 ThreadRegistry::OnFork(u32 tid) { + ThreadRegistryLock l(this); + // We only purge user_id (pthread_t) of live threads because + // they cause CHECK failures if new threads with matching pthread_t + // created after fork. + // Potentially we could purge more info (ThreadContextBase themselves), + // but it's hard to test and easy to introduce new issues by doing this. + for (auto *tctx : threads_) { + if (tctx->tid == tid || !tctx->user_id) + continue; + CHECK(live_.erase(tctx->user_id)); + tctx->user_id = 0; + } + return alive_threads_; +} + +} // namespace __sanitizer diff --git a/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_thread_registry.h b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_thread_registry.h new file mode 100644 index 0000000000..2c7e5c276f --- /dev/null +++ b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_thread_registry.h @@ -0,0 +1,168 @@ +//===-- sanitizer_thread_registry.h -----------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file is shared between sanitizer tools. +// +// General thread bookkeeping functionality. +//===----------------------------------------------------------------------===// + +#ifndef SANITIZER_THREAD_REGISTRY_H +#define SANITIZER_THREAD_REGISTRY_H + +#include "sanitizer_common.h" +#include "sanitizer_dense_map.h" +#include "sanitizer_list.h" +#include "sanitizer_mutex.h" + +namespace __sanitizer { + +enum ThreadStatus { + ThreadStatusInvalid, // Non-existent thread, data is invalid. + ThreadStatusCreated, // Created but not yet running. + ThreadStatusRunning, // The thread is currently running. + ThreadStatusFinished, // Joinable thread is finished but not yet joined. + ThreadStatusDead // Joined, but some info is still available. +}; + +enum class ThreadType { + Regular, // Normal thread + Worker, // macOS Grand Central Dispatch (GCD) worker thread + Fiber, // Fiber +}; + +// Generic thread context. Specific sanitizer tools may inherit from it. +// If thread is dead, context may optionally be reused for a new thread. +class ThreadContextBase { + public: + explicit ThreadContextBase(u32 tid); + const u32 tid; // Thread ID. Main thread should have tid = 0. + u64 unique_id; // Unique thread ID. + u32 reuse_count; // Number of times this tid was reused. + tid_t os_id; // PID (used for reporting). + uptr user_id; // Some opaque user thread id (e.g. pthread_t). + char name[64]; // As annotated by user. + + ThreadStatus status; + bool detached; + ThreadType thread_type; + + u32 parent_tid; + ThreadContextBase *next; // For storing thread contexts in a list. + + atomic_uint32_t thread_destroyed; // To address race of Joined vs Finished + + void SetName(const char *new_name); + + void SetDead(); + void SetJoined(void *arg); + void SetFinished(); + void SetStarted(tid_t _os_id, ThreadType _thread_type, void *arg); + void SetCreated(uptr _user_id, u64 _unique_id, bool _detached, + u32 _parent_tid, void *arg); + void Reset(); + + void SetDestroyed(); + bool GetDestroyed(); + + // The following methods may be overriden by subclasses. + // Some of them take opaque arg that may be optionally be used + // by subclasses. + virtual void OnDead() {} + virtual void OnJoined(void *arg) {} + virtual void OnFinished() {} + virtual void OnStarted(void *arg) {} + virtual void OnCreated(void *arg) {} + virtual void OnReset() {} + virtual void OnDetached(void *arg) {} + + protected: + ~ThreadContextBase(); +}; + +typedef ThreadContextBase* (*ThreadContextFactory)(u32 tid); + +class SANITIZER_MUTEX ThreadRegistry { + public: + ThreadRegistry(ThreadContextFactory factory); + ThreadRegistry(ThreadContextFactory factory, u32 max_threads, + u32 thread_quarantine_size, u32 max_reuse); + void GetNumberOfThreads(uptr *total = nullptr, uptr *running = nullptr, + uptr *alive = nullptr); + uptr GetMaxAliveThreads(); + + void Lock() SANITIZER_ACQUIRE() { mtx_.Lock(); } + void CheckLocked() const SANITIZER_CHECK_LOCKED() { mtx_.CheckLocked(); } + void Unlock() SANITIZER_RELEASE() { mtx_.Unlock(); } + + // Should be guarded by ThreadRegistryLock. + ThreadContextBase *GetThreadLocked(u32 tid) { + return threads_.empty() ? nullptr : threads_[tid]; + } + + u32 NumThreadsLocked() const { return threads_.size(); } + + u32 CreateThread(uptr user_id, bool detached, u32 parent_tid, void *arg); + + typedef void (*ThreadCallback)(ThreadContextBase *tctx, void *arg); + // Invokes callback with a specified arg for each thread context. + // Should be guarded by ThreadRegistryLock. + void RunCallbackForEachThreadLocked(ThreadCallback cb, void *arg); + + typedef bool (*FindThreadCallback)(ThreadContextBase *tctx, void *arg); + // Finds a thread using the provided callback. Returns kInvalidTid if no + // thread is found. + u32 FindThread(FindThreadCallback cb, void *arg); + // Should be guarded by ThreadRegistryLock. Return 0 if no thread + // is found. + ThreadContextBase *FindThreadContextLocked(FindThreadCallback cb, + void *arg); + ThreadContextBase *FindThreadContextByOsIDLocked(tid_t os_id); + + void SetThreadName(u32 tid, const char *name); + void SetThreadNameByUserId(uptr user_id, const char *name); + void DetachThread(u32 tid, void *arg); + void JoinThread(u32 tid, void *arg); + // Finishes thread and returns previous status. + ThreadStatus FinishThread(u32 tid); + void StartThread(u32 tid, tid_t os_id, ThreadType thread_type, void *arg); + u32 ConsumeThreadUserId(uptr user_id); + void SetThreadUserId(u32 tid, uptr user_id); + + // OnFork must be called in the child process after fork to purge old + // threads that don't exist anymore (except for the current thread tid). + // Returns number of alive threads before fork. + u32 OnFork(u32 tid); + + private: + const ThreadContextFactory context_factory_; + const u32 max_threads_; + const u32 thread_quarantine_size_; + const u32 max_reuse_; + + Mutex mtx_; + + u64 total_threads_; // Total number of created threads. May be greater than + // max_threads_ if contexts were reused. + uptr alive_threads_; // Created or running. + uptr max_alive_threads_; + uptr running_threads_; + + InternalMmapVector<ThreadContextBase *> threads_; + IntrusiveList<ThreadContextBase> dead_threads_; + IntrusiveList<ThreadContextBase> invalid_threads_; + DenseMap<uptr, Tid> live_; + + void QuarantinePush(ThreadContextBase *tctx); + ThreadContextBase *QuarantinePop(); +}; + +typedef GenericScopedLock<ThreadRegistry> ThreadRegistryLock; + +} // namespace __sanitizer + +#endif // SANITIZER_THREAD_REGISTRY_H diff --git a/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_thread_safety.h b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_thread_safety.h new file mode 100644 index 0000000000..c34ea804da --- /dev/null +++ b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_thread_safety.h @@ -0,0 +1,49 @@ +//===-- sanitizer_thread_safety.h -------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file is shared between sanitizer tools. +// +// Wrappers around thread safety annotations. +// https://clang.llvm.org/docs/ThreadSafetyAnalysis.html +//===----------------------------------------------------------------------===// + +#ifndef SANITIZER_THREAD_SAFETY_H +#define SANITIZER_THREAD_SAFETY_H + +#if defined(__clang__) +# define SANITIZER_THREAD_ANNOTATION(x) __attribute__((x)) +#else +# define SANITIZER_THREAD_ANNOTATION(x) +#endif + +#define SANITIZER_MUTEX SANITIZER_THREAD_ANNOTATION(capability("mutex")) +#define SANITIZER_SCOPED_LOCK SANITIZER_THREAD_ANNOTATION(scoped_lockable) +#define SANITIZER_GUARDED_BY(x) SANITIZER_THREAD_ANNOTATION(guarded_by(x)) +#define SANITIZER_PT_GUARDED_BY(x) SANITIZER_THREAD_ANNOTATION(pt_guarded_by(x)) +#define SANITIZER_REQUIRES(...) \ + SANITIZER_THREAD_ANNOTATION(requires_capability(__VA_ARGS__)) +#define SANITIZER_REQUIRES_SHARED(...) \ + SANITIZER_THREAD_ANNOTATION(requires_shared_capability(__VA_ARGS__)) +#define SANITIZER_ACQUIRE(...) \ + SANITIZER_THREAD_ANNOTATION(acquire_capability(__VA_ARGS__)) +#define SANITIZER_ACQUIRE_SHARED(...) \ + SANITIZER_THREAD_ANNOTATION(acquire_shared_capability(__VA_ARGS__)) +#define SANITIZER_TRY_ACQUIRE(...) \ + SANITIZER_THREAD_ANNOTATION(try_acquire_capability(__VA_ARGS__)) +#define SANITIZER_RELEASE(...) \ + SANITIZER_THREAD_ANNOTATION(release_capability(__VA_ARGS__)) +#define SANITIZER_RELEASE_SHARED(...) \ + SANITIZER_THREAD_ANNOTATION(release_shared_capability(__VA_ARGS__)) +#define SANITIZER_EXCLUDES(...) \ + SANITIZER_THREAD_ANNOTATION(locks_excluded(__VA_ARGS__)) +#define SANITIZER_CHECK_LOCKED(...) \ + SANITIZER_THREAD_ANNOTATION(assert_capability(__VA_ARGS__)) +#define SANITIZER_NO_THREAD_SAFETY_ANALYSIS \ + SANITIZER_THREAD_ANNOTATION(no_thread_safety_analysis) + +#endif diff --git a/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_tls_get_addr.cpp b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_tls_get_addr.cpp new file mode 100644 index 0000000000..b13e2dc9e3 --- /dev/null +++ b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_tls_get_addr.cpp @@ -0,0 +1,178 @@ +//===-- sanitizer_tls_get_addr.cpp ----------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// Handle the __tls_get_addr call. +// +//===----------------------------------------------------------------------===// + +#include "sanitizer_tls_get_addr.h" + +#include "sanitizer_atomic.h" +#include "sanitizer_flags.h" +#include "sanitizer_platform_interceptors.h" + +namespace __sanitizer { +#if SANITIZER_INTERCEPT_TLS_GET_ADDR + +// The actual parameter that comes to __tls_get_addr +// is a pointer to a struct with two words in it: +struct TlsGetAddrParam { + uptr dso_id; + uptr offset; +}; + +// Glibc starting from 2.19 allocates tls using __signal_safe_memalign, +// which has such header. +struct Glibc_2_19_tls_header { + uptr size; + uptr start; +}; + +// This must be static TLS +__attribute__((tls_model("initial-exec"))) +static __thread DTLS dtls; + +// Make sure we properly destroy the DTLS objects: +// this counter should never get too large. +static atomic_uintptr_t number_of_live_dtls; + +static const uptr kDestroyedThread = -1; + +static void DTLS_Deallocate(DTLS::DTVBlock *block) { + VReport(2, "__tls_get_addr: DTLS_Deallocate %p\n", (void *)block); + UnmapOrDie(block, sizeof(DTLS::DTVBlock)); + atomic_fetch_sub(&number_of_live_dtls, 1, memory_order_relaxed); +} + +static DTLS::DTVBlock *DTLS_NextBlock(atomic_uintptr_t *cur) { + uptr v = atomic_load(cur, memory_order_acquire); + if (v == kDestroyedThread) + return nullptr; + DTLS::DTVBlock *next = (DTLS::DTVBlock *)v; + if (next) + return next; + DTLS::DTVBlock *new_dtv = + (DTLS::DTVBlock *)MmapOrDie(sizeof(DTLS::DTVBlock), "DTLS_NextBlock"); + uptr prev = 0; + if (!atomic_compare_exchange_strong(cur, &prev, (uptr)new_dtv, + memory_order_seq_cst)) { + UnmapOrDie(new_dtv, sizeof(DTLS::DTVBlock)); + return (DTLS::DTVBlock *)prev; + } + uptr num_live_dtls = + atomic_fetch_add(&number_of_live_dtls, 1, memory_order_relaxed); + VReport(2, "__tls_get_addr: DTLS_NextBlock %p %zd\n", (void *)&dtls, + num_live_dtls); + return new_dtv; +} + +static DTLS::DTV *DTLS_Find(uptr id) { + VReport(2, "__tls_get_addr: DTLS_Find %p %zd\n", (void *)&dtls, id); + static constexpr uptr kPerBlock = ARRAY_SIZE(DTLS::DTVBlock::dtvs); + DTLS::DTVBlock *cur = DTLS_NextBlock(&dtls.dtv_block); + if (!cur) + return nullptr; + for (; id >= kPerBlock; id -= kPerBlock) cur = DTLS_NextBlock(&cur->next); + return cur->dtvs + id; +} + +void DTLS_Destroy() { + if (!common_flags()->intercept_tls_get_addr) return; + VReport(2, "__tls_get_addr: DTLS_Destroy %p\n", (void *)&dtls); + DTLS::DTVBlock *block = (DTLS::DTVBlock *)atomic_exchange( + &dtls.dtv_block, kDestroyedThread, memory_order_release); + while (block) { + DTLS::DTVBlock *next = + (DTLS::DTVBlock *)atomic_load(&block->next, memory_order_acquire); + DTLS_Deallocate(block); + block = next; + } +} + +#if defined(__powerpc64__) || defined(__mips__) +// This is glibc's TLS_DTV_OFFSET: +// "Dynamic thread vector pointers point 0x8000 past the start of each +// TLS block." (sysdeps/<arch>/dl-tls.h) +static const uptr kDtvOffset = 0x8000; +#elif defined(__riscv) +// This is glibc's TLS_DTV_OFFSET: +// "Dynamic thread vector pointers point 0x800 past the start of each +// TLS block." (sysdeps/riscv/dl-tls.h) +static const uptr kDtvOffset = 0x800; +#else +static const uptr kDtvOffset = 0; +#endif + +DTLS::DTV *DTLS_on_tls_get_addr(void *arg_void, void *res, + uptr static_tls_begin, uptr static_tls_end) { + if (!common_flags()->intercept_tls_get_addr) return 0; + TlsGetAddrParam *arg = reinterpret_cast<TlsGetAddrParam *>(arg_void); + uptr dso_id = arg->dso_id; + DTLS::DTV *dtv = DTLS_Find(dso_id); + if (!dtv || dtv->beg) + return 0; + uptr tls_size = 0; + uptr tls_beg = reinterpret_cast<uptr>(res) - arg->offset - kDtvOffset; + VReport(2, + "__tls_get_addr: %p {0x%zx,0x%zx} => %p; tls_beg: 0x%zx; sp: %p " + "num_live_dtls %zd\n", + (void *)arg, arg->dso_id, arg->offset, res, tls_beg, (void *)&tls_beg, + atomic_load(&number_of_live_dtls, memory_order_relaxed)); + if (dtls.last_memalign_ptr == tls_beg) { + tls_size = dtls.last_memalign_size; + VReport(2, "__tls_get_addr: glibc <=2.18 suspected; tls={0x%zx,0x%zx}\n", + tls_beg, tls_size); + } else if (tls_beg >= static_tls_begin && tls_beg < static_tls_end) { + // This is the static TLS block which was initialized / unpoisoned at thread + // creation. + VReport(2, "__tls_get_addr: static tls: 0x%zx\n", tls_beg); + tls_size = 0; + } else if ((tls_beg % 4096) == sizeof(Glibc_2_19_tls_header)) { + // We may want to check gnu_get_libc_version(). + Glibc_2_19_tls_header *header = (Glibc_2_19_tls_header *)tls_beg - 1; + tls_size = header->size; + tls_beg = header->start; + VReport(2, "__tls_get_addr: glibc >=2.19 suspected; tls={0x%zx 0x%zx}\n", + tls_beg, tls_size); + } else { + VReport(2, "__tls_get_addr: Can't guess glibc version\n"); + // This may happen inside the DTOR of main thread, so just ignore it. + tls_size = 0; + } + dtv->beg = tls_beg; + dtv->size = tls_size; + return dtv; +} + +void DTLS_on_libc_memalign(void *ptr, uptr size) { + if (!common_flags()->intercept_tls_get_addr) return; + VReport(2, "DTLS_on_libc_memalign: %p 0x%zx\n", ptr, size); + dtls.last_memalign_ptr = reinterpret_cast<uptr>(ptr); + dtls.last_memalign_size = size; +} + +DTLS *DTLS_Get() { return &dtls; } + +bool DTLSInDestruction(DTLS *dtls) { + return atomic_load(&dtls->dtv_block, memory_order_relaxed) == + kDestroyedThread; +} + +#else +void DTLS_on_libc_memalign(void *ptr, uptr size) {} +DTLS::DTV *DTLS_on_tls_get_addr(void *arg, void *res, + unsigned long, unsigned long) { return 0; } +DTLS *DTLS_Get() { return 0; } +void DTLS_Destroy() {} +bool DTLSInDestruction(DTLS *dtls) { + UNREACHABLE("dtls is unsupported on this platform!"); +} + +#endif // SANITIZER_INTERCEPT_TLS_GET_ADDR + +} // namespace __sanitizer diff --git a/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_tls_get_addr.h b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_tls_get_addr.h new file mode 100644 index 0000000000..a599c0bbc7 --- /dev/null +++ b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_tls_get_addr.h @@ -0,0 +1,79 @@ +//===-- sanitizer_tls_get_addr.h --------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// Handle the __tls_get_addr call. +// +// All this magic is specific to glibc and is required to workaround +// the lack of interface that would tell us about the Dynamic TLS (DTLS). +// https://sourceware.org/bugzilla/show_bug.cgi?id=16291 +// +// The matters get worse because the glibc implementation changed between +// 2.18 and 2.19: +// https://groups.google.com/forum/#!topic/address-sanitizer/BfwYD8HMxTM +// +// Before 2.19, every DTLS chunk is allocated with __libc_memalign, +// which we intercept and thus know where is the DTLS. +// Since 2.19, DTLS chunks are allocated with __signal_safe_memalign, +// which is an internal function that wraps a mmap call, neither of which +// we can intercept. Luckily, __signal_safe_memalign has a simple parseable +// header which we can use. +// +//===----------------------------------------------------------------------===// + +#ifndef SANITIZER_TLS_GET_ADDR_H +#define SANITIZER_TLS_GET_ADDR_H + +#include "sanitizer_atomic.h" +#include "sanitizer_common.h" + +namespace __sanitizer { + +struct DTLS { + // Array of DTLS chunks for the current Thread. + // If beg == 0, the chunk is unused. + struct DTV { + uptr beg, size; + }; + struct DTVBlock { + atomic_uintptr_t next; + DTV dtvs[(4096UL - sizeof(next)) / sizeof(DTLS::DTV)]; + }; + + static_assert(sizeof(DTVBlock) <= 4096UL, "Unexpected block size"); + + atomic_uintptr_t dtv_block; + + // Auxiliary fields, don't access them outside sanitizer_tls_get_addr.cpp + uptr last_memalign_size; + uptr last_memalign_ptr; +}; + +template <typename Fn> +void ForEachDVT(DTLS *dtls, const Fn &fn) { + DTLS::DTVBlock *block = + (DTLS::DTVBlock *)atomic_load(&dtls->dtv_block, memory_order_acquire); + while (block) { + int id = 0; + for (auto &d : block->dtvs) fn(d, id++); + block = (DTLS::DTVBlock *)atomic_load(&block->next, memory_order_acquire); + } +} + +// Returns pointer and size of a linker-allocated TLS block. +// Each block is returned exactly once. +DTLS::DTV *DTLS_on_tls_get_addr(void *arg, void *res, uptr static_tls_begin, + uptr static_tls_end); +void DTLS_on_libc_memalign(void *ptr, uptr size); +DTLS *DTLS_Get(); +void DTLS_Destroy(); // Make sure to call this before the thread is destroyed. +// Returns true if DTLS of suspended thread is in destruction process. +bool DTLSInDestruction(DTLS *dtls); + +} // namespace __sanitizer + +#endif // SANITIZER_TLS_GET_ADDR_H diff --git a/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_type_traits.cpp b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_type_traits.cpp new file mode 100644 index 0000000000..5ee37d7376 --- /dev/null +++ b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_type_traits.cpp @@ -0,0 +1,20 @@ +//===-- sanitizer_type_traits.cpp -------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// Implements a subset of C++ type traits. This is so we can avoid depending +// on system C++ headers. +// +//===----------------------------------------------------------------------===// +#include "sanitizer_type_traits.h" + +namespace __sanitizer { + +const bool true_type::value; +const bool false_type::value; + +} // namespace __sanitizer diff --git a/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_type_traits.h b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_type_traits.h new file mode 100644 index 0000000000..06a44d1b5c --- /dev/null +++ b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_type_traits.h @@ -0,0 +1,141 @@ +//===-- sanitizer_type_traits.h ---------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// Implements a subset of C++ type traits. This is so we can avoid depending +// on system C++ headers. +// +//===----------------------------------------------------------------------===// +#ifndef SANITIZER_TYPE_TRAITS_H +#define SANITIZER_TYPE_TRAITS_H + +#include "sanitizer_common/sanitizer_internal_defs.h" + +namespace __sanitizer { + +struct true_type { + static const bool value = true; +}; + +struct false_type { + static const bool value = false; +}; + +// is_same<T, U> +// +// Type trait to compare if types are the same. +// E.g. +// +// ``` +// is_same<int,int>::value - True +// is_same<int,char>::value - False +// ``` +template <typename T, typename U> +struct is_same : public false_type {}; + +template <typename T> +struct is_same<T, T> : public true_type {}; + +// conditional<B, T, F> +// +// Defines type as T if B is true or as F otherwise. +// E.g. the following is true +// +// ``` +// is_same<int, conditional<true, int, double>::type>::value +// is_same<double, conditional<false, int, double>::type>::value +// ``` +template <bool B, class T, class F> +struct conditional { + using type = T; +}; + +template <class T, class F> +struct conditional<false, T, F> { + using type = F; +}; + +template <class T> +struct remove_reference { + using type = T; +}; +template <class T> +struct remove_reference<T&> { + using type = T; +}; +template <class T> +struct remove_reference<T&&> { + using type = T; +}; + +template <class T> +WARN_UNUSED_RESULT inline typename remove_reference<T>::type&& move(T&& t) { + return static_cast<typename remove_reference<T>::type&&>(t); +} + +template <class T> +WARN_UNUSED_RESULT inline constexpr T&& forward( + typename remove_reference<T>::type& t) { + return static_cast<T&&>(t); +} + +template <class T> +WARN_UNUSED_RESULT inline constexpr T&& forward( + typename remove_reference<T>::type&& t) { + return static_cast<T&&>(t); +} + +template <class T, T v> +struct integral_constant { + static constexpr const T value = v; + typedef T value_type; + typedef integral_constant type; + constexpr operator value_type() const { return value; } + constexpr value_type operator()() const { return value; } +}; + +#ifndef __has_builtin +# define __has_builtin(x) 0 +#endif + +#if __has_builtin(__is_trivially_destructible) + +template <class T> +struct is_trivially_destructible + : public integral_constant<bool, __is_trivially_destructible(T)> {}; + +#elif __has_builtin(__has_trivial_destructor) + +template <class T> +struct is_trivially_destructible + : public integral_constant<bool, __has_trivial_destructor(T)> {}; + +#else + +template <class T> +struct is_trivially_destructible + : public integral_constant<bool, /* less efficient fallback */ false> {}; + +#endif + +#if __has_builtin(__is_trivially_copyable) + +template <class T> +struct is_trivially_copyable + : public integral_constant<bool, __is_trivially_copyable(T)> {}; + +#else + +template <class T> +struct is_trivially_copyable + : public integral_constant<bool, /* less efficient fallback */ false> {}; + +#endif + +} // namespace __sanitizer + +#endif diff --git a/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_unwind_linux_libcdep.cpp b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_unwind_linux_libcdep.cpp new file mode 100644 index 0000000000..b2628dcc4d --- /dev/null +++ b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_unwind_linux_libcdep.cpp @@ -0,0 +1,180 @@ +//===-- sanitizer_unwind_linux_libcdep.cpp --------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file contains the unwind.h-based (aka "slow") stack unwinding routines +// available to the tools on Linux, Android, NetBSD, FreeBSD, and Solaris. +//===----------------------------------------------------------------------===// + +#include "sanitizer_platform.h" +#if SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD || \ + SANITIZER_SOLARIS +#include "sanitizer_common.h" +#include "sanitizer_stacktrace.h" + +#if SANITIZER_ANDROID +#include <dlfcn.h> // for dlopen() +#endif + +#if SANITIZER_FREEBSD +#define _GNU_SOURCE // to declare _Unwind_Backtrace() from <unwind.h> +#endif +#include <unwind.h> + +namespace __sanitizer { + +namespace { + +//---------------------------- UnwindSlow -------------------------------------- + +typedef struct { + uptr absolute_pc; + uptr stack_top; + uptr stack_size; +} backtrace_frame_t; + +extern "C" { +typedef void *(*acquire_my_map_info_list_func)(); +typedef void (*release_my_map_info_list_func)(void *map); +typedef sptr (*unwind_backtrace_signal_arch_func)( + void *siginfo, void *sigcontext, void *map_info_list, + backtrace_frame_t *backtrace, uptr ignore_depth, uptr max_depth); +acquire_my_map_info_list_func acquire_my_map_info_list; +release_my_map_info_list_func release_my_map_info_list; +unwind_backtrace_signal_arch_func unwind_backtrace_signal_arch; +} // extern "C" + +#if defined(__arm__) && !SANITIZER_NETBSD +// NetBSD uses dwarf EH +#define UNWIND_STOP _URC_END_OF_STACK +#define UNWIND_CONTINUE _URC_NO_REASON +#else +#define UNWIND_STOP _URC_NORMAL_STOP +#define UNWIND_CONTINUE _URC_NO_REASON +#endif + +uptr Unwind_GetIP(struct _Unwind_Context *ctx) { +#if defined(__arm__) && !SANITIZER_MAC + uptr val; + _Unwind_VRS_Result res = _Unwind_VRS_Get(ctx, _UVRSC_CORE, + 15 /* r15 = PC */, _UVRSD_UINT32, &val); + CHECK(res == _UVRSR_OK && "_Unwind_VRS_Get failed"); + // Clear the Thumb bit. + return val & ~(uptr)1; +#else + return (uptr)_Unwind_GetIP(ctx); +#endif +} + +struct UnwindTraceArg { + BufferedStackTrace *stack; + u32 max_depth; +}; + +_Unwind_Reason_Code Unwind_Trace(struct _Unwind_Context *ctx, void *param) { + UnwindTraceArg *arg = (UnwindTraceArg*)param; + CHECK_LT(arg->stack->size, arg->max_depth); + uptr pc = Unwind_GetIP(ctx); + const uptr kPageSize = GetPageSizeCached(); + // Let's assume that any pointer in the 0th page (i.e. <0x1000 on i386 and + // x86_64) is invalid and stop unwinding here. If we're adding support for + // a platform where this isn't true, we need to reconsider this check. + if (pc < kPageSize) return UNWIND_STOP; + arg->stack->trace_buffer[arg->stack->size++] = pc; + if (arg->stack->size == arg->max_depth) return UNWIND_STOP; + return UNWIND_CONTINUE; +} + +} // namespace + +#if SANITIZER_ANDROID +void SanitizerInitializeUnwinder() { + if (AndroidGetApiLevel() >= ANDROID_LOLLIPOP_MR1) return; + + // Pre-lollipop Android can not unwind through signal handler frames with + // libgcc unwinder, but it has a libcorkscrew.so library with the necessary + // workarounds. + void *p = dlopen("libcorkscrew.so", RTLD_LAZY); + if (!p) { + VReport(1, + "Failed to open libcorkscrew.so. You may see broken stack traces " + "in SEGV reports."); + return; + } + acquire_my_map_info_list = + (acquire_my_map_info_list_func)(uptr)dlsym(p, "acquire_my_map_info_list"); + release_my_map_info_list = + (release_my_map_info_list_func)(uptr)dlsym(p, "release_my_map_info_list"); + unwind_backtrace_signal_arch = (unwind_backtrace_signal_arch_func)(uptr)dlsym( + p, "unwind_backtrace_signal_arch"); + if (!acquire_my_map_info_list || !release_my_map_info_list || + !unwind_backtrace_signal_arch) { + VReport(1, + "Failed to find one of the required symbols in libcorkscrew.so. " + "You may see broken stack traces in SEGV reports."); + acquire_my_map_info_list = 0; + unwind_backtrace_signal_arch = 0; + release_my_map_info_list = 0; + } +} +#endif + +void BufferedStackTrace::UnwindSlow(uptr pc, u32 max_depth) { + CHECK_GE(max_depth, 2); + size = 0; + UnwindTraceArg arg = {this, Min(max_depth + 1, kStackTraceMax)}; + _Unwind_Backtrace(Unwind_Trace, &arg); + // We need to pop a few frames so that pc is on top. + uptr to_pop = LocatePcInTrace(pc); + // trace_buffer[0] belongs to the current function so we always pop it, + // unless there is only 1 frame in the stack trace (1 frame is always better + // than 0!). + // 1-frame stacks don't normally happen, but this depends on the actual + // unwinder implementation (libgcc, libunwind, etc) which is outside of our + // control. + if (to_pop == 0 && size > 1) + to_pop = 1; + PopStackFrames(to_pop); +#if defined(__GNUC__) && defined(__sparc__) + // __builtin_return_address returns the address of the call instruction + // on the SPARC and not the return address, so we need to compensate. + trace_buffer[0] = GetNextInstructionPc(pc); +#else + trace_buffer[0] = pc; +#endif +} + +void BufferedStackTrace::UnwindSlow(uptr pc, void *context, u32 max_depth) { + CHECK(context); + CHECK_GE(max_depth, 2); + if (!unwind_backtrace_signal_arch) { + UnwindSlow(pc, max_depth); + return; + } + + void *map = acquire_my_map_info_list(); + CHECK(map); + InternalMmapVector<backtrace_frame_t> frames(kStackTraceMax); + // siginfo argument appears to be unused. + sptr res = unwind_backtrace_signal_arch(/* siginfo */ 0, context, map, + frames.data(), + /* ignore_depth */ 0, max_depth); + release_my_map_info_list(map); + if (res < 0) return; + CHECK_LE((uptr)res, kStackTraceMax); + + size = 0; + // +2 compensate for libcorkscrew unwinder returning addresses of call + // instructions instead of raw return addresses. + for (sptr i = 0; i < res; ++i) + trace_buffer[size++] = frames[i].absolute_pc + 2; +} + +} // namespace __sanitizer + +#endif // SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD || + // SANITIZER_SOLARIS diff --git a/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_unwind_win.cpp b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_unwind_win.cpp new file mode 100644 index 0000000000..afcd01dae0 --- /dev/null +++ b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_unwind_win.cpp @@ -0,0 +1,93 @@ +//===-- sanitizer_unwind_win.cpp ------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +/// Sanitizer unwind Windows specific functions. +// +//===----------------------------------------------------------------------===// + +#include "sanitizer_platform.h" +#if SANITIZER_WINDOWS + +#define WIN32_LEAN_AND_MEAN +#define NOGDI +#include <windows.h> + +#include "sanitizer_dbghelp.h" // for StackWalk64 +#include "sanitizer_stacktrace.h" +#include "sanitizer_symbolizer.h" // for InitializeDbgHelpIfNeeded + +using namespace __sanitizer; + +#if !SANITIZER_GO +void BufferedStackTrace::UnwindSlow(uptr pc, u32 max_depth) { + CHECK_GE(max_depth, 2); + // FIXME: CaptureStackBackTrace might be too slow for us. + // FIXME: Compare with StackWalk64. + // FIXME: Look at LLVMUnhandledExceptionFilter in Signals.inc + size = CaptureStackBackTrace(1, Min(max_depth, kStackTraceMax), + (void **)&trace_buffer[0], 0); + if (size == 0) + return; + + // Skip the RTL frames by searching for the PC in the stacktrace. + uptr pc_location = LocatePcInTrace(pc); + PopStackFrames(pc_location); + + // Replace the first frame with the PC because the frame in the + // stacktrace might be incorrect. + trace_buffer[0] = pc; +} + +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wframe-larger-than=" +#endif +void BufferedStackTrace::UnwindSlow(uptr pc, void *context, u32 max_depth) { + CHECK(context); + CHECK_GE(max_depth, 2); + CONTEXT ctx = *(CONTEXT *)context; + STACKFRAME64 stack_frame; + memset(&stack_frame, 0, sizeof(stack_frame)); + + InitializeDbgHelpIfNeeded(); + + size = 0; +# if SANITIZER_WINDOWS64 +# if SANITIZER_ARM64 + int machine_type = IMAGE_FILE_MACHINE_ARM64; + stack_frame.AddrPC.Offset = ctx.Pc; + stack_frame.AddrFrame.Offset = ctx.Fp; + stack_frame.AddrStack.Offset = ctx.Sp; +# else + int machine_type = IMAGE_FILE_MACHINE_AMD64; + stack_frame.AddrPC.Offset = ctx.Rip; + stack_frame.AddrFrame.Offset = ctx.Rbp; + stack_frame.AddrStack.Offset = ctx.Rsp; +# endif +# else + int machine_type = IMAGE_FILE_MACHINE_I386; + stack_frame.AddrPC.Offset = ctx.Eip; + stack_frame.AddrFrame.Offset = ctx.Ebp; + stack_frame.AddrStack.Offset = ctx.Esp; +# endif + stack_frame.AddrPC.Mode = AddrModeFlat; + stack_frame.AddrFrame.Mode = AddrModeFlat; + stack_frame.AddrStack.Mode = AddrModeFlat; + while (StackWalk64(machine_type, GetCurrentProcess(), GetCurrentThread(), + &stack_frame, &ctx, NULL, SymFunctionTableAccess64, + SymGetModuleBase64, NULL) && + size < Min(max_depth, kStackTraceMax)) { + trace_buffer[size++] = (uptr)stack_frame.AddrPC.Offset; + } +} +# ifdef __clang__ +# pragma clang diagnostic pop +# endif +# endif // #if !SANITIZER_GO + +#endif // SANITIZER_WINDOWS diff --git a/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_vector.h b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_vector.h new file mode 100644 index 0000000000..31216f3ec3 --- /dev/null +++ b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_vector.h @@ -0,0 +1,124 @@ +//===-- sanitizer_vector.h -------------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file is shared between sanitizers run-time libraries. +// +//===----------------------------------------------------------------------===// + +// Low-fat STL-like vector container. + +#ifndef SANITIZER_VECTOR_H +#define SANITIZER_VECTOR_H + +#include "sanitizer_common/sanitizer_allocator_internal.h" +#include "sanitizer_common/sanitizer_libc.h" + +namespace __sanitizer { + +template<typename T> +class Vector { + public: + Vector() : begin_(), end_(), last_() {} + + ~Vector() { + if (begin_) + InternalFree(begin_); + } + + void Reset() { + if (begin_) + InternalFree(begin_); + begin_ = 0; + end_ = 0; + last_ = 0; + } + + uptr Size() const { + return end_ - begin_; + } + + T &operator[](uptr i) { + DCHECK_LT(i, end_ - begin_); + return begin_[i]; + } + + const T &operator[](uptr i) const { + DCHECK_LT(i, end_ - begin_); + return begin_[i]; + } + + T *PushBack() { + EnsureSize(Size() + 1); + T *p = &end_[-1]; + internal_memset(p, 0, sizeof(*p)); + return p; + } + + T *PushBack(const T& v) { + EnsureSize(Size() + 1); + T *p = &end_[-1]; + internal_memcpy(p, &v, sizeof(*p)); + return p; + } + + void PopBack() { + DCHECK_GT(end_, begin_); + end_--; + } + + void Resize(uptr size) { + if (size == 0) { + end_ = begin_; + return; + } + uptr old_size = Size(); + if (size <= old_size) { + end_ = begin_ + size; + return; + } + EnsureSize(size); + if (old_size < size) { + for (uptr i = old_size; i < size; i++) + internal_memset(&begin_[i], 0, sizeof(begin_[i])); + } + } + + private: + T *begin_; + T *end_; + T *last_; + + void EnsureSize(uptr size) { + if (size <= Size()) + return; + if (size <= (uptr)(last_ - begin_)) { + end_ = begin_ + size; + return; + } + uptr cap0 = last_ - begin_; + uptr cap = cap0 * 5 / 4; // 25% growth + if (cap == 0) + cap = 16; + if (cap < size) + cap = size; + T *p = (T*)InternalAlloc(cap * sizeof(T)); + if (cap0) { + internal_memcpy(p, begin_, cap0 * sizeof(T)); + InternalFree(begin_); + } + begin_ = p; + end_ = begin_ + size; + last_ = begin_ + cap; + } + + Vector(const Vector&); + void operator=(const Vector&); +}; +} // namespace __sanitizer + +#endif // #ifndef SANITIZER_VECTOR_H diff --git a/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_win.cpp b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_win.cpp new file mode 100644 index 0000000000..afa5046d0c --- /dev/null +++ b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_win.cpp @@ -0,0 +1,1174 @@ +//===-- sanitizer_win.cpp -------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file is shared between AddressSanitizer and ThreadSanitizer +// run-time libraries and implements windows-specific functions from +// sanitizer_libc.h. +//===----------------------------------------------------------------------===// + +#include "sanitizer_platform.h" +#if SANITIZER_WINDOWS + +#define WIN32_LEAN_AND_MEAN +#define NOGDI +#include <windows.h> +#include <io.h> +#include <psapi.h> +#include <stdlib.h> + +#include "sanitizer_common.h" +#include "sanitizer_file.h" +#include "sanitizer_libc.h" +#include "sanitizer_mutex.h" +#include "sanitizer_placement_new.h" +#include "sanitizer_win_defs.h" + +#if defined(PSAPI_VERSION) && PSAPI_VERSION == 1 +#pragma comment(lib, "psapi") +#endif +#if SANITIZER_WIN_TRACE +#error #include <traceloggingprovider.h> +// Windows trace logging provider init +#pragma comment(lib, "advapi32.lib") +TRACELOGGING_DECLARE_PROVIDER(g_asan_provider); +// GUID must be the same in utils/AddressSanitizerLoggingProvider.wprp +TRACELOGGING_DEFINE_PROVIDER(g_asan_provider, "AddressSanitizerLoggingProvider", + (0x6c6c766d, 0x3846, 0x4e6a, 0xa4, 0xfb, 0x5b, + 0x53, 0x0b, 0xd0, 0xf3, 0xfa)); +#else +#define TraceLoggingUnregister(x) +#endif + +// For WaitOnAddress +# pragma comment(lib, "synchronization.lib") + +// A macro to tell the compiler that this part of the code cannot be reached, +// if the compiler supports this feature. Since we're using this in +// code that is called when terminating the process, the expansion of the +// macro should not terminate the process to avoid infinite recursion. +#if defined(__clang__) +# define BUILTIN_UNREACHABLE() __builtin_unreachable() +#elif defined(__GNUC__) && \ + (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5)) +# define BUILTIN_UNREACHABLE() __builtin_unreachable() +#elif defined(_MSC_VER) +# define BUILTIN_UNREACHABLE() __assume(0) +#else +# define BUILTIN_UNREACHABLE() +#endif + +namespace __sanitizer { + +#include "sanitizer_syscall_generic.inc" + +// --------------------- sanitizer_common.h +uptr GetPageSize() { + SYSTEM_INFO si; + GetSystemInfo(&si); + return si.dwPageSize; +} + +uptr GetMmapGranularity() { + SYSTEM_INFO si; + GetSystemInfo(&si); + return si.dwAllocationGranularity; +} + +uptr GetMaxUserVirtualAddress() { + SYSTEM_INFO si; + GetSystemInfo(&si); + return (uptr)si.lpMaximumApplicationAddress; +} + +uptr GetMaxVirtualAddress() { + return GetMaxUserVirtualAddress(); +} + +bool FileExists(const char *filename) { + return ::GetFileAttributesA(filename) != INVALID_FILE_ATTRIBUTES; +} + +uptr internal_getpid() { + return GetProcessId(GetCurrentProcess()); +} + +int internal_dlinfo(void *handle, int request, void *p) { + UNIMPLEMENTED(); +} + +// In contrast to POSIX, on Windows GetCurrentThreadId() +// returns a system-unique identifier. +tid_t GetTid() { + return GetCurrentThreadId(); +} + +uptr GetThreadSelf() { + return GetTid(); +} + +#if !SANITIZER_GO +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; +} +#endif // #if !SANITIZER_GO + +void *MmapOrDie(uptr size, const char *mem_type, bool raw_report) { + void *rv = VirtualAlloc(0, size, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE); + if (rv == 0) + ReportMmapFailureAndDie(size, mem_type, "allocate", + GetLastError(), raw_report); + return rv; +} + +void UnmapOrDie(void *addr, uptr size) { + if (!size || !addr) + return; + + MEMORY_BASIC_INFORMATION mbi; + CHECK(VirtualQuery(addr, &mbi, sizeof(mbi))); + + // MEM_RELEASE can only be used to unmap whole regions previously mapped with + // VirtualAlloc. So we first try MEM_RELEASE since it is better, and if that + // fails try MEM_DECOMMIT. + if (VirtualFree(addr, 0, MEM_RELEASE) == 0) { + if (VirtualFree(addr, size, MEM_DECOMMIT) == 0) { + Report("ERROR: %s failed to " + "deallocate 0x%zx (%zd) bytes at address %p (error code: %d)\n", + SanitizerToolName, size, size, addr, GetLastError()); + CHECK("unable to unmap" && 0); + } + } +} + +static void *ReturnNullptrOnOOMOrDie(uptr size, const char *mem_type, + const char *mmap_type) { + error_t last_error = GetLastError(); + if (last_error == ERROR_NOT_ENOUGH_MEMORY) + return nullptr; + ReportMmapFailureAndDie(size, mem_type, mmap_type, last_error); +} + +void *MmapOrDieOnFatalError(uptr size, const char *mem_type) { + void *rv = VirtualAlloc(0, size, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE); + if (rv == 0) + return ReturnNullptrOnOOMOrDie(size, mem_type, "allocate"); + return rv; +} + +// We want to map a chunk of address space aligned to 'alignment'. +void *MmapAlignedOrDieOnFatalError(uptr size, uptr alignment, + const char *mem_type) { + CHECK(IsPowerOfTwo(size)); + CHECK(IsPowerOfTwo(alignment)); + + // Windows will align our allocations to at least 64K. + alignment = Max(alignment, GetMmapGranularity()); + + uptr mapped_addr = + (uptr)VirtualAlloc(0, size, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE); + if (!mapped_addr) + return ReturnNullptrOnOOMOrDie(size, mem_type, "allocate aligned"); + + // If we got it right on the first try, return. Otherwise, unmap it and go to + // the slow path. + if (IsAligned(mapped_addr, alignment)) + return (void*)mapped_addr; + if (VirtualFree((void *)mapped_addr, 0, MEM_RELEASE) == 0) + ReportMmapFailureAndDie(size, mem_type, "deallocate", GetLastError()); + + // If we didn't get an aligned address, overallocate, find an aligned address, + // unmap, and try to allocate at that aligned address. + int retries = 0; + const int kMaxRetries = 10; + for (; retries < kMaxRetries && + (mapped_addr == 0 || !IsAligned(mapped_addr, alignment)); + retries++) { + // Overallocate size + alignment bytes. + mapped_addr = + (uptr)VirtualAlloc(0, size + alignment, MEM_RESERVE, PAGE_NOACCESS); + if (!mapped_addr) + return ReturnNullptrOnOOMOrDie(size, mem_type, "allocate aligned"); + + // Find the aligned address. + uptr aligned_addr = RoundUpTo(mapped_addr, alignment); + + // Free the overallocation. + if (VirtualFree((void *)mapped_addr, 0, MEM_RELEASE) == 0) + ReportMmapFailureAndDie(size, mem_type, "deallocate", GetLastError()); + + // Attempt to allocate exactly the number of bytes we need at the aligned + // address. This may fail for a number of reasons, in which case we continue + // the loop. + mapped_addr = (uptr)VirtualAlloc((void *)aligned_addr, size, + MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE); + } + + // Fail if we can't make this work quickly. + if (retries == kMaxRetries && mapped_addr == 0) + return ReturnNullptrOnOOMOrDie(size, mem_type, "allocate aligned"); + + return (void *)mapped_addr; +} + +bool MmapFixedNoReserve(uptr fixed_addr, uptr size, const char *name) { + // FIXME: is this really "NoReserve"? On Win32 this does not matter much, + // but on Win64 it does. + (void)name; // unsupported +#if !SANITIZER_GO && SANITIZER_WINDOWS64 + // On asan/Windows64, use MEM_COMMIT would result in error + // 1455:ERROR_COMMITMENT_LIMIT. + // Asan uses exception handler to commit page on demand. + void *p = VirtualAlloc((LPVOID)fixed_addr, size, MEM_RESERVE, PAGE_READWRITE); +#else + void *p = VirtualAlloc((LPVOID)fixed_addr, size, MEM_RESERVE | MEM_COMMIT, + PAGE_READWRITE); +#endif + if (p == 0) { + Report("ERROR: %s failed to " + "allocate %p (%zd) bytes at %p (error code: %d)\n", + SanitizerToolName, size, size, fixed_addr, GetLastError()); + return false; + } + return true; +} + +bool MmapFixedSuperNoReserve(uptr fixed_addr, uptr size, const char *name) { + // FIXME: Windows support large pages too. Might be worth checking + return MmapFixedNoReserve(fixed_addr, size, name); +} + +// Memory space mapped by 'MmapFixedOrDie' must have been reserved by +// 'MmapFixedNoAccess'. +void *MmapFixedOrDie(uptr fixed_addr, uptr size, const char *name) { + void *p = VirtualAlloc((LPVOID)fixed_addr, size, + MEM_COMMIT, PAGE_READWRITE); + if (p == 0) { + char mem_type[30]; + internal_snprintf(mem_type, sizeof(mem_type), "memory at address 0x%zx", + fixed_addr); + ReportMmapFailureAndDie(size, mem_type, "allocate", GetLastError()); + } + return p; +} + +// Uses fixed_addr for now. +// Will use offset instead once we've implemented this function for real. +uptr ReservedAddressRange::Map(uptr fixed_addr, uptr size, const char *name) { + return reinterpret_cast<uptr>(MmapFixedOrDieOnFatalError(fixed_addr, size)); +} + +uptr ReservedAddressRange::MapOrDie(uptr fixed_addr, uptr size, + const char *name) { + return reinterpret_cast<uptr>(MmapFixedOrDie(fixed_addr, size)); +} + +void ReservedAddressRange::Unmap(uptr addr, uptr size) { + // Only unmap if it covers the entire range. + CHECK((addr == reinterpret_cast<uptr>(base_)) && (size == size_)); + // We unmap the whole range, just null out the base. + base_ = nullptr; + size_ = 0; + UnmapOrDie(reinterpret_cast<void*>(addr), size); +} + +void *MmapFixedOrDieOnFatalError(uptr fixed_addr, uptr size, const char *name) { + void *p = VirtualAlloc((LPVOID)fixed_addr, size, + MEM_COMMIT, PAGE_READWRITE); + if (p == 0) { + char mem_type[30]; + internal_snprintf(mem_type, sizeof(mem_type), "memory at address 0x%zx", + fixed_addr); + return ReturnNullptrOnOOMOrDie(size, mem_type, "allocate"); + } + return p; +} + +void *MmapNoReserveOrDie(uptr size, const char *mem_type) { + // FIXME: make this really NoReserve? + return MmapOrDie(size, mem_type); +} + +uptr ReservedAddressRange::Init(uptr size, const char *name, uptr fixed_addr) { + base_ = fixed_addr ? MmapFixedNoAccess(fixed_addr, size) : MmapNoAccess(size); + size_ = size; + name_ = name; + (void)os_handle_; // unsupported + return reinterpret_cast<uptr>(base_); +} + + +void *MmapFixedNoAccess(uptr fixed_addr, uptr size, const char *name) { + (void)name; // unsupported + void *res = VirtualAlloc((LPVOID)fixed_addr, size, + MEM_RESERVE, PAGE_NOACCESS); + if (res == 0) + Report("WARNING: %s failed to " + "mprotect %p (%zd) bytes at %p (error code: %d)\n", + SanitizerToolName, size, size, fixed_addr, GetLastError()); + return res; +} + +void *MmapNoAccess(uptr size) { + void *res = VirtualAlloc(nullptr, size, MEM_RESERVE, PAGE_NOACCESS); + if (res == 0) + Report("WARNING: %s failed to " + "mprotect %p (%zd) bytes (error code: %d)\n", + SanitizerToolName, size, size, GetLastError()); + return res; +} + +bool MprotectNoAccess(uptr addr, uptr size) { + DWORD old_protection; + return VirtualProtect((LPVOID)addr, size, PAGE_NOACCESS, &old_protection); +} + +bool MprotectReadOnly(uptr addr, uptr size) { + DWORD old_protection; + return VirtualProtect((LPVOID)addr, size, PAGE_READONLY, &old_protection); +} + +void ReleaseMemoryPagesToOS(uptr beg, uptr end) { + uptr beg_aligned = RoundDownTo(beg, GetPageSizeCached()), + end_aligned = RoundDownTo(end, GetPageSizeCached()); + CHECK(beg < end); // make sure the region is sane + if (beg_aligned == end_aligned) // make sure we're freeing at least 1 page; + return; + UnmapOrDie((void *)beg, end_aligned - beg_aligned); +} + +void SetShadowRegionHugePageMode(uptr addr, uptr size) { + // FIXME: probably similar to ReleaseMemoryToOS. +} + +bool DontDumpShadowMemory(uptr addr, uptr length) { + // This is almost useless on 32-bits. + // FIXME: add madvise-analog when we move to 64-bits. + return true; +} + +uptr MapDynamicShadow(uptr shadow_size_bytes, uptr shadow_scale, + uptr min_shadow_base_alignment, + UNUSED uptr &high_mem_end) { + const uptr granularity = GetMmapGranularity(); + const uptr alignment = + Max<uptr>(granularity << shadow_scale, 1ULL << min_shadow_base_alignment); + const uptr left_padding = + Max<uptr>(granularity, 1ULL << min_shadow_base_alignment); + uptr space_size = shadow_size_bytes + left_padding; + uptr shadow_start = FindAvailableMemoryRange(space_size, alignment, + granularity, nullptr, nullptr); + CHECK_NE((uptr)0, shadow_start); + CHECK(IsAligned(shadow_start, alignment)); + return shadow_start; +} + +uptr FindAvailableMemoryRange(uptr size, uptr alignment, uptr left_padding, + uptr *largest_gap_found, + uptr *max_occupied_addr) { + uptr address = 0; + while (true) { + MEMORY_BASIC_INFORMATION info; + if (!::VirtualQuery((void*)address, &info, sizeof(info))) + return 0; + + if (info.State == MEM_FREE) { + uptr shadow_address = RoundUpTo((uptr)info.BaseAddress + left_padding, + alignment); + if (shadow_address + size < (uptr)info.BaseAddress + info.RegionSize) + return shadow_address; + } + + // Move to the next region. + address = (uptr)info.BaseAddress + info.RegionSize; + } + return 0; +} + +uptr MapDynamicShadowAndAliases(uptr shadow_size, uptr alias_size, + uptr num_aliases, uptr ring_buffer_size) { + CHECK(false && "HWASan aliasing is unimplemented on Windows"); + return 0; +} + +bool MemoryRangeIsAvailable(uptr range_start, uptr range_end) { + MEMORY_BASIC_INFORMATION mbi; + CHECK(VirtualQuery((void *)range_start, &mbi, sizeof(mbi))); + return mbi.Protect == PAGE_NOACCESS && + (uptr)mbi.BaseAddress + mbi.RegionSize >= range_end; +} + +void *MapFileToMemory(const char *file_name, uptr *buff_size) { + UNIMPLEMENTED(); +} + +void *MapWritableFileToMemory(void *addr, uptr size, fd_t fd, OFF_T offset) { + UNIMPLEMENTED(); +} + +static const int kMaxEnvNameLength = 128; +static const DWORD kMaxEnvValueLength = 32767; + +namespace { + +struct EnvVariable { + char name[kMaxEnvNameLength]; + char value[kMaxEnvValueLength]; +}; + +} // namespace + +static const int kEnvVariables = 5; +static EnvVariable env_vars[kEnvVariables]; +static int num_env_vars; + +const char *GetEnv(const char *name) { + // Note: this implementation caches the values of the environment variables + // and limits their quantity. + for (int i = 0; i < num_env_vars; i++) { + if (0 == internal_strcmp(name, env_vars[i].name)) + return env_vars[i].value; + } + CHECK_LT(num_env_vars, kEnvVariables); + DWORD rv = GetEnvironmentVariableA(name, env_vars[num_env_vars].value, + kMaxEnvValueLength); + if (rv > 0 && rv < kMaxEnvValueLength) { + CHECK_LT(internal_strlen(name), kMaxEnvNameLength); + internal_strncpy(env_vars[num_env_vars].name, name, kMaxEnvNameLength); + num_env_vars++; + return env_vars[num_env_vars - 1].value; + } + return 0; +} + +const char *GetPwd() { + UNIMPLEMENTED(); +} + +u32 GetUid() { + UNIMPLEMENTED(); +} + +namespace { +struct ModuleInfo { + const char *filepath; + uptr base_address; + uptr end_address; +}; + +#if !SANITIZER_GO +int CompareModulesBase(const void *pl, const void *pr) { + const ModuleInfo *l = (const ModuleInfo *)pl, *r = (const ModuleInfo *)pr; + if (l->base_address < r->base_address) + return -1; + return l->base_address > r->base_address; +} +#endif +} // namespace + +#if !SANITIZER_GO +void DumpProcessMap() { + Report("Dumping process modules:\n"); + ListOfModules modules; + modules.init(); + uptr num_modules = modules.size(); + + InternalMmapVector<ModuleInfo> module_infos(num_modules); + for (size_t i = 0; i < num_modules; ++i) { + module_infos[i].filepath = modules[i].full_name(); + module_infos[i].base_address = modules[i].ranges().front()->beg; + module_infos[i].end_address = modules[i].ranges().back()->end; + } + qsort(module_infos.data(), num_modules, sizeof(ModuleInfo), + CompareModulesBase); + + for (size_t i = 0; i < num_modules; ++i) { + const ModuleInfo &mi = module_infos[i]; + if (mi.end_address != 0) { + Printf("\t%p-%p %s\n", mi.base_address, mi.end_address, + mi.filepath[0] ? mi.filepath : "[no name]"); + } else if (mi.filepath[0]) { + Printf("\t??\?-??? %s\n", mi.filepath); + } else { + Printf("\t???\n"); + } + } +} +#endif + +void DisableCoreDumperIfNecessary() { + // Do nothing. +} + +void ReExec() { + UNIMPLEMENTED(); +} + +void PlatformPrepareForSandboxing(__sanitizer_sandbox_arguments *args) {} + +bool StackSizeIsUnlimited() { + UNIMPLEMENTED(); +} + +void SetStackSizeLimitInBytes(uptr limit) { + UNIMPLEMENTED(); +} + +bool AddressSpaceIsUnlimited() { + UNIMPLEMENTED(); +} + +void SetAddressSpaceUnlimited() { + UNIMPLEMENTED(); +} + +bool IsPathSeparator(const char c) { + return c == '\\' || c == '/'; +} + +static bool IsAlpha(char c) { + c = ToLower(c); + return c >= 'a' && c <= 'z'; +} + +bool IsAbsolutePath(const char *path) { + return path != nullptr && IsAlpha(path[0]) && path[1] == ':' && + IsPathSeparator(path[2]); +} + +void internal_usleep(u64 useconds) { Sleep(useconds / 1000); } + +u64 NanoTime() { + static LARGE_INTEGER frequency = {}; + LARGE_INTEGER counter; + if (UNLIKELY(frequency.QuadPart == 0)) { + QueryPerformanceFrequency(&frequency); + CHECK_NE(frequency.QuadPart, 0); + } + QueryPerformanceCounter(&counter); + counter.QuadPart *= 1000ULL * 1000000ULL; + counter.QuadPart /= frequency.QuadPart; + return counter.QuadPart; +} + +u64 MonotonicNanoTime() { return NanoTime(); } + +void Abort() { + internal__exit(3); +} + +bool CreateDir(const char *pathname) { + return CreateDirectoryA(pathname, nullptr) != 0; +} + +#if !SANITIZER_GO +// Read the file to extract the ImageBase field from the PE header. If ASLR is +// disabled and this virtual address is available, the loader will typically +// load the image at this address. Therefore, we call it the preferred base. Any +// addresses in the DWARF typically assume that the object has been loaded at +// this address. +static uptr GetPreferredBase(const char *modname, char *buf, size_t buf_size) { + fd_t fd = OpenFile(modname, RdOnly, nullptr); + if (fd == kInvalidFd) + return 0; + FileCloser closer(fd); + + // Read just the DOS header. + IMAGE_DOS_HEADER dos_header; + uptr bytes_read; + if (!ReadFromFile(fd, &dos_header, sizeof(dos_header), &bytes_read) || + bytes_read != sizeof(dos_header)) + return 0; + + // The file should start with the right signature. + if (dos_header.e_magic != IMAGE_DOS_SIGNATURE) + return 0; + + // The layout at e_lfanew is: + // "PE\0\0" + // IMAGE_FILE_HEADER + // IMAGE_OPTIONAL_HEADER + // Seek to e_lfanew and read all that data. + if (::SetFilePointer(fd, dos_header.e_lfanew, nullptr, FILE_BEGIN) == + INVALID_SET_FILE_POINTER) + return 0; + if (!ReadFromFile(fd, buf, buf_size, &bytes_read) || bytes_read != buf_size) + return 0; + + // Check for "PE\0\0" before the PE header. + char *pe_sig = &buf[0]; + if (internal_memcmp(pe_sig, "PE\0\0", 4) != 0) + return 0; + + // Skip over IMAGE_FILE_HEADER. We could do more validation here if we wanted. + IMAGE_OPTIONAL_HEADER *pe_header = + (IMAGE_OPTIONAL_HEADER *)(pe_sig + 4 + sizeof(IMAGE_FILE_HEADER)); + + // Check for more magic in the PE header. + if (pe_header->Magic != IMAGE_NT_OPTIONAL_HDR_MAGIC) + return 0; + + // Finally, return the ImageBase. + return (uptr)pe_header->ImageBase; +} + +void ListOfModules::init() { + clearOrInit(); + HANDLE cur_process = GetCurrentProcess(); + + // Query the list of modules. Start by assuming there are no more than 256 + // modules and retry if that's not sufficient. + HMODULE *hmodules = 0; + uptr modules_buffer_size = sizeof(HMODULE) * 256; + DWORD bytes_required; + while (!hmodules) { + hmodules = (HMODULE *)MmapOrDie(modules_buffer_size, __FUNCTION__); + CHECK(EnumProcessModules(cur_process, hmodules, modules_buffer_size, + &bytes_required)); + if (bytes_required > modules_buffer_size) { + // Either there turned out to be more than 256 hmodules, or new hmodules + // could have loaded since the last try. Retry. + UnmapOrDie(hmodules, modules_buffer_size); + hmodules = 0; + modules_buffer_size = bytes_required; + } + } + + InternalMmapVector<char> buf(4 + sizeof(IMAGE_FILE_HEADER) + + sizeof(IMAGE_OPTIONAL_HEADER)); + InternalMmapVector<wchar_t> modname_utf16(kMaxPathLength); + InternalMmapVector<char> module_name(kMaxPathLength); + // |num_modules| is the number of modules actually present, + size_t num_modules = bytes_required / sizeof(HMODULE); + for (size_t i = 0; i < num_modules; ++i) { + HMODULE handle = hmodules[i]; + MODULEINFO mi; + if (!GetModuleInformation(cur_process, handle, &mi, sizeof(mi))) + continue; + + // Get the UTF-16 path and convert to UTF-8. + int modname_utf16_len = + GetModuleFileNameW(handle, &modname_utf16[0], kMaxPathLength); + if (modname_utf16_len == 0) + modname_utf16[0] = '\0'; + int module_name_len = ::WideCharToMultiByte( + CP_UTF8, 0, &modname_utf16[0], modname_utf16_len + 1, &module_name[0], + kMaxPathLength, NULL, NULL); + module_name[module_name_len] = '\0'; + + uptr base_address = (uptr)mi.lpBaseOfDll; + uptr end_address = (uptr)mi.lpBaseOfDll + mi.SizeOfImage; + + // Adjust the base address of the module so that we get a VA instead of an + // RVA when computing the module offset. This helps llvm-symbolizer find the + // right DWARF CU. In the common case that the image is loaded at it's + // preferred address, we will now print normal virtual addresses. + uptr preferred_base = + GetPreferredBase(&module_name[0], &buf[0], buf.size()); + uptr adjusted_base = base_address - preferred_base; + + modules_.push_back(LoadedModule()); + LoadedModule &cur_module = modules_.back(); + cur_module.set(&module_name[0], adjusted_base); + // We add the whole module as one single address range. + cur_module.addAddressRange(base_address, end_address, /*executable*/ true, + /*writable*/ true); + } + UnmapOrDie(hmodules, modules_buffer_size); +} + +void ListOfModules::fallbackInit() { clear(); } + +// We can't use atexit() directly at __asan_init time as the CRT is not fully +// initialized at this point. Place the functions into a vector and use +// atexit() as soon as it is ready for use (i.e. after .CRT$XIC initializers). +InternalMmapVectorNoCtor<void (*)(void)> atexit_functions; + +int Atexit(void (*function)(void)) { + atexit_functions.push_back(function); + return 0; +} + +static int RunAtexit() { + TraceLoggingUnregister(g_asan_provider); + int ret = 0; + for (uptr i = 0; i < atexit_functions.size(); ++i) { + ret |= atexit(atexit_functions[i]); + } + return ret; +} + +#pragma section(".CRT$XID", long, read) +__declspec(allocate(".CRT$XID")) int (*__run_atexit)() = RunAtexit; +#endif + +// ------------------ sanitizer_libc.h +fd_t OpenFile(const char *filename, FileAccessMode mode, error_t *last_error) { + // FIXME: Use the wide variants to handle Unicode filenames. + fd_t res; + if (mode == RdOnly) { + res = CreateFileA(filename, GENERIC_READ, + FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, + nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr); + } else if (mode == WrOnly) { + res = CreateFileA(filename, GENERIC_WRITE, 0, nullptr, CREATE_ALWAYS, + FILE_ATTRIBUTE_NORMAL, nullptr); + } else { + UNIMPLEMENTED(); + } + CHECK(res != kStdoutFd || kStdoutFd == kInvalidFd); + CHECK(res != kStderrFd || kStderrFd == kInvalidFd); + if (res == kInvalidFd && last_error) + *last_error = GetLastError(); + return res; +} + +void CloseFile(fd_t fd) { + CloseHandle(fd); +} + +bool ReadFromFile(fd_t fd, void *buff, uptr buff_size, uptr *bytes_read, + error_t *error_p) { + CHECK(fd != kInvalidFd); + + // bytes_read can't be passed directly to ReadFile: + // uptr is unsigned long long on 64-bit Windows. + unsigned long num_read_long; + + bool success = ::ReadFile(fd, buff, buff_size, &num_read_long, nullptr); + if (!success && error_p) + *error_p = GetLastError(); + if (bytes_read) + *bytes_read = num_read_long; + return success; +} + +bool SupportsColoredOutput(fd_t fd) { + // FIXME: support colored output. + return false; +} + +bool WriteToFile(fd_t fd, const void *buff, uptr buff_size, uptr *bytes_written, + error_t *error_p) { + CHECK(fd != kInvalidFd); + + // Handle null optional parameters. + error_t dummy_error; + error_p = error_p ? error_p : &dummy_error; + uptr dummy_bytes_written; + bytes_written = bytes_written ? bytes_written : &dummy_bytes_written; + + // Initialize output parameters in case we fail. + *error_p = 0; + *bytes_written = 0; + + // Map the conventional Unix fds 1 and 2 to Windows handles. They might be + // closed, in which case this will fail. + if (fd == kStdoutFd || fd == kStderrFd) { + fd = GetStdHandle(fd == kStdoutFd ? STD_OUTPUT_HANDLE : STD_ERROR_HANDLE); + if (fd == 0) { + *error_p = ERROR_INVALID_HANDLE; + return false; + } + } + + DWORD bytes_written_32; + if (!WriteFile(fd, buff, buff_size, &bytes_written_32, 0)) { + *error_p = GetLastError(); + return false; + } else { + *bytes_written = bytes_written_32; + return true; + } +} + +uptr internal_sched_yield() { + Sleep(0); + return 0; +} + +void internal__exit(int exitcode) { + TraceLoggingUnregister(g_asan_provider); + // ExitProcess runs some finalizers, so use TerminateProcess to avoid that. + // The debugger doesn't stop on TerminateProcess like it does on ExitProcess, + // so add our own breakpoint here. + if (::IsDebuggerPresent()) + __debugbreak(); + TerminateProcess(GetCurrentProcess(), exitcode); + BUILTIN_UNREACHABLE(); +} + +uptr internal_ftruncate(fd_t fd, uptr size) { + UNIMPLEMENTED(); +} + +uptr GetRSS() { + PROCESS_MEMORY_COUNTERS counters; + if (!GetProcessMemoryInfo(GetCurrentProcess(), &counters, sizeof(counters))) + return 0; + return counters.WorkingSetSize; +} + +void *internal_start_thread(void *(*func)(void *arg), void *arg) { return 0; } +void internal_join_thread(void *th) { } + +void FutexWait(atomic_uint32_t *p, u32 cmp) { + WaitOnAddress(p, &cmp, sizeof(cmp), INFINITE); +} + +void FutexWake(atomic_uint32_t *p, u32 count) { + if (count == 1) + WakeByAddressSingle(p); + else + WakeByAddressAll(p); +} + +uptr GetTlsSize() { + return 0; +} + +void InitTlsSize() { +} + +void GetThreadStackAndTls(bool main, uptr *stk_addr, uptr *stk_size, + uptr *tls_addr, uptr *tls_size) { +#if SANITIZER_GO + *stk_addr = 0; + *stk_size = 0; + *tls_addr = 0; + *tls_size = 0; +#else + uptr stack_top, stack_bottom; + GetThreadStackTopAndBottom(main, &stack_top, &stack_bottom); + *stk_addr = stack_bottom; + *stk_size = stack_top - stack_bottom; + *tls_addr = 0; + *tls_size = 0; +#endif +} + +void ReportFile::Write(const char *buffer, uptr length) { + SpinMutexLock l(mu); + ReopenIfNecessary(); + if (!WriteToFile(fd, buffer, length)) { + // stderr may be closed, but we may be able to print to the debugger + // instead. This is the case when launching a program from Visual Studio, + // and the following routine should write to its console. + OutputDebugStringA(buffer); + } +} + +void SetAlternateSignalStack() { + // FIXME: Decide what to do on Windows. +} + +void UnsetAlternateSignalStack() { + // FIXME: Decide what to do on Windows. +} + +void InstallDeadlySignalHandlers(SignalHandlerType handler) { + (void)handler; + // FIXME: Decide what to do on Windows. +} + +HandleSignalMode GetHandleSignalMode(int signum) { + // FIXME: Decide what to do on Windows. + return kHandleSignalNo; +} + +// Check based on flags if we should handle this exception. +bool IsHandledDeadlyException(DWORD exceptionCode) { + switch (exceptionCode) { + case EXCEPTION_ACCESS_VIOLATION: + case EXCEPTION_ARRAY_BOUNDS_EXCEEDED: + case EXCEPTION_STACK_OVERFLOW: + case EXCEPTION_DATATYPE_MISALIGNMENT: + case EXCEPTION_IN_PAGE_ERROR: + return common_flags()->handle_segv; + case EXCEPTION_ILLEGAL_INSTRUCTION: + case EXCEPTION_PRIV_INSTRUCTION: + case EXCEPTION_BREAKPOINT: + return common_flags()->handle_sigill; + case EXCEPTION_FLT_DENORMAL_OPERAND: + case EXCEPTION_FLT_DIVIDE_BY_ZERO: + case EXCEPTION_FLT_INEXACT_RESULT: + case EXCEPTION_FLT_INVALID_OPERATION: + case EXCEPTION_FLT_OVERFLOW: + case EXCEPTION_FLT_STACK_CHECK: + case EXCEPTION_FLT_UNDERFLOW: + case EXCEPTION_INT_DIVIDE_BY_ZERO: + case EXCEPTION_INT_OVERFLOW: + return common_flags()->handle_sigfpe; + } + return false; +} + +bool IsAccessibleMemoryRange(uptr beg, uptr size) { + SYSTEM_INFO si; + GetNativeSystemInfo(&si); + uptr page_size = si.dwPageSize; + uptr page_mask = ~(page_size - 1); + + for (uptr page = beg & page_mask, end = (beg + size - 1) & page_mask; + page <= end;) { + MEMORY_BASIC_INFORMATION info; + if (VirtualQuery((LPCVOID)page, &info, sizeof(info)) != sizeof(info)) + return false; + + if (info.Protect == 0 || info.Protect == PAGE_NOACCESS || + info.Protect == PAGE_EXECUTE) + return false; + + if (info.RegionSize == 0) + return false; + + page += info.RegionSize; + } + + return true; +} + +bool SignalContext::IsStackOverflow() const { + return (DWORD)GetType() == EXCEPTION_STACK_OVERFLOW; +} + +void SignalContext::InitPcSpBp() { + EXCEPTION_RECORD *exception_record = (EXCEPTION_RECORD *)siginfo; + CONTEXT *context_record = (CONTEXT *)context; + + pc = (uptr)exception_record->ExceptionAddress; +# if SANITIZER_WINDOWS64 +# if SANITIZER_ARM64 + bp = (uptr)context_record->Fp; + sp = (uptr)context_record->Sp; +# else + bp = (uptr)context_record->Rbp; + sp = (uptr)context_record->Rsp; +# endif +# else + bp = (uptr)context_record->Ebp; + sp = (uptr)context_record->Esp; +# endif +} + +uptr SignalContext::GetAddress() const { + EXCEPTION_RECORD *exception_record = (EXCEPTION_RECORD *)siginfo; + if (exception_record->ExceptionCode == EXCEPTION_ACCESS_VIOLATION) + return exception_record->ExceptionInformation[1]; + return (uptr)exception_record->ExceptionAddress; +} + +bool SignalContext::IsMemoryAccess() const { + return ((EXCEPTION_RECORD *)siginfo)->ExceptionCode == + EXCEPTION_ACCESS_VIOLATION; +} + +bool SignalContext::IsTrueFaultingAddress() const { return true; } + +SignalContext::WriteFlag SignalContext::GetWriteFlag() const { + EXCEPTION_RECORD *exception_record = (EXCEPTION_RECORD *)siginfo; + + // The write flag is only available for access violation exceptions. + if (exception_record->ExceptionCode != EXCEPTION_ACCESS_VIOLATION) + return SignalContext::Unknown; + + // The contents of this array are documented at + // https://docs.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-exception_record + // The first element indicates read as 0, write as 1, or execute as 8. The + // second element is the faulting address. + switch (exception_record->ExceptionInformation[0]) { + case 0: + return SignalContext::Read; + case 1: + return SignalContext::Write; + case 8: + return SignalContext::Unknown; + } + return SignalContext::Unknown; +} + +void SignalContext::DumpAllRegisters(void *context) { + // FIXME: Implement this. +} + +int SignalContext::GetType() const { + return static_cast<const EXCEPTION_RECORD *>(siginfo)->ExceptionCode; +} + +const char *SignalContext::Describe() const { + unsigned code = GetType(); + // Get the string description of the exception if this is a known deadly + // exception. + switch (code) { + case EXCEPTION_ACCESS_VIOLATION: + return "access-violation"; + case EXCEPTION_ARRAY_BOUNDS_EXCEEDED: + return "array-bounds-exceeded"; + case EXCEPTION_STACK_OVERFLOW: + return "stack-overflow"; + case EXCEPTION_DATATYPE_MISALIGNMENT: + return "datatype-misalignment"; + case EXCEPTION_IN_PAGE_ERROR: + return "in-page-error"; + case EXCEPTION_ILLEGAL_INSTRUCTION: + return "illegal-instruction"; + case EXCEPTION_PRIV_INSTRUCTION: + return "priv-instruction"; + case EXCEPTION_BREAKPOINT: + return "breakpoint"; + case EXCEPTION_FLT_DENORMAL_OPERAND: + return "flt-denormal-operand"; + case EXCEPTION_FLT_DIVIDE_BY_ZERO: + return "flt-divide-by-zero"; + case EXCEPTION_FLT_INEXACT_RESULT: + return "flt-inexact-result"; + case EXCEPTION_FLT_INVALID_OPERATION: + return "flt-invalid-operation"; + case EXCEPTION_FLT_OVERFLOW: + return "flt-overflow"; + case EXCEPTION_FLT_STACK_CHECK: + return "flt-stack-check"; + case EXCEPTION_FLT_UNDERFLOW: + return "flt-underflow"; + case EXCEPTION_INT_DIVIDE_BY_ZERO: + return "int-divide-by-zero"; + case EXCEPTION_INT_OVERFLOW: + return "int-overflow"; + } + return "unknown exception"; +} + +uptr ReadBinaryName(/*out*/char *buf, uptr buf_len) { + if (buf_len == 0) + return 0; + + // Get the UTF-16 path and convert to UTF-8. + InternalMmapVector<wchar_t> binname_utf16(kMaxPathLength); + int binname_utf16_len = + GetModuleFileNameW(NULL, &binname_utf16[0], kMaxPathLength); + if (binname_utf16_len == 0) { + buf[0] = '\0'; + return 0; + } + int binary_name_len = + ::WideCharToMultiByte(CP_UTF8, 0, &binname_utf16[0], binname_utf16_len, + buf, buf_len, NULL, NULL); + if ((unsigned)binary_name_len == buf_len) + --binary_name_len; + buf[binary_name_len] = '\0'; + return binary_name_len; +} + +uptr ReadLongProcessName(/*out*/char *buf, uptr buf_len) { + return ReadBinaryName(buf, buf_len); +} + +void CheckVMASize() { + // Do nothing. +} + +void InitializePlatformEarly() { + // Do nothing. +} + +void MaybeReexec() { + // No need to re-exec on Windows. +} + +void CheckASLR() { + // Do nothing +} + +void CheckMPROTECT() { + // Do nothing +} + +char **GetArgv() { + // FIXME: Actually implement this function. + return 0; +} + +char **GetEnviron() { + // FIXME: Actually implement this function. + return 0; +} + +pid_t StartSubprocess(const char *program, const char *const argv[], + const char *const envp[], fd_t stdin_fd, fd_t stdout_fd, + fd_t stderr_fd) { + // FIXME: implement on this platform + // Should be implemented based on + // SymbolizerProcess::StarAtSymbolizerSubprocess + // from lib/sanitizer_common/sanitizer_symbolizer_win.cpp. + return -1; +} + +bool IsProcessRunning(pid_t pid) { + // FIXME: implement on this platform. + return false; +} + +int WaitForProcess(pid_t pid) { return -1; } + +// FIXME implement on this platform. +void GetMemoryProfile(fill_profile_f cb, uptr *stats) {} + +void CheckNoDeepBind(const char *filename, int flag) { + // Do nothing. +} + +// FIXME: implement on this platform. +bool GetRandom(void *buffer, uptr length, bool blocking) { + UNIMPLEMENTED(); +} + +u32 GetNumberOfCPUs() { + SYSTEM_INFO sysinfo = {}; + GetNativeSystemInfo(&sysinfo); + return sysinfo.dwNumberOfProcessors; +} + +#if SANITIZER_WIN_TRACE +// TODO(mcgov): Rename this project-wide to PlatformLogInit +void AndroidLogInit(void) { + HRESULT hr = TraceLoggingRegister(g_asan_provider); + if (!SUCCEEDED(hr)) + return; +} + +void SetAbortMessage(const char *) {} + +void LogFullErrorReport(const char *buffer) { + if (common_flags()->log_to_syslog) { + InternalMmapVector<wchar_t> filename; + DWORD filename_length = 0; + do { + filename.resize(filename.size() + 0x100); + filename_length = + GetModuleFileNameW(NULL, filename.begin(), filename.size()); + } while (filename_length >= filename.size()); + TraceLoggingWrite(g_asan_provider, "AsanReportEvent", + TraceLoggingValue(filename.begin(), "ExecutableName"), + TraceLoggingValue(buffer, "AsanReportContents")); + } +} +#endif // SANITIZER_WIN_TRACE + +void InitializePlatformCommonFlags(CommonFlags *cf) {} + +} // namespace __sanitizer + +#endif // _WIN32 diff --git a/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_win.h b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_win.h new file mode 100644 index 0000000000..ff8939ca5e --- /dev/null +++ b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_win.h @@ -0,0 +1,25 @@ +//===-- sanitizer_win.h -----------------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// Windows-specific declarations. +// +//===----------------------------------------------------------------------===// +#ifndef SANITIZER_WIN_H +#define SANITIZER_WIN_H + +#include "sanitizer_platform.h" +#if SANITIZER_WINDOWS +#include "sanitizer_internal_defs.h" + +namespace __sanitizer { +// Check based on flags if we should handle the exception. +bool IsHandledDeadlyException(DWORD exceptionCode); +} // namespace __sanitizer + +#endif // SANITIZER_WINDOWS +#endif // SANITIZER_WIN_H diff --git a/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_win_defs.h b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_win_defs.h new file mode 100644 index 0000000000..bfe38a3323 --- /dev/null +++ b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_win_defs.h @@ -0,0 +1,174 @@ +//===-- sanitizer_win_defs.h ------------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// Common definitions for Windows-specific code. +// +//===----------------------------------------------------------------------===// +#ifndef SANITIZER_WIN_DEFS_H +#define SANITIZER_WIN_DEFS_H + +#include "sanitizer_platform.h" +#if SANITIZER_WINDOWS + +#ifndef WINAPI +#if defined(_M_IX86) || defined(__i386__) +#define WINAPI __stdcall +#else +#define WINAPI +#endif +#endif + +#if defined(_M_IX86) || defined(__i386__) +#define WIN_SYM_PREFIX "_" +#else +#define WIN_SYM_PREFIX +#endif + +// For MinGW, the /export: directives contain undecorated symbols, contrary to +// link/lld-link. The GNU linker doesn't support /alternatename and /include +// though, thus lld-link in MinGW mode interprets them in the same way as +// in the default mode. +#ifdef __MINGW32__ +#define WIN_EXPORT_PREFIX +#else +#define WIN_EXPORT_PREFIX WIN_SYM_PREFIX +#endif + +// Intermediate macro to ensure the parameter is expanded before stringified. +#define STRINGIFY_(A) #A +#define STRINGIFY(A) STRINGIFY_(A) + +#if !SANITIZER_GO + +// ----------------- A workaround for the absence of weak symbols -------------- +// We don't have a direct equivalent of weak symbols when using MSVC, but we can +// use the /alternatename directive to tell the linker to default a specific +// symbol to a specific value. +// Take into account that this is a pragma directive for the linker, so it will +// be ignored by the compiler and the function will be marked as UNDEF in the +// symbol table of the resulting object file. The linker won't find the default +// implementation until it links with that object file. +// So, suppose we provide a default implementation "fundef" for "fun", and this +// is compiled into the object file "test.obj" including the pragma directive. +// If we have some code with references to "fun" and we link that code with +// "test.obj", it will work because the linker always link object files. +// But, if "test.obj" is included in a static library, like "test.lib", then the +// liker will only link to "test.obj" if necessary. If we only included the +// definition of "fun", it won't link to "test.obj" (from test.lib) because +// "fun" appears as UNDEF, so it doesn't resolve the symbol "fun", and will +// result in a link error (the linker doesn't find the pragma directive). +// So, a workaround is to force linkage with the modules that include weak +// definitions, with the following macro: WIN_FORCE_LINK() + +#define WIN_WEAK_ALIAS(Name, Default) \ + __pragma(comment(linker, "/alternatename:" WIN_SYM_PREFIX STRINGIFY(Name) "="\ + WIN_SYM_PREFIX STRINGIFY(Default))) + +#define WIN_FORCE_LINK(Name) \ + __pragma(comment(linker, "/include:" WIN_SYM_PREFIX STRINGIFY(Name))) + +#define WIN_EXPORT(ExportedName, Name) \ + __pragma(comment(linker, "/export:" WIN_EXPORT_PREFIX STRINGIFY(ExportedName)\ + "=" WIN_EXPORT_PREFIX STRINGIFY(Name))) + +// We cannot define weak functions on Windows, but we can use WIN_WEAK_ALIAS() +// which defines an alias to a default implementation, and only works when +// linking statically. +// So, to define a weak function "fun", we define a default implementation with +// a different name "fun__def" and we create a "weak alias" fun = fun__def. +// Then, users can override it just defining "fun". +// We impose "extern "C"" because otherwise WIN_WEAK_ALIAS() will fail because +// of name mangling. + +// Dummy name for default implementation of weak function. +# define WEAK_DEFAULT_NAME(Name) Name##__def +// Name for exported implementation of weak function. +# define WEAK_EXPORT_NAME(Name) Name##__dll + +// Use this macro when you need to define and export a weak function from a +// library. For example: +// WIN_WEAK_EXPORT_DEF(bool, compare, int a, int b) { return a > b; } +# define WIN_WEAK_EXPORT_DEF(ReturnType, Name, ...) \ + WIN_WEAK_ALIAS(Name, WEAK_DEFAULT_NAME(Name)) \ + WIN_EXPORT(WEAK_EXPORT_NAME(Name), Name) \ + extern "C" ReturnType Name(__VA_ARGS__); \ + extern "C" ReturnType WEAK_DEFAULT_NAME(Name)(__VA_ARGS__) + +// Use this macro when you need to import a weak function from a library. It +// defines a weak alias to the imported function from the dll. For example: +// WIN_WEAK_IMPORT_DEF(compare) +# define WIN_WEAK_IMPORT_DEF(Name) \ + WIN_WEAK_ALIAS(Name, WEAK_EXPORT_NAME(Name)) + +// So, for Windows we provide something similar to weak symbols in Linux, with +// some differences: +// + A default implementation must always be provided. +// +// + When linking statically it works quite similarly. For example: +// +// // libExample.cc +// WIN_WEAK_EXPORT_DEF(bool, compare, int a, int b) { return a > b; } +// +// // client.cc +// // We can use the default implementation from the library: +// compare(1, 2); +// // Or we can override it: +// extern "C" bool compare (int a, int b) { return a >= b; } +// +// And it will work fine. If we don't override the function, we need to ensure +// that the linker includes the object file with the default implementation. +// We can do so with the linker option "-wholearchive:". +// +// + When linking dynamically with a library (dll), weak functions are exported +// with "__dll" suffix. Clients can use the macro WIN_WEAK_IMPORT_DEF(fun) +// which defines a "weak alias" fun = fun__dll. +// +// // libExample.cc +// WIN_WEAK_EXPORT_DEF(bool, compare, int a, int b) { return a > b; } +// +// // client.cc +// WIN_WEAK_IMPORT_DEF(compare) +// // We can use the default implementation from the library: +// compare(1, 2); +// // Or we can override it: +// extern "C" bool compare (int a, int b) { return a >= b; } +// +// But if we override the function, the dlls don't have access to it (which +// is different in linux). If that is desired, the strong definition must be +// exported and interception can be used from the rest of the dlls. +// +// // libExample.cc +// WIN_WEAK_EXPORT_DEF(bool, compare, int a, int b) { return a > b; } +// // When initialized, check if the main executable defined "compare". +// int libExample_init() { +// uptr fnptr = __interception::InternalGetProcAddress( +// (void *)GetModuleHandleA(0), "compare"); +// if (fnptr && !__interception::OverrideFunction((uptr)compare, fnptr, 0)) +// abort(); +// return 0; +// } +// +// // client.cc +// WIN_WEAK_IMPORT_DEF(compare) +// // We override and export compare: +// extern "C" __declspec(dllexport) bool compare (int a, int b) { +// return a >= b; +// } +// + +#else // SANITIZER_GO + +// Go neither needs nor wants weak references. +// The shenanigans above don't work for gcc. +# define WIN_WEAK_EXPORT_DEF(ReturnType, Name, ...) \ + extern "C" ReturnType Name(__VA_ARGS__) + +#endif // SANITIZER_GO + +#endif // SANITIZER_WINDOWS +#endif // SANITIZER_WIN_DEFS_H diff --git a/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_win_dll_thunk.h b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_win_dll_thunk.h new file mode 100644 index 0000000000..48c73c4c98 --- /dev/null +++ b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_win_dll_thunk.h @@ -0,0 +1,181 @@ +//===-- sanitizer_win_dll_thunk.h -----------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// This header provide helper macros to delegate calls to the shared runtime +// that lives in the main executable. It should be included to dll_thunks that +// will be linked to the dlls, when the sanitizer is a static library included +// in the main executable. +//===----------------------------------------------------------------------===// +#ifndef SANITIZER_WIN_DLL_THUNK_H +#define SANITIZER_WIN_DLL_THUNK_H +#include "sanitizer_internal_defs.h" + +namespace __sanitizer { +uptr dllThunkGetRealAddrOrDie(const char *name); + +int dllThunkIntercept(const char* main_function, uptr dll_function); + +int dllThunkInterceptWhenPossible(const char* main_function, + const char* default_function, uptr dll_function); +} + +extern "C" int __dll_thunk_init(); + +// ----------------- Function interception helper macros -------------------- // +// Override dll_function with main_function from main executable. +#define INTERCEPT_OR_DIE(main_function, dll_function) \ + static int intercept_##dll_function() { \ + return __sanitizer::dllThunkIntercept(main_function, (__sanitizer::uptr) \ + dll_function); \ + } \ + __pragma(section(".DLLTH$M", long, read)) \ + __declspec(allocate(".DLLTH$M")) int (*__dll_thunk_##dll_function)() = \ + intercept_##dll_function; + +// Try to override dll_function with main_function from main executable. +// If main_function is not present, override dll_function with default_function. +#define INTERCEPT_WHEN_POSSIBLE(main_function, default_function, dll_function) \ + static int intercept_##dll_function() { \ + return __sanitizer::dllThunkInterceptWhenPossible(main_function, \ + default_function, (__sanitizer::uptr)dll_function); \ + } \ + __pragma(section(".DLLTH$M", long, read)) \ + __declspec(allocate(".DLLTH$M")) int (*__dll_thunk_##dll_function)() = \ + intercept_##dll_function; + +// -------------------- Function interception macros ------------------------ // +// Special case of hooks -- ASan own interface functions. Those are only called +// after __asan_init, thus an empty implementation is sufficient. +#define INTERCEPT_SANITIZER_FUNCTION(name) \ + extern "C" __declspec(noinline) void name() { \ + volatile int prevent_icf = (__LINE__ << 8) ^ __COUNTER__; \ + static const char function_name[] = #name; \ + for (const char* ptr = &function_name[0]; *ptr; ++ptr) \ + prevent_icf ^= *ptr; \ + (void)prevent_icf; \ + __debugbreak(); \ + } \ + INTERCEPT_OR_DIE(#name, name) + +// Special case of hooks -- Weak functions, could be redefined in the main +// executable, but that is not necessary, so we shouldn't die if we can not find +// a reference. Instead, when the function is not present in the main executable +// we consider the default impl provided by asan library. +#define INTERCEPT_SANITIZER_WEAK_FUNCTION(name) \ + extern "C" __declspec(noinline) void name() { \ + volatile int prevent_icf = (__LINE__ << 8) ^ __COUNTER__; \ + static const char function_name[] = #name; \ + for (const char* ptr = &function_name[0]; *ptr; ++ptr) \ + prevent_icf ^= *ptr; \ + (void)prevent_icf; \ + __debugbreak(); \ + } \ + INTERCEPT_WHEN_POSSIBLE(#name, STRINGIFY(WEAK_EXPORT_NAME(name)), name) + +// We can't define our own version of strlen etc. because that would lead to +// link-time or even type mismatch errors. Instead, we can declare a function +// just to be able to get its address. Me may miss the first few calls to the +// functions since it can be called before __dll_thunk_init, but that would lead +// to false negatives in the startup code before user's global initializers, +// which isn't a big deal. +#define INTERCEPT_LIBRARY_FUNCTION(name) \ + extern "C" void name(); \ + INTERCEPT_OR_DIE(WRAPPER_NAME(name), name) + +// Use these macros for functions that could be called before __dll_thunk_init() +// is executed and don't lead to errors if defined (free, malloc, etc). +#define INTERCEPT_WRAP_V_V(name) \ + extern "C" void name() { \ + typedef decltype(name) *fntype; \ + static fntype fn = (fntype)__sanitizer::dllThunkGetRealAddrOrDie(#name); \ + fn(); \ + } \ + INTERCEPT_OR_DIE(#name, name); + +#define INTERCEPT_WRAP_V_W(name) \ + extern "C" void name(void *arg) { \ + typedef decltype(name) *fntype; \ + static fntype fn = (fntype)__sanitizer::dllThunkGetRealAddrOrDie(#name); \ + fn(arg); \ + } \ + INTERCEPT_OR_DIE(#name, name); + +#define INTERCEPT_WRAP_V_WW(name) \ + extern "C" void name(void *arg1, void *arg2) { \ + typedef decltype(name) *fntype; \ + static fntype fn = (fntype)__sanitizer::dllThunkGetRealAddrOrDie(#name); \ + fn(arg1, arg2); \ + } \ + INTERCEPT_OR_DIE(#name, name); + +#define INTERCEPT_WRAP_V_WWW(name) \ + extern "C" void name(void *arg1, void *arg2, void *arg3) { \ + typedef decltype(name) *fntype; \ + static fntype fn = (fntype)__sanitizer::dllThunkGetRealAddrOrDie(#name); \ + fn(arg1, arg2, arg3); \ + } \ + INTERCEPT_OR_DIE(#name, name); + +#define INTERCEPT_WRAP_W_V(name) \ + extern "C" void *name() { \ + typedef decltype(name) *fntype; \ + static fntype fn = (fntype)__sanitizer::dllThunkGetRealAddrOrDie(#name); \ + return fn(); \ + } \ + INTERCEPT_OR_DIE(#name, name); + +#define INTERCEPT_WRAP_W_W(name) \ + extern "C" void *name(void *arg) { \ + typedef decltype(name) *fntype; \ + static fntype fn = (fntype)__sanitizer::dllThunkGetRealAddrOrDie(#name); \ + return fn(arg); \ + } \ + INTERCEPT_OR_DIE(#name, name); + +#define INTERCEPT_WRAP_W_WW(name) \ + extern "C" void *name(void *arg1, void *arg2) { \ + typedef decltype(name) *fntype; \ + static fntype fn = (fntype)__sanitizer::dllThunkGetRealAddrOrDie(#name); \ + return fn(arg1, arg2); \ + } \ + INTERCEPT_OR_DIE(#name, name); + +#define INTERCEPT_WRAP_W_WWW(name) \ + extern "C" void *name(void *arg1, void *arg2, void *arg3) { \ + typedef decltype(name) *fntype; \ + static fntype fn = (fntype)__sanitizer::dllThunkGetRealAddrOrDie(#name); \ + return fn(arg1, arg2, arg3); \ + } \ + INTERCEPT_OR_DIE(#name, name); + +#define INTERCEPT_WRAP_W_WWWW(name) \ + extern "C" void *name(void *arg1, void *arg2, void *arg3, void *arg4) { \ + typedef decltype(name) *fntype; \ + static fntype fn = (fntype)__sanitizer::dllThunkGetRealAddrOrDie(#name); \ + return fn(arg1, arg2, arg3, arg4); \ + } \ + INTERCEPT_OR_DIE(#name, name); + +#define INTERCEPT_WRAP_W_WWWWW(name) \ + extern "C" void *name(void *arg1, void *arg2, void *arg3, void *arg4, \ + void *arg5) { \ + typedef decltype(name) *fntype; \ + static fntype fn = (fntype)__sanitizer::dllThunkGetRealAddrOrDie(#name); \ + return fn(arg1, arg2, arg3, arg4, arg5); \ + } \ + INTERCEPT_OR_DIE(#name, name); + +#define INTERCEPT_WRAP_W_WWWWWW(name) \ + extern "C" void *name(void *arg1, void *arg2, void *arg3, void *arg4, \ + void *arg5, void *arg6) { \ + typedef decltype(name) *fntype; \ + static fntype fn = (fntype)__sanitizer::dllThunkGetRealAddrOrDie(#name); \ + return fn(arg1, arg2, arg3, arg4, arg5, arg6); \ + } \ + INTERCEPT_OR_DIE(#name, name); + +#endif // SANITIZER_WIN_DLL_THUNK_H diff --git a/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_win_weak_interception.h b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_win_weak_interception.h new file mode 100644 index 0000000000..5e4d8b8def --- /dev/null +++ b/contrib/libs/clang14-rt/lib/sanitizer_common/sanitizer_win_weak_interception.h @@ -0,0 +1,32 @@ +//===-- sanitizer_win_weak_interception.h ---------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// This header provide helper macros to delegate calls of weak functions to the +// implementation in the main executable when a strong definition is present. +//===----------------------------------------------------------------------===// +#ifndef SANITIZER_WIN_WEAK_INTERCEPTION_H +#define SANITIZER_WIN_WEAK_INTERCEPTION_H +#include "sanitizer_internal_defs.h" + +namespace __sanitizer { +int interceptWhenPossible(uptr dll_function, const char *real_function); +} + +// ----------------- Function interception helper macros -------------------- // +// Weak functions, could be redefined in the main executable, but that is not +// necessary, so we shouldn't die if we can not find a reference. +#define INTERCEPT_WEAK(Name) interceptWhenPossible((uptr) Name, #Name); + +#define INTERCEPT_SANITIZER_WEAK_FUNCTION(Name) \ + static int intercept_##Name() { \ + return __sanitizer::interceptWhenPossible((__sanitizer::uptr) Name, #Name);\ + } \ + __pragma(section(".WEAK$M", long, read)) \ + __declspec(allocate(".WEAK$M")) int (*__weak_intercept_##Name)() = \ + intercept_##Name; + +#endif // SANITIZER_WIN_WEAK_INTERCEPTION_H |