Index: projects/clang400-import/contrib/compiler-rt/include/sanitizer/common_interface_defs.h =================================================================== --- projects/clang400-import/contrib/compiler-rt/include/sanitizer/common_interface_defs.h (revision 311696) +++ projects/clang400-import/contrib/compiler-rt/include/sanitizer/common_interface_defs.h (revision 311697) @@ -1,177 +1,196 @@ //===-- sanitizer/common_interface_defs.h -----------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // Common part of the public sanitizer interface. //===----------------------------------------------------------------------===// #ifndef SANITIZER_COMMON_INTERFACE_DEFS_H #define SANITIZER_COMMON_INTERFACE_DEFS_H #include #include // GCC does not understand __has_feature. #if !defined(__has_feature) # define __has_feature(x) 0 #endif #ifdef __cplusplus extern "C" { #endif // Arguments for __sanitizer_sandbox_on_notify() below. typedef struct { // Enable sandbox support in sanitizer coverage. int coverage_sandboxed; // File descriptor to write coverage data to. If -1 is passed, a file will // be pre-opened by __sanitizer_sandobx_on_notify(). This field has no // effect if coverage_sandboxed == 0. intptr_t coverage_fd; // If non-zero, split the coverage data into well-formed blocks. This is // useful when coverage_fd is a socket descriptor. Each block will contain // a header, allowing data from multiple processes to be sent over the same // socket. unsigned int coverage_max_block_size; } __sanitizer_sandbox_arguments; // Tell the tools to write their reports to "path." instead of stderr. void __sanitizer_set_report_path(const char *path); // Tell the tools to write their reports to the provided file descriptor // (casted to void *). void __sanitizer_set_report_fd(void *fd); // Notify the tools that the sandbox is going to be turned on. The reserved // parameter will be used in the future to hold a structure with functions // that the tools may call to bypass the sandbox. 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. void __sanitizer_report_error_summary(const char *error_summary); // Some of the sanitizers (e.g. asan/tsan) may miss bugs that happen // in unaligned loads/stores. In order to find such bugs reliably one needs // to replace plain unaligned loads/stores with these calls. uint16_t __sanitizer_unaligned_load16(const void *p); uint32_t __sanitizer_unaligned_load32(const void *p); uint64_t __sanitizer_unaligned_load64(const void *p); void __sanitizer_unaligned_store16(void *p, uint16_t x); void __sanitizer_unaligned_store32(void *p, uint32_t x); void __sanitizer_unaligned_store64(void *p, uint64_t x); // Annotate the current state of a contiguous container, such as // std::vector, std::string or similar. // A contiguous container is a container that keeps all of its elements // in a contiguous region of memory. The container owns the region of memory // [beg, end); the memory [beg, mid) is used to store the current elements // and the memory [mid, end) is reserved for future elements; // beg <= mid <= end. For example, in "std::vector<> v" // beg = &v[0]; // end = beg + v.capacity() * sizeof(v[0]); // mid = beg + v.size() * sizeof(v[0]); // // This annotation tells the Sanitizer tool about the current state of the // container so that the tool can report errors when memory from [mid, end) // is accessed. Insert this annotation into methods like push_back/pop_back. // Supply the old and the new values of mid (old_mid/new_mid). // In the initial state mid == end and so should be the final // state when the container is destroyed or when it reallocates the storage. // // Use with caution and don't use for anything other than vector-like classes. // // For AddressSanitizer, 'beg' should be 8-aligned and 'end' should // be either 8-aligned or it should point to the end of a separate heap-, // stack-, or global- allocated buffer. I.e. the following will not work: // int64_t x[2]; // 16 bytes, 8-aligned. // char *beg = (char *)&x[0]; // char *end = beg + 12; // Not 8 aligned, not the end of the buffer. // This however will work fine: // int32_t x[3]; // 12 bytes, but 8-aligned under AddressSanitizer. // char *beg = (char*)&x[0]; // char *end = beg + 12; // Not 8-aligned, but is the end of the buffer. void __sanitizer_annotate_contiguous_container(const void *beg, const void *end, const void *old_mid, const void *new_mid); // Returns true if the contiguous container [beg, end) is properly poisoned // (e.g. with __sanitizer_annotate_contiguous_container), i.e. if // - [beg, mid) is addressable, // - [mid, end) is unaddressable. // Full verification requires O(end-beg) time; this function tries to avoid // such complexity by touching only parts of the container around beg/mid/end. int __sanitizer_verify_contiguous_container(const void *beg, const void *mid, const void *end); // Similar to __sanitizer_verify_contiguous_container but returns the address // of the first improperly poisoned byte otherwise. Returns null if the area // is poisoned properly. const void *__sanitizer_contiguous_container_find_bad_address( const void *beg, const void *mid, const void *end); // Print the stack trace leading to this call. Useful for debugging user code. void __sanitizer_print_stack_trace(); + // Symbolizes the supplied 'pc' using the format string 'fmt'. + // Outputs at most 'out_buf_size' bytes into 'out_buf'. + // The format syntax is described in + // lib/sanitizer_common/sanitizer_stacktrace_printer.h. + void __sanitizer_symbolize_pc(void *pc, const char *fmt, char *out_buf, + size_t out_buf_size); + // Same as __sanitizer_symbolize_pc, but for data section (i.e. globals). + void __sanitizer_symbolize_global(void *data_ptr, const char *fmt, + char *out_buf, size_t out_buf_size); + // Sets the callback to be called right before death on error. // Passing 0 will unset the callback. void __sanitizer_set_death_callback(void (*callback)(void)); // Interceptor hooks. // Whenever a libc function interceptor is called it checks if the // corresponding weak hook is defined, and it so -- calls it. // The primary use case is data-flow-guided fuzzing, where the fuzzer needs // to know what is being passed to libc functions, e.g. memcmp. // FIXME: implement more hooks. void __sanitizer_weak_hook_memcmp(void *called_pc, const void *s1, const void *s2, size_t n, int result); void __sanitizer_weak_hook_strncmp(void *called_pc, const char *s1, const char *s2, size_t n, int result); void __sanitizer_weak_hook_strncasecmp(void *called_pc, const char *s1, const char *s2, size_t n, int result); void __sanitizer_weak_hook_strcmp(void *called_pc, const char *s1, const char *s2, int result); void __sanitizer_weak_hook_strcasecmp(void *called_pc, const char *s1, const char *s2, int result); void __sanitizer_weak_hook_strstr(void *called_pc, const char *s1, const char *s2, char *result); void __sanitizer_weak_hook_strcasestr(void *called_pc, const char *s1, const char *s2, char *result); void __sanitizer_weak_hook_memmem(void *called_pc, const void *s1, size_t len1, const void *s2, size_t len2, void *result); // Prints stack traces for all live heap allocations ordered by total // allocation size until `top_percent` of total live heap is shown. // `top_percent` should be between 1 and 100. // Experimental feature currently available only with asan on Linux/x86_64. void __sanitizer_print_memory_profile(size_t top_percent); // Fiber annotation interface. // Before switching to a different stack, one must call // __sanitizer_start_switch_fiber with a pointer to the bottom of the // destination stack and its size. When code starts running on the new stack, // it must call __sanitizer_finish_switch_fiber to finalize the switch. // The start_switch function takes a void** to store the current fake stack if // there is one (it is needed when detect_stack_use_after_return is enabled). // When restoring a stack, this pointer must be given to the finish_switch // function. In most cases, this void* can be stored on the stack just before // switching. When leaving a fiber definitely, null must be passed as first // argument to the start_switch function so that the fake stack is destroyed. // If you do not want support for stack use-after-return detection, you can // always pass null to these two functions. // Note that the fake stack mechanism is disabled during fiber switch, so if a // signal callback runs during the switch, it will not benefit from the stack // use-after-return detection. void __sanitizer_start_switch_fiber(void **fake_stack_save, const void *bottom, size_t size); - void __sanitizer_finish_switch_fiber(void *fake_stack_save); + void __sanitizer_finish_switch_fiber(void *fake_stack_save, + const void **bottom_old, + size_t *size_old); + + // Get full module name and calculate pc offset within it. + // Returns 1 if pc belongs to some module, 0 if module was not found. + int __sanitizer_get_module_and_offset_for_pc(void *pc, char *module_path, + size_t module_path_len, + void **pc_offset); + #ifdef __cplusplus } // extern "C" #endif #endif // SANITIZER_COMMON_INTERFACE_DEFS_H Index: projects/clang400-import/contrib/compiler-rt/include/sanitizer/coverage_interface.h =================================================================== --- projects/clang400-import/contrib/compiler-rt/include/sanitizer/coverage_interface.h (revision 311696) +++ projects/clang400-import/contrib/compiler-rt/include/sanitizer/coverage_interface.h (revision 311697) @@ -1,72 +1,71 @@ //===-- sanitizer/coverage_interface.h --------------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // Public interface for sanitizer coverage. //===----------------------------------------------------------------------===// #ifndef SANITIZER_COVERAG_INTERFACE_H #define SANITIZER_COVERAG_INTERFACE_H #include #ifdef __cplusplus extern "C" { #endif // Initialize coverage. void __sanitizer_cov_init(); // Record and dump coverage info. void __sanitizer_cov_dump(); + + // Dump collected coverage info. Sorts pcs by module into individual + // .sancov files. + void __sanitizer_dump_coverage(const uintptr_t *pcs, uintptr_t len); + // Open .sancov.packed in the coverage directory and return the file // descriptor. Returns -1 on failure, or if coverage dumping is disabled. // This is intended for use by sandboxing code. intptr_t __sanitizer_maybe_open_cov_file(const char *name); // Get the number of unique covered blocks (or edges). // This can be useful for coverage-directed in-process fuzzers. uintptr_t __sanitizer_get_total_unique_coverage(); // Get the number of unique indirect caller-callee pairs. uintptr_t __sanitizer_get_total_unique_caller_callee_pairs(); // Reset the basic-block (edge) coverage to the initial state. // Useful for in-process fuzzing to start collecting coverage from scratch. // Experimental, will likely not work for multi-threaded process. void __sanitizer_reset_coverage(); // Set *data to the array of covered PCs and return the size of that array. // Some of the entries in *data will be zero. uintptr_t __sanitizer_get_coverage_guards(uintptr_t **data); - // Set *data to the growing buffer with covered PCs and return the size - // of the buffer. The entries are never zero. - // When only unique pcs are collected, the size is equal to - // __sanitizer_get_total_unique_coverage. - // WARNING: EXPERIMENTAL API. - uintptr_t __sanitizer_get_coverage_pc_buffer(uintptr_t **data); - // The coverage instrumentation may optionally provide imprecise counters. // Rather than exposing the counter values to the user we instead map // the counters to a bitset. // Every counter is associated with 8 bits in the bitset. // We define 8 value ranges: 1, 2, 3, 4-7, 8-15, 16-31, 32-127, 128+ // The i-th bit is set to 1 if the counter value is in the i-th range. // This counter-based coverage implementation is *not* thread-safe. // Returns the number of registered coverage counters. uintptr_t __sanitizer_get_number_of_counters(); // Updates the counter 'bitset', clears the counters and returns the number of // new bits in 'bitset'. // If 'bitset' is nullptr, only clears the counters. // Otherwise 'bitset' should be at least // __sanitizer_get_number_of_counters bytes long and 8-aligned. uintptr_t __sanitizer_update_counter_bitset_and_clear_counters(uint8_t *bitset); + #ifdef __cplusplus } // extern "C" #endif #endif // SANITIZER_COVERAG_INTERFACE_H Index: projects/clang400-import/contrib/compiler-rt/include/xray/xray_interface.h =================================================================== --- projects/clang400-import/contrib/compiler-rt/include/xray/xray_interface.h (nonexistent) +++ projects/clang400-import/contrib/compiler-rt/include/xray/xray_interface.h (revision 311697) @@ -0,0 +1,65 @@ +//===-- xray_interface.h ----------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file is a part of XRay, a dynamic runtime instrumentation system. +// +// APIs for controlling XRay functionality explicitly. +//===----------------------------------------------------------------------===// +#ifndef XRAY_XRAY_INTERFACE_H +#define XRAY_XRAY_INTERFACE_H + +#include + +extern "C" { + +enum XRayEntryType { ENTRY = 0, EXIT = 1, TAIL = 2 }; + +// Provide a function to invoke for when instrumentation points are hit. This is +// a user-visible control surface that overrides the default implementation. The +// function provided should take the following arguments: +// +// - function id: an identifier that indicates the id of a function; this id +// is generated by xray; the mapping between the function id +// and the actual function pointer is available through +// __xray_table. +// - entry type: identifies what kind of instrumentation point was encountered +// (function entry, function exit, etc.). See the enum +// XRayEntryType for more details. +// +// The user handler must handle correctly spurious calls after this handler is +// removed or replaced with another handler, because it would be too costly for +// XRay runtime to avoid spurious calls. +// To prevent circular calling, the handler function itself and all its +// direct&indirect callees must not be instrumented with XRay, which can be +// achieved by marking them all with: __attribute__((xray_never_instrument)) +// +// Returns 1 on success, 0 on error. +extern int __xray_set_handler(void (*entry)(int32_t, XRayEntryType)); + +// This removes whatever the currently provided handler is. Returns 1 on +// success, 0 on error. +extern int __xray_remove_handler(); + +enum XRayPatchingStatus { + NOT_INITIALIZED = 0, + SUCCESS = 1, + ONGOING = 2, + FAILED = 3, +}; + +// This tells XRay to patch the instrumentation points. See XRayPatchingStatus +// for possible result values. +extern XRayPatchingStatus __xray_patch(); + +// Reverses the effect of __xray_patch(). See XRayPatchingStatus for possible +// result values. +extern XRayPatchingStatus __xray_unpatch(); +} + +#endif Property changes on: projects/clang400-import/contrib/compiler-rt/include/xray/xray_interface.h ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: projects/clang400-import/contrib/compiler-rt/include/xray/xray_records.h =================================================================== --- projects/clang400-import/contrib/compiler-rt/include/xray/xray_records.h (nonexistent) +++ projects/clang400-import/contrib/compiler-rt/include/xray/xray_records.h (revision 311697) @@ -0,0 +1,80 @@ +//===-- xray_records.h ------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file is a part of XRay, a dynamic runtime instrumentation system. +// +// This header exposes some record types useful for the XRay in-memory logging +// implementation. +// +//===----------------------------------------------------------------------===// + +#ifndef XRAY_XRAY_RECORDS_H +#define XRAY_XRAY_RECORDS_H + +namespace __xray { + +enum FileTypes { + NAIVE_LOG = 0, +}; + +// This data structure is used to describe the contents of the file. We use this +// for versioning the supported XRay file formats. +struct alignas(32) XRayFileHeader { + uint16_t Version = 0; + + // The type of file we're writing out. See the FileTypes enum for more + // information. This allows different implementations of the XRay logging to + // have different files for different information being stored. + uint16_t Type = 0; + + // What follows are a set of flags that indicate useful things for when + // reading the data in the file. + bool ConstantTSC : 1; + bool NonstopTSC : 1; + + // The frequency by which TSC increases per-second. + alignas(8) uint64_t CycleFrequency = 0; +} __attribute__((packed)); + +static_assert(sizeof(XRayFileHeader) == 32, "XRayFileHeader != 32 bytes"); + +enum RecordTypes { + NORMAL = 0, +}; + +struct alignas(32) XRayRecord { + // This is the type of the record being written. We use 16 bits to allow us to + // treat this as a discriminant, and so that the first 4 bytes get packed + // properly. See RecordTypes for more supported types. + uint16_t RecordType = 0; + + // The CPU where the thread is running. We assume number of CPUs <= 256. + uint8_t CPU = 0; + + // The type of the event. Usually either ENTER = 0 or EXIT = 1. + uint8_t Type = 0; + + // The function ID for the record. + int32_t FuncId = 0; + + // Get the full 8 bytes of the TSC when we get the log record. + uint64_t TSC = 0; + + // The thread ID for the currently running thread. + uint32_t TId = 0; + + // Use some bytes in the end of the record for buffers. + char Buffer[4] = {}; +} __attribute__((packed)); + +static_assert(sizeof(XRayRecord) == 32, "XRayRecord != 32 bytes"); + +} // namespace __xray + +#endif // XRAY_XRAY_RECORDS_H Property changes on: projects/clang400-import/contrib/compiler-rt/include/xray/xray_records.h ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: projects/clang400-import/contrib/compiler-rt/lib/asan/asan_activation.cc =================================================================== --- projects/clang400-import/contrib/compiler-rt/lib/asan/asan_activation.cc (revision 311696) +++ projects/clang400-import/contrib/compiler-rt/lib/asan/asan_activation.cc (revision 311697) @@ -1,140 +1,142 @@ //===-- asan_activation.cc --------------------------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // This file is a part of AddressSanitizer, an address sanity checker. // // ASan activation/deactivation logic. //===----------------------------------------------------------------------===// #include "asan_activation.h" #include "asan_allocator.h" #include "asan_flags.h" #include "asan_internal.h" #include "asan_poisoning.h" #include "asan_stack.h" #include "sanitizer_common/sanitizer_flags.h" namespace __asan { static struct AsanDeactivatedFlags { AllocatorOptions allocator_options; int malloc_context_size; bool poison_heap; bool coverage; const char *coverage_dir; void RegisterActivationFlags(FlagParser *parser, Flags *f, CommonFlags *cf) { #define ASAN_ACTIVATION_FLAG(Type, Name) \ RegisterFlag(parser, #Name, "", &f->Name); #define COMMON_ACTIVATION_FLAG(Type, Name) \ RegisterFlag(parser, #Name, "", &cf->Name); #include "asan_activation_flags.inc" #undef ASAN_ACTIVATION_FLAG #undef COMMON_ACTIVATION_FLAG RegisterIncludeFlags(parser, cf); } void OverrideFromActivationFlags() { Flags f; CommonFlags cf; FlagParser parser; RegisterActivationFlags(&parser, &f, &cf); cf.SetDefaults(); // Copy the current activation flags. allocator_options.CopyTo(&f, &cf); cf.malloc_context_size = malloc_context_size; f.poison_heap = poison_heap; cf.coverage = coverage; cf.coverage_dir = coverage_dir; cf.verbosity = Verbosity(); cf.help = false; // this is activation-specific help // Check if activation flags need to be overriden. if (const char *env = GetEnv("ASAN_ACTIVATION_OPTIONS")) { parser.ParseString(env); } InitializeCommonFlags(&cf); if (Verbosity()) ReportUnrecognizedFlags(); if (cf.help) parser.PrintFlagDescriptions(); allocator_options.SetFrom(&f, &cf); malloc_context_size = cf.malloc_context_size; poison_heap = f.poison_heap; coverage = cf.coverage; coverage_dir = cf.coverage_dir; } void Print() { Report( "quarantine_size_mb %d, max_redzone %d, poison_heap %d, " "malloc_context_size %d, alloc_dealloc_mismatch %d, " - "allocator_may_return_null %d, coverage %d, coverage_dir %s\n", + "allocator_may_return_null %d, coverage %d, coverage_dir %s, " + "allocator_release_to_os_interval_ms %d\n", allocator_options.quarantine_size_mb, allocator_options.max_redzone, poison_heap, malloc_context_size, allocator_options.alloc_dealloc_mismatch, - allocator_options.may_return_null, coverage, coverage_dir); + allocator_options.may_return_null, coverage, coverage_dir, + allocator_options.release_to_os_interval_ms); } } asan_deactivated_flags; static bool asan_is_deactivated; void AsanDeactivate() { CHECK(!asan_is_deactivated); VReport(1, "Deactivating ASan\n"); // Stash runtime state. GetAllocatorOptions(&asan_deactivated_flags.allocator_options); asan_deactivated_flags.malloc_context_size = GetMallocContextSize(); asan_deactivated_flags.poison_heap = CanPoisonMemory(); asan_deactivated_flags.coverage = common_flags()->coverage; asan_deactivated_flags.coverage_dir = common_flags()->coverage_dir; // Deactivate the runtime. SetCanPoisonMemory(false); SetMallocContextSize(1); ReInitializeCoverage(false, nullptr); AllocatorOptions disabled = asan_deactivated_flags.allocator_options; disabled.quarantine_size_mb = 0; disabled.min_redzone = 16; // Redzone must be at least 16 bytes long. disabled.max_redzone = 16; disabled.alloc_dealloc_mismatch = false; disabled.may_return_null = true; ReInitializeAllocator(disabled); asan_is_deactivated = true; } void AsanActivate() { if (!asan_is_deactivated) return; VReport(1, "Activating ASan\n"); UpdateProcessName(); asan_deactivated_flags.OverrideFromActivationFlags(); SetCanPoisonMemory(asan_deactivated_flags.poison_heap); SetMallocContextSize(asan_deactivated_flags.malloc_context_size); ReInitializeCoverage(asan_deactivated_flags.coverage, asan_deactivated_flags.coverage_dir); ReInitializeAllocator(asan_deactivated_flags.allocator_options); asan_is_deactivated = false; if (Verbosity()) { Report("Activated with flags:\n"); asan_deactivated_flags.Print(); } } } // namespace __asan Index: projects/clang400-import/contrib/compiler-rt/lib/asan/asan_activation_flags.inc =================================================================== --- projects/clang400-import/contrib/compiler-rt/lib/asan/asan_activation_flags.inc (revision 311696) +++ projects/clang400-import/contrib/compiler-rt/lib/asan/asan_activation_flags.inc (revision 311697) @@ -1,35 +1,36 @@ //===-- asan_activation_flags.inc -------------------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // A subset of ASan (and common) runtime flags supported at activation time. // //===----------------------------------------------------------------------===// #ifndef ASAN_ACTIVATION_FLAG # error "Define ASAN_ACTIVATION_FLAG prior to including this file!" #endif #ifndef COMMON_ACTIVATION_FLAG # error "Define COMMON_ACTIVATION_FLAG prior to including this file!" #endif // ASAN_ACTIVATION_FLAG(Type, Name) // See COMMON_FLAG in sanitizer_flags.inc for more details. ASAN_ACTIVATION_FLAG(int, redzone) ASAN_ACTIVATION_FLAG(int, max_redzone) ASAN_ACTIVATION_FLAG(int, quarantine_size_mb) ASAN_ACTIVATION_FLAG(bool, alloc_dealloc_mismatch) ASAN_ACTIVATION_FLAG(bool, poison_heap) COMMON_ACTIVATION_FLAG(bool, allocator_may_return_null) COMMON_ACTIVATION_FLAG(int, malloc_context_size) COMMON_ACTIVATION_FLAG(bool, coverage) COMMON_ACTIVATION_FLAG(const char *, coverage_dir) COMMON_ACTIVATION_FLAG(int, verbosity) COMMON_ACTIVATION_FLAG(bool, help) +COMMON_ACTIVATION_FLAG(s32, allocator_release_to_os_interval_ms) Index: projects/clang400-import/contrib/compiler-rt/lib/asan/asan_allocator.cc =================================================================== --- projects/clang400-import/contrib/compiler-rt/lib/asan/asan_allocator.cc (revision 311696) +++ projects/clang400-import/contrib/compiler-rt/lib/asan/asan_allocator.cc (revision 311697) @@ -1,924 +1,972 @@ //===-- asan_allocator.cc -------------------------------------------------===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // This file is a part of AddressSanitizer, an address sanity checker. // // Implementation of ASan's memory allocator, 2-nd version. // This variant uses the allocator from sanitizer_common, i.e. the one shared // with ThreadSanitizer and MemorySanitizer. // //===----------------------------------------------------------------------===// #include "asan_allocator.h" #include "asan_mapping.h" #include "asan_poisoning.h" #include "asan_report.h" #include "asan_stack.h" #include "asan_thread.h" #include "sanitizer_common/sanitizer_allocator_interface.h" #include "sanitizer_common/sanitizer_flags.h" #include "sanitizer_common/sanitizer_internal_defs.h" #include "sanitizer_common/sanitizer_list.h" #include "sanitizer_common/sanitizer_stackdepot.h" #include "sanitizer_common/sanitizer_quarantine.h" #include "lsan/lsan_common.h" namespace __asan { // Valid redzone sizes are 16, 32, 64, ... 2048, so we encode them in 3 bits. // We use adaptive redzones: for larger allocation larger redzones are used. static u32 RZLog2Size(u32 rz_log) { CHECK_LT(rz_log, 8); return 16 << rz_log; } static u32 RZSize2Log(u32 rz_size) { CHECK_GE(rz_size, 16); CHECK_LE(rz_size, 2048); CHECK(IsPowerOfTwo(rz_size)); u32 res = Log2(rz_size) - 4; CHECK_EQ(rz_size, RZLog2Size(res)); return res; } static AsanAllocator &get_allocator(); // The memory chunk allocated from the underlying allocator looks like this: // L L L L L L H H U U U U U U R R // L -- left redzone words (0 or more bytes) // H -- ChunkHeader (16 bytes), which is also a part of the left redzone. // U -- user memory. // R -- right redzone (0 or more bytes) // ChunkBase consists of ChunkHeader and other bytes that overlap with user // memory. // If the left redzone is greater than the ChunkHeader size we store a magic // value in the first uptr word of the memory block and store the address of // ChunkBase in the next uptr. // M B L L L L L L L L L H H U U U U U U // | ^ // ---------------------| // M -- magic value kAllocBegMagic // B -- address of ChunkHeader pointing to the first 'H' static const uptr kAllocBegMagic = 0xCC6E96B9; struct ChunkHeader { // 1-st 8 bytes. u32 chunk_state : 8; // Must be first. u32 alloc_tid : 24; u32 free_tid : 24; u32 from_memalign : 1; u32 alloc_type : 2; u32 rz_log : 3; u32 lsan_tag : 2; // 2-nd 8 bytes // This field is used for small sizes. For large sizes it is equal to // SizeClassMap::kMaxSize and the actual size is stored in the // SecondaryAllocator's metadata. u32 user_requested_size; u32 alloc_context_id; }; struct ChunkBase : ChunkHeader { // Header2, intersects with user memory. u32 free_context_id; }; static const uptr kChunkHeaderSize = sizeof(ChunkHeader); static const uptr kChunkHeader2Size = sizeof(ChunkBase) - kChunkHeaderSize; COMPILER_CHECK(kChunkHeaderSize == 16); COMPILER_CHECK(kChunkHeader2Size <= 16); // Every chunk of memory allocated by this allocator can be in one of 3 states: // CHUNK_AVAILABLE: the chunk is in the free list and ready to be allocated. // CHUNK_ALLOCATED: the chunk is allocated and not yet freed. // CHUNK_QUARANTINE: the chunk was freed and put into quarantine zone. enum { CHUNK_AVAILABLE = 0, // 0 is the default value even if we didn't set it. CHUNK_ALLOCATED = 2, CHUNK_QUARANTINE = 3 }; struct AsanChunk: ChunkBase { uptr Beg() { return reinterpret_cast(this) + kChunkHeaderSize; } uptr UsedSize(bool locked_version = false) { if (user_requested_size != SizeClassMap::kMaxSize) return user_requested_size; return *reinterpret_cast( get_allocator().GetMetaData(AllocBeg(locked_version))); } void *AllocBeg(bool locked_version = false) { if (from_memalign) { if (locked_version) return get_allocator().GetBlockBeginFastLocked( reinterpret_cast(this)); return get_allocator().GetBlockBegin(reinterpret_cast(this)); } return reinterpret_cast(Beg() - RZLog2Size(rz_log)); } bool AddrIsInside(uptr addr, bool locked_version = false) { return (addr >= Beg()) && (addr < Beg() + UsedSize(locked_version)); } }; struct QuarantineCallback { explicit QuarantineCallback(AllocatorCache *cache) : cache_(cache) { } void Recycle(AsanChunk *m) { CHECK_EQ(m->chunk_state, CHUNK_QUARANTINE); atomic_store((atomic_uint8_t*)m, CHUNK_AVAILABLE, memory_order_relaxed); CHECK_NE(m->alloc_tid, kInvalidTid); CHECK_NE(m->free_tid, kInvalidTid); PoisonShadow(m->Beg(), RoundUpTo(m->UsedSize(), SHADOW_GRANULARITY), kAsanHeapLeftRedzoneMagic); void *p = reinterpret_cast(m->AllocBeg()); if (p != m) { uptr *alloc_magic = reinterpret_cast(p); CHECK_EQ(alloc_magic[0], kAllocBegMagic); // Clear the magic value, as allocator internals may overwrite the // contents of deallocated chunk, confusing GetAsanChunk lookup. alloc_magic[0] = 0; CHECK_EQ(alloc_magic[1], reinterpret_cast(m)); } // Statistics. AsanStats &thread_stats = GetCurrentThreadStats(); thread_stats.real_frees++; thread_stats.really_freed += m->UsedSize(); get_allocator().Deallocate(cache_, p); } void *Allocate(uptr size) { return get_allocator().Allocate(cache_, size, 1, false); } void Deallocate(void *p) { get_allocator().Deallocate(cache_, p); } AllocatorCache *cache_; }; typedef Quarantine AsanQuarantine; typedef AsanQuarantine::Cache QuarantineCache; void AsanMapUnmapCallback::OnMap(uptr p, uptr size) const { PoisonShadow(p, size, kAsanHeapLeftRedzoneMagic); // Statistics. AsanStats &thread_stats = GetCurrentThreadStats(); thread_stats.mmaps++; thread_stats.mmaped += size; } void AsanMapUnmapCallback::OnUnmap(uptr p, uptr size) const { PoisonShadow(p, size, 0); // We are about to unmap a chunk of user memory. // Mark the corresponding shadow memory as not needed. FlushUnneededASanShadowMemory(p, size); // Statistics. AsanStats &thread_stats = GetCurrentThreadStats(); thread_stats.munmaps++; thread_stats.munmaped += size; } // We can not use THREADLOCAL because it is not supported on some of the // platforms we care about (OSX 10.6, Android). // static THREADLOCAL AllocatorCache cache; AllocatorCache *GetAllocatorCache(AsanThreadLocalMallocStorage *ms) { CHECK(ms); return &ms->allocator_cache; } QuarantineCache *GetQuarantineCache(AsanThreadLocalMallocStorage *ms) { CHECK(ms); CHECK_LE(sizeof(QuarantineCache), sizeof(ms->quarantine_cache)); return reinterpret_cast(ms->quarantine_cache); } void AllocatorOptions::SetFrom(const Flags *f, const CommonFlags *cf) { quarantine_size_mb = f->quarantine_size_mb; + thread_local_quarantine_size_kb = f->thread_local_quarantine_size_kb; min_redzone = f->redzone; max_redzone = f->max_redzone; may_return_null = cf->allocator_may_return_null; alloc_dealloc_mismatch = f->alloc_dealloc_mismatch; + release_to_os_interval_ms = cf->allocator_release_to_os_interval_ms; } void AllocatorOptions::CopyTo(Flags *f, CommonFlags *cf) { f->quarantine_size_mb = quarantine_size_mb; + f->thread_local_quarantine_size_kb = thread_local_quarantine_size_kb; f->redzone = min_redzone; f->max_redzone = max_redzone; cf->allocator_may_return_null = may_return_null; f->alloc_dealloc_mismatch = alloc_dealloc_mismatch; + cf->allocator_release_to_os_interval_ms = release_to_os_interval_ms; } struct Allocator { static const uptr kMaxAllowedMallocSize = FIRST_32_SECOND_64(3UL << 30, 1ULL << 40); - static const uptr kMaxThreadLocalQuarantine = - FIRST_32_SECOND_64(1 << 18, 1 << 20); AsanAllocator allocator; AsanQuarantine quarantine; StaticSpinMutex fallback_mutex; AllocatorCache fallback_allocator_cache; QuarantineCache fallback_quarantine_cache; // ------------------- Options -------------------------- atomic_uint16_t min_redzone; atomic_uint16_t max_redzone; atomic_uint8_t alloc_dealloc_mismatch; // ------------------- Initialization ------------------------ explicit Allocator(LinkerInitialized) : quarantine(LINKER_INITIALIZED), fallback_quarantine_cache(LINKER_INITIALIZED) {} void CheckOptions(const AllocatorOptions &options) const { CHECK_GE(options.min_redzone, 16); CHECK_GE(options.max_redzone, options.min_redzone); CHECK_LE(options.max_redzone, 2048); CHECK(IsPowerOfTwo(options.min_redzone)); CHECK(IsPowerOfTwo(options.max_redzone)); } void SharedInitCode(const AllocatorOptions &options) { CheckOptions(options); quarantine.Init((uptr)options.quarantine_size_mb << 20, - kMaxThreadLocalQuarantine); + (uptr)options.thread_local_quarantine_size_kb << 10); atomic_store(&alloc_dealloc_mismatch, options.alloc_dealloc_mismatch, memory_order_release); atomic_store(&min_redzone, options.min_redzone, memory_order_release); atomic_store(&max_redzone, options.max_redzone, memory_order_release); } void Initialize(const AllocatorOptions &options) { - allocator.Init(options.may_return_null); + allocator.Init(options.may_return_null, options.release_to_os_interval_ms); SharedInitCode(options); } + void RePoisonChunk(uptr chunk) { + // This could a user-facing chunk (with redzones), or some internal + // housekeeping chunk, like TransferBatch. Start by assuming the former. + AsanChunk *ac = GetAsanChunk((void *)chunk); + uptr allocated_size = allocator.GetActuallyAllocatedSize((void *)ac); + uptr beg = ac->Beg(); + uptr end = ac->Beg() + ac->UsedSize(true); + uptr chunk_end = chunk + allocated_size; + if (chunk < beg && beg < end && end <= chunk_end) { + // Looks like a valid AsanChunk. Or maybe not. Be conservative and only + // poison the redzones. + PoisonShadow(chunk, beg - chunk, kAsanHeapLeftRedzoneMagic); + uptr end_aligned_down = RoundDownTo(end, SHADOW_GRANULARITY); + FastPoisonShadowPartialRightRedzone( + end_aligned_down, end - end_aligned_down, + chunk_end - end_aligned_down, kAsanHeapLeftRedzoneMagic); + } else { + // This can not be an AsanChunk. Poison everything. It may be reused as + // AsanChunk later. + PoisonShadow(chunk, allocated_size, kAsanHeapLeftRedzoneMagic); + } + } + void ReInitialize(const AllocatorOptions &options) { allocator.SetMayReturnNull(options.may_return_null); + allocator.SetReleaseToOSIntervalMs(options.release_to_os_interval_ms); SharedInitCode(options); + + // Poison all existing allocation's redzones. + if (CanPoisonMemory()) { + allocator.ForceLock(); + allocator.ForEachChunk( + [](uptr chunk, void *alloc) { + ((Allocator *)alloc)->RePoisonChunk(chunk); + }, + this); + allocator.ForceUnlock(); + } } void GetOptions(AllocatorOptions *options) const { options->quarantine_size_mb = quarantine.GetSize() >> 20; + options->thread_local_quarantine_size_kb = quarantine.GetCacheSize() >> 10; options->min_redzone = atomic_load(&min_redzone, memory_order_acquire); options->max_redzone = atomic_load(&max_redzone, memory_order_acquire); options->may_return_null = allocator.MayReturnNull(); options->alloc_dealloc_mismatch = atomic_load(&alloc_dealloc_mismatch, memory_order_acquire); + options->release_to_os_interval_ms = allocator.ReleaseToOSIntervalMs(); } // -------------------- Helper methods. ------------------------- uptr ComputeRZLog(uptr user_requested_size) { u32 rz_log = user_requested_size <= 64 - 16 ? 0 : user_requested_size <= 128 - 32 ? 1 : user_requested_size <= 512 - 64 ? 2 : user_requested_size <= 4096 - 128 ? 3 : user_requested_size <= (1 << 14) - 256 ? 4 : user_requested_size <= (1 << 15) - 512 ? 5 : user_requested_size <= (1 << 16) - 1024 ? 6 : 7; u32 min_rz = atomic_load(&min_redzone, memory_order_acquire); u32 max_rz = atomic_load(&max_redzone, memory_order_acquire); return Min(Max(rz_log, RZSize2Log(min_rz)), RZSize2Log(max_rz)); } // We have an address between two chunks, and we want to report just one. AsanChunk *ChooseChunk(uptr addr, AsanChunk *left_chunk, AsanChunk *right_chunk) { // Prefer an allocated chunk over freed chunk and freed chunk // over available chunk. if (left_chunk->chunk_state != right_chunk->chunk_state) { if (left_chunk->chunk_state == CHUNK_ALLOCATED) return left_chunk; if (right_chunk->chunk_state == CHUNK_ALLOCATED) return right_chunk; if (left_chunk->chunk_state == CHUNK_QUARANTINE) return left_chunk; if (right_chunk->chunk_state == CHUNK_QUARANTINE) return right_chunk; } // Same chunk_state: choose based on offset. sptr l_offset = 0, r_offset = 0; CHECK(AsanChunkView(left_chunk).AddrIsAtRight(addr, 1, &l_offset)); CHECK(AsanChunkView(right_chunk).AddrIsAtLeft(addr, 1, &r_offset)); if (l_offset < r_offset) return left_chunk; return right_chunk; } // -------------------- Allocation/Deallocation routines --------------- void *Allocate(uptr size, uptr alignment, BufferedStackTrace *stack, AllocType alloc_type, bool can_fill) { if (UNLIKELY(!asan_inited)) AsanInitFromRtl(); Flags &fl = *flags(); CHECK(stack); const uptr min_alignment = SHADOW_GRANULARITY; if (alignment < min_alignment) alignment = min_alignment; if (size == 0) { // We'd be happy to avoid allocating memory for zero-size requests, but // some programs/tests depend on this behavior and assume that malloc // would not return NULL even for zero-size allocations. Moreover, it // looks like operator new should never return NULL, and results of // consecutive "new" calls must be different even if the allocated size // is zero. size = 1; } CHECK(IsPowerOfTwo(alignment)); uptr rz_log = ComputeRZLog(size); uptr rz_size = RZLog2Size(rz_log); uptr rounded_size = RoundUpTo(Max(size, kChunkHeader2Size), alignment); uptr needed_size = rounded_size + rz_size; if (alignment > min_alignment) needed_size += alignment; bool using_primary_allocator = true; // If we are allocating from the secondary allocator, there will be no // automatic right redzone, so add the right redzone manually. if (!PrimaryAllocator::CanAllocate(needed_size, alignment)) { needed_size += rz_size; using_primary_allocator = false; } CHECK(IsAligned(needed_size, min_alignment)); if (size > kMaxAllowedMallocSize || needed_size > kMaxAllowedMallocSize) { Report("WARNING: AddressSanitizer failed to allocate 0x%zx bytes\n", (void*)size); - return allocator.ReturnNullOrDie(); + return allocator.ReturnNullOrDieOnBadRequest(); } AsanThread *t = GetCurrentThread(); void *allocated; bool check_rss_limit = true; if (t) { AllocatorCache *cache = GetAllocatorCache(&t->malloc_storage()); allocated = allocator.Allocate(cache, needed_size, 8, false, check_rss_limit); } else { SpinMutexLock l(&fallback_mutex); AllocatorCache *cache = &fallback_allocator_cache; allocated = allocator.Allocate(cache, needed_size, 8, false, check_rss_limit); } - if (!allocated) - return allocator.ReturnNullOrDie(); + if (!allocated) return allocator.ReturnNullOrDieOnOOM(); if (*(u8 *)MEM_TO_SHADOW((uptr)allocated) == 0 && CanPoisonMemory()) { // Heap poisoning is enabled, but the allocator provides an unpoisoned // chunk. This is possible if CanPoisonMemory() was false for some // time, for example, due to flags()->start_disabled. // Anyway, poison the block before using it for anything else. uptr allocated_size = allocator.GetActuallyAllocatedSize(allocated); PoisonShadow((uptr)allocated, allocated_size, kAsanHeapLeftRedzoneMagic); } uptr alloc_beg = reinterpret_cast(allocated); uptr alloc_end = alloc_beg + needed_size; uptr beg_plus_redzone = alloc_beg + rz_size; uptr user_beg = beg_plus_redzone; if (!IsAligned(user_beg, alignment)) user_beg = RoundUpTo(user_beg, alignment); uptr user_end = user_beg + size; CHECK_LE(user_end, alloc_end); uptr chunk_beg = user_beg - kChunkHeaderSize; AsanChunk *m = reinterpret_cast(chunk_beg); m->alloc_type = alloc_type; m->rz_log = rz_log; u32 alloc_tid = t ? t->tid() : 0; m->alloc_tid = alloc_tid; CHECK_EQ(alloc_tid, m->alloc_tid); // Does alloc_tid fit into the bitfield? m->free_tid = kInvalidTid; m->from_memalign = user_beg != beg_plus_redzone; if (alloc_beg != chunk_beg) { CHECK_LE(alloc_beg+ 2 * sizeof(uptr), chunk_beg); reinterpret_cast(alloc_beg)[0] = kAllocBegMagic; reinterpret_cast(alloc_beg)[1] = chunk_beg; } if (using_primary_allocator) { CHECK(size); m->user_requested_size = size; CHECK(allocator.FromPrimary(allocated)); } else { CHECK(!allocator.FromPrimary(allocated)); m->user_requested_size = SizeClassMap::kMaxSize; uptr *meta = reinterpret_cast(allocator.GetMetaData(allocated)); meta[0] = size; meta[1] = chunk_beg; } m->alloc_context_id = StackDepotPut(*stack); uptr size_rounded_down_to_granularity = RoundDownTo(size, SHADOW_GRANULARITY); // Unpoison the bulk of the memory region. if (size_rounded_down_to_granularity) PoisonShadow(user_beg, size_rounded_down_to_granularity, 0); // Deal with the end of the region if size is not aligned to granularity. if (size != size_rounded_down_to_granularity && CanPoisonMemory()) { u8 *shadow = (u8 *)MemToShadow(user_beg + size_rounded_down_to_granularity); *shadow = fl.poison_partial ? (size & (SHADOW_GRANULARITY - 1)) : 0; } AsanStats &thread_stats = GetCurrentThreadStats(); thread_stats.mallocs++; thread_stats.malloced += size; thread_stats.malloced_redzones += needed_size - size; if (needed_size > SizeClassMap::kMaxSize) thread_stats.malloc_large++; else thread_stats.malloced_by_size[SizeClassMap::ClassID(needed_size)]++; void *res = reinterpret_cast(user_beg); if (can_fill && fl.max_malloc_fill_size) { uptr fill_size = Min(size, (uptr)fl.max_malloc_fill_size); REAL(memset)(res, fl.malloc_fill_byte, fill_size); } #if CAN_SANITIZE_LEAKS m->lsan_tag = __lsan::DisabledInThisThread() ? __lsan::kIgnored : __lsan::kDirectlyLeaked; #endif // Must be the last mutation of metadata in this function. atomic_store((atomic_uint8_t *)m, CHUNK_ALLOCATED, memory_order_release); ASAN_MALLOC_HOOK(res, size); return res; } // Set quarantine flag if chunk is allocated, issue ASan error report on // available and quarantined chunks. Return true on success, false otherwise. bool AtomicallySetQuarantineFlagIfAllocated(AsanChunk *m, void *ptr, BufferedStackTrace *stack) { u8 old_chunk_state = CHUNK_ALLOCATED; // Flip the chunk_state atomically to avoid race on double-free. if (!atomic_compare_exchange_strong((atomic_uint8_t *)m, &old_chunk_state, CHUNK_QUARANTINE, memory_order_acquire)) { ReportInvalidFree(ptr, old_chunk_state, stack); // It's not safe to push a chunk in quarantine on invalid free. return false; } CHECK_EQ(CHUNK_ALLOCATED, old_chunk_state); return true; } // Expects the chunk to already be marked as quarantined by using // AtomicallySetQuarantineFlagIfAllocated. void QuarantineChunk(AsanChunk *m, void *ptr, BufferedStackTrace *stack, AllocType alloc_type) { CHECK_EQ(m->chunk_state, CHUNK_QUARANTINE); CHECK_GE(m->alloc_tid, 0); if (SANITIZER_WORDSIZE == 64) // On 32-bits this resides in user area. CHECK_EQ(m->free_tid, kInvalidTid); AsanThread *t = GetCurrentThread(); m->free_tid = t ? t->tid() : 0; m->free_context_id = StackDepotPut(*stack); // Poison the region. PoisonShadow(m->Beg(), RoundUpTo(m->UsedSize(), SHADOW_GRANULARITY), kAsanHeapFreeMagic); AsanStats &thread_stats = GetCurrentThreadStats(); thread_stats.frees++; thread_stats.freed += m->UsedSize(); // Push into quarantine. if (t) { AsanThreadLocalMallocStorage *ms = &t->malloc_storage(); AllocatorCache *ac = GetAllocatorCache(ms); quarantine.Put(GetQuarantineCache(ms), QuarantineCallback(ac), m, m->UsedSize()); } else { SpinMutexLock l(&fallback_mutex); AllocatorCache *ac = &fallback_allocator_cache; quarantine.Put(&fallback_quarantine_cache, QuarantineCallback(ac), m, m->UsedSize()); } } void Deallocate(void *ptr, uptr delete_size, BufferedStackTrace *stack, AllocType alloc_type) { uptr p = reinterpret_cast(ptr); if (p == 0) return; uptr chunk_beg = p - kChunkHeaderSize; AsanChunk *m = reinterpret_cast(chunk_beg); ASAN_FREE_HOOK(ptr); // Must mark the chunk as quarantined before any changes to its metadata. // Do not quarantine given chunk if we failed to set CHUNK_QUARANTINE flag. if (!AtomicallySetQuarantineFlagIfAllocated(m, ptr, stack)) return; if (m->alloc_type != alloc_type) { if (atomic_load(&alloc_dealloc_mismatch, memory_order_acquire)) { ReportAllocTypeMismatch((uptr)ptr, stack, (AllocType)m->alloc_type, (AllocType)alloc_type); } } if (delete_size && flags()->new_delete_type_mismatch && delete_size != m->UsedSize()) { - ReportNewDeleteSizeMismatch(p, m->UsedSize(), delete_size, stack); + ReportNewDeleteSizeMismatch(p, delete_size, stack); } QuarantineChunk(m, ptr, stack, alloc_type); } void *Reallocate(void *old_ptr, uptr new_size, BufferedStackTrace *stack) { CHECK(old_ptr && new_size); uptr p = reinterpret_cast(old_ptr); uptr chunk_beg = p - kChunkHeaderSize; AsanChunk *m = reinterpret_cast(chunk_beg); AsanStats &thread_stats = GetCurrentThreadStats(); thread_stats.reallocs++; thread_stats.realloced += new_size; void *new_ptr = Allocate(new_size, 8, stack, FROM_MALLOC, true); if (new_ptr) { u8 chunk_state = m->chunk_state; if (chunk_state != CHUNK_ALLOCATED) ReportInvalidFree(old_ptr, chunk_state, stack); CHECK_NE(REAL(memcpy), nullptr); uptr memcpy_size = Min(new_size, m->UsedSize()); // If realloc() races with free(), we may start copying freed memory. // However, we will report racy double-free later anyway. REAL(memcpy)(new_ptr, old_ptr, memcpy_size); Deallocate(old_ptr, 0, stack, FROM_MALLOC); } return new_ptr; } void *Calloc(uptr nmemb, uptr size, BufferedStackTrace *stack) { if (CallocShouldReturnNullDueToOverflow(size, nmemb)) - return allocator.ReturnNullOrDie(); + return allocator.ReturnNullOrDieOnBadRequest(); void *ptr = Allocate(nmemb * size, 8, stack, FROM_MALLOC, false); // If the memory comes from the secondary allocator no need to clear it // as it comes directly from mmap. if (ptr && allocator.FromPrimary(ptr)) REAL(memset)(ptr, 0, nmemb * size); return ptr; } void ReportInvalidFree(void *ptr, u8 chunk_state, BufferedStackTrace *stack) { if (chunk_state == CHUNK_QUARANTINE) ReportDoubleFree((uptr)ptr, stack); else ReportFreeNotMalloced((uptr)ptr, stack); } void CommitBack(AsanThreadLocalMallocStorage *ms) { AllocatorCache *ac = GetAllocatorCache(ms); quarantine.Drain(GetQuarantineCache(ms), QuarantineCallback(ac)); allocator.SwallowCache(ac); } // -------------------------- Chunk lookup ---------------------- // Assumes alloc_beg == allocator.GetBlockBegin(alloc_beg). AsanChunk *GetAsanChunk(void *alloc_beg) { if (!alloc_beg) return nullptr; if (!allocator.FromPrimary(alloc_beg)) { uptr *meta = reinterpret_cast(allocator.GetMetaData(alloc_beg)); AsanChunk *m = reinterpret_cast(meta[1]); return m; } uptr *alloc_magic = reinterpret_cast(alloc_beg); if (alloc_magic[0] == kAllocBegMagic) return reinterpret_cast(alloc_magic[1]); return reinterpret_cast(alloc_beg); } AsanChunk *GetAsanChunkByAddr(uptr p) { void *alloc_beg = allocator.GetBlockBegin(reinterpret_cast(p)); return GetAsanChunk(alloc_beg); } // Allocator must be locked when this function is called. AsanChunk *GetAsanChunkByAddrFastLocked(uptr p) { void *alloc_beg = allocator.GetBlockBeginFastLocked(reinterpret_cast(p)); return GetAsanChunk(alloc_beg); } uptr AllocationSize(uptr p) { AsanChunk *m = GetAsanChunkByAddr(p); if (!m) return 0; if (m->chunk_state != CHUNK_ALLOCATED) return 0; if (m->Beg() != p) return 0; return m->UsedSize(); } AsanChunkView FindHeapChunkByAddress(uptr addr) { AsanChunk *m1 = GetAsanChunkByAddr(addr); if (!m1) return AsanChunkView(m1); sptr offset = 0; if (AsanChunkView(m1).AddrIsAtLeft(addr, 1, &offset)) { // The address is in the chunk's left redzone, so maybe it is actually // a right buffer overflow from the other chunk to the left. // Search a bit to the left to see if there is another chunk. AsanChunk *m2 = nullptr; for (uptr l = 1; l < GetPageSizeCached(); l++) { m2 = GetAsanChunkByAddr(addr - l); if (m2 == m1) continue; // Still the same chunk. break; } if (m2 && AsanChunkView(m2).AddrIsAtRight(addr, 1, &offset)) m1 = ChooseChunk(addr, m2, m1); } return AsanChunkView(m1); } void PrintStats() { allocator.PrintStats(); + quarantine.PrintStats(); } void ForceLock() { allocator.ForceLock(); fallback_mutex.Lock(); } void ForceUnlock() { fallback_mutex.Unlock(); allocator.ForceUnlock(); } }; static Allocator instance(LINKER_INITIALIZED); static AsanAllocator &get_allocator() { return instance.allocator; } -bool AsanChunkView::IsValid() { +bool AsanChunkView::IsValid() const { return chunk_ && chunk_->chunk_state != CHUNK_AVAILABLE; } -bool AsanChunkView::IsAllocated() { +bool AsanChunkView::IsAllocated() const { return chunk_ && chunk_->chunk_state == CHUNK_ALLOCATED; } -uptr AsanChunkView::Beg() { return chunk_->Beg(); } -uptr AsanChunkView::End() { return Beg() + UsedSize(); } -uptr AsanChunkView::UsedSize() { return chunk_->UsedSize(); } -uptr AsanChunkView::AllocTid() { return chunk_->alloc_tid; } -uptr AsanChunkView::FreeTid() { return chunk_->free_tid; } +bool AsanChunkView::IsQuarantined() const { + return chunk_ && chunk_->chunk_state == CHUNK_QUARANTINE; +} +uptr AsanChunkView::Beg() const { return chunk_->Beg(); } +uptr AsanChunkView::End() const { return Beg() + UsedSize(); } +uptr AsanChunkView::UsedSize() const { return chunk_->UsedSize(); } +uptr AsanChunkView::AllocTid() const { return chunk_->alloc_tid; } +uptr AsanChunkView::FreeTid() const { return chunk_->free_tid; } +AllocType AsanChunkView::GetAllocType() const { + return (AllocType)chunk_->alloc_type; +} static StackTrace GetStackTraceFromId(u32 id) { CHECK(id); StackTrace res = StackDepotGet(id); CHECK(res.trace); return res; } -u32 AsanChunkView::GetAllocStackId() { return chunk_->alloc_context_id; } -u32 AsanChunkView::GetFreeStackId() { return chunk_->free_context_id; } +u32 AsanChunkView::GetAllocStackId() const { return chunk_->alloc_context_id; } +u32 AsanChunkView::GetFreeStackId() const { return chunk_->free_context_id; } -StackTrace AsanChunkView::GetAllocStack() { +StackTrace AsanChunkView::GetAllocStack() const { return GetStackTraceFromId(GetAllocStackId()); } -StackTrace AsanChunkView::GetFreeStack() { +StackTrace AsanChunkView::GetFreeStack() const { return GetStackTraceFromId(GetFreeStackId()); } void InitializeAllocator(const AllocatorOptions &options) { instance.Initialize(options); } void ReInitializeAllocator(const AllocatorOptions &options) { instance.ReInitialize(options); } void GetAllocatorOptions(AllocatorOptions *options) { instance.GetOptions(options); } AsanChunkView FindHeapChunkByAddress(uptr addr) { return instance.FindHeapChunkByAddress(addr); +} +AsanChunkView FindHeapChunkByAllocBeg(uptr addr) { + return AsanChunkView(instance.GetAsanChunk(reinterpret_cast(addr))); } void AsanThreadLocalMallocStorage::CommitBack() { instance.CommitBack(this); } void PrintInternalAllocatorStats() { instance.PrintStats(); } void *asan_memalign(uptr alignment, uptr size, BufferedStackTrace *stack, AllocType alloc_type) { return instance.Allocate(size, alignment, stack, alloc_type, true); } void asan_free(void *ptr, BufferedStackTrace *stack, AllocType alloc_type) { instance.Deallocate(ptr, 0, stack, alloc_type); } void asan_sized_free(void *ptr, uptr size, BufferedStackTrace *stack, AllocType alloc_type) { instance.Deallocate(ptr, size, stack, alloc_type); } void *asan_malloc(uptr size, BufferedStackTrace *stack) { return instance.Allocate(size, 8, stack, FROM_MALLOC, true); } void *asan_calloc(uptr nmemb, uptr size, BufferedStackTrace *stack) { return instance.Calloc(nmemb, size, stack); } void *asan_realloc(void *p, uptr size, BufferedStackTrace *stack) { if (!p) return instance.Allocate(size, 8, stack, FROM_MALLOC, true); if (size == 0) { instance.Deallocate(p, 0, stack, FROM_MALLOC); return nullptr; } return instance.Reallocate(p, size, stack); } void *asan_valloc(uptr size, BufferedStackTrace *stack) { return instance.Allocate(size, GetPageSizeCached(), stack, FROM_MALLOC, true); } void *asan_pvalloc(uptr size, BufferedStackTrace *stack) { uptr PageSize = GetPageSizeCached(); size = RoundUpTo(size, PageSize); if (size == 0) { // pvalloc(0) should allocate one page. size = PageSize; } return instance.Allocate(size, PageSize, stack, FROM_MALLOC, true); } int asan_posix_memalign(void **memptr, uptr alignment, uptr size, BufferedStackTrace *stack) { void *ptr = instance.Allocate(size, alignment, stack, FROM_MALLOC, true); CHECK(IsAligned((uptr)ptr, alignment)); *memptr = ptr; return 0; } uptr asan_malloc_usable_size(const void *ptr, uptr pc, uptr bp) { if (!ptr) return 0; uptr usable_size = instance.AllocationSize(reinterpret_cast(ptr)); if (flags()->check_malloc_usable_size && (usable_size == 0)) { GET_STACK_TRACE_FATAL(pc, bp); ReportMallocUsableSizeNotOwned((uptr)ptr, &stack); } return usable_size; } uptr asan_mz_size(const void *ptr) { return instance.AllocationSize(reinterpret_cast(ptr)); } void asan_mz_force_lock() { instance.ForceLock(); } void asan_mz_force_unlock() { instance.ForceUnlock(); } void AsanSoftRssLimitExceededCallback(bool exceeded) { instance.allocator.SetRssLimitIsExceeded(exceeded); } } // namespace __asan // --- Implementation of LSan-specific functions --- {{{1 namespace __lsan { void LockAllocator() { __asan::get_allocator().ForceLock(); } void UnlockAllocator() { __asan::get_allocator().ForceUnlock(); } void GetAllocatorGlobalRange(uptr *begin, uptr *end) { *begin = (uptr)&__asan::get_allocator(); *end = *begin + sizeof(__asan::get_allocator()); } uptr PointsIntoChunk(void* p) { uptr addr = reinterpret_cast(p); __asan::AsanChunk *m = __asan::instance.GetAsanChunkByAddrFastLocked(addr); if (!m) return 0; uptr chunk = m->Beg(); if (m->chunk_state != __asan::CHUNK_ALLOCATED) return 0; if (m->AddrIsInside(addr, /*locked_version=*/true)) return chunk; if (IsSpecialCaseOfOperatorNew0(chunk, m->UsedSize(/*locked_version*/ true), addr)) return chunk; return 0; } uptr GetUserBegin(uptr chunk) { __asan::AsanChunk *m = __asan::instance.GetAsanChunkByAddrFastLocked(chunk); CHECK(m); return m->Beg(); } LsanMetadata::LsanMetadata(uptr chunk) { metadata_ = reinterpret_cast(chunk - __asan::kChunkHeaderSize); } bool LsanMetadata::allocated() const { __asan::AsanChunk *m = reinterpret_cast<__asan::AsanChunk *>(metadata_); return m->chunk_state == __asan::CHUNK_ALLOCATED; } ChunkTag LsanMetadata::tag() const { __asan::AsanChunk *m = reinterpret_cast<__asan::AsanChunk *>(metadata_); return static_cast(m->lsan_tag); } void LsanMetadata::set_tag(ChunkTag value) { __asan::AsanChunk *m = reinterpret_cast<__asan::AsanChunk *>(metadata_); m->lsan_tag = value; } uptr LsanMetadata::requested_size() const { __asan::AsanChunk *m = reinterpret_cast<__asan::AsanChunk *>(metadata_); return m->UsedSize(/*locked_version=*/true); } u32 LsanMetadata::stack_trace_id() const { __asan::AsanChunk *m = reinterpret_cast<__asan::AsanChunk *>(metadata_); return m->alloc_context_id; } void ForEachChunk(ForEachChunkCallback callback, void *arg) { __asan::get_allocator().ForEachChunk(callback, arg); } IgnoreObjectResult IgnoreObjectLocked(const void *p) { uptr addr = reinterpret_cast(p); __asan::AsanChunk *m = __asan::instance.GetAsanChunkByAddr(addr); if (!m) return kIgnoreObjectInvalid; if ((m->chunk_state == __asan::CHUNK_ALLOCATED) && m->AddrIsInside(addr)) { if (m->lsan_tag == kIgnored) return kIgnoreObjectAlreadyIgnored; m->lsan_tag = __lsan::kIgnored; return kIgnoreObjectSuccess; } else { return kIgnoreObjectInvalid; } } } // namespace __lsan // ---------------------- Interface ---------------- {{{1 using namespace __asan; // NOLINT // ASan allocator doesn't reserve extra bytes, so normally we would // just return "size". We don't want to expose our redzone sizes, etc here. uptr __sanitizer_get_estimated_allocated_size(uptr size) { return size; } int __sanitizer_get_ownership(const void *p) { uptr ptr = reinterpret_cast(p); return instance.AllocationSize(ptr) > 0; } uptr __sanitizer_get_allocated_size(const void *p) { if (!p) return 0; uptr ptr = reinterpret_cast(p); uptr allocated_size = instance.AllocationSize(ptr); // Die if p is not malloced or if it is already freed. if (allocated_size == 0) { GET_STACK_TRACE_FATAL_HERE; ReportSanitizerGetAllocatedSizeNotOwned(ptr, &stack); } return allocated_size; } #if !SANITIZER_SUPPORTS_WEAK_HOOKS // Provide default (no-op) implementation of malloc hooks. extern "C" { SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE void __sanitizer_malloc_hook(void *ptr, uptr size) { (void)ptr; (void)size; } SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE void __sanitizer_free_hook(void *ptr) { (void)ptr; } } // extern "C" #endif Index: projects/clang400-import/contrib/compiler-rt/lib/asan/asan_allocator.h =================================================================== --- projects/clang400-import/contrib/compiler-rt/lib/asan/asan_allocator.h (revision 311696) +++ projects/clang400-import/contrib/compiler-rt/lib/asan/asan_allocator.h (revision 311697) @@ -1,187 +1,210 @@ //===-- asan_allocator.h ----------------------------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // This file is a part of AddressSanitizer, an address sanity checker. // // ASan-private header for asan_allocator.cc. //===----------------------------------------------------------------------===// #ifndef ASAN_ALLOCATOR_H #define ASAN_ALLOCATOR_H #include "asan_flags.h" #include "asan_internal.h" #include "asan_interceptors.h" #include "sanitizer_common/sanitizer_allocator.h" #include "sanitizer_common/sanitizer_list.h" namespace __asan { enum AllocType { FROM_MALLOC = 1, // Memory block came from malloc, calloc, realloc, etc. FROM_NEW = 2, // Memory block came from operator new. FROM_NEW_BR = 3 // Memory block came from operator new [ ] }; struct AsanChunk; struct AllocatorOptions { u32 quarantine_size_mb; + u32 thread_local_quarantine_size_kb; u16 min_redzone; u16 max_redzone; u8 may_return_null; u8 alloc_dealloc_mismatch; + s32 release_to_os_interval_ms; void SetFrom(const Flags *f, const CommonFlags *cf); void CopyTo(Flags *f, CommonFlags *cf); }; void InitializeAllocator(const AllocatorOptions &options); void ReInitializeAllocator(const AllocatorOptions &options); void GetAllocatorOptions(AllocatorOptions *options); class AsanChunkView { public: explicit AsanChunkView(AsanChunk *chunk) : chunk_(chunk) {} - bool IsValid(); // Checks if AsanChunkView points to a valid allocated - // or quarantined chunk. - bool IsAllocated(); // Checks if the memory is currently allocated. - uptr Beg(); // First byte of user memory. - uptr End(); // Last byte of user memory. - uptr UsedSize(); // Size requested by the user. - uptr AllocTid(); - uptr FreeTid(); + bool IsValid() const; // Checks if AsanChunkView points to a valid + // allocated or quarantined chunk. + bool IsAllocated() const; // Checks if the memory is currently allocated. + bool IsQuarantined() const; // Checks if the memory is currently quarantined. + uptr Beg() const; // First byte of user memory. + uptr End() const; // Last byte of user memory. + uptr UsedSize() const; // Size requested by the user. + uptr AllocTid() const; + uptr FreeTid() const; bool Eq(const AsanChunkView &c) const { return chunk_ == c.chunk_; } - u32 GetAllocStackId(); - u32 GetFreeStackId(); - StackTrace GetAllocStack(); - StackTrace GetFreeStack(); - bool AddrIsInside(uptr addr, uptr access_size, sptr *offset) { + u32 GetAllocStackId() const; + u32 GetFreeStackId() const; + StackTrace GetAllocStack() const; + StackTrace GetFreeStack() const; + AllocType GetAllocType() const; + bool AddrIsInside(uptr addr, uptr access_size, sptr *offset) const { if (addr >= Beg() && (addr + access_size) <= End()) { *offset = addr - Beg(); return true; } return false; } - bool AddrIsAtLeft(uptr addr, uptr access_size, sptr *offset) { + bool AddrIsAtLeft(uptr addr, uptr access_size, sptr *offset) const { (void)access_size; if (addr < Beg()) { *offset = Beg() - addr; return true; } return false; } - bool AddrIsAtRight(uptr addr, uptr access_size, sptr *offset) { + bool AddrIsAtRight(uptr addr, uptr access_size, sptr *offset) const { if (addr + access_size > End()) { *offset = addr - End(); return true; } return false; } private: AsanChunk *const chunk_; }; AsanChunkView FindHeapChunkByAddress(uptr address); +AsanChunkView FindHeapChunkByAllocBeg(uptr address); // List of AsanChunks with total size. class AsanChunkFifoList: public IntrusiveList { public: explicit AsanChunkFifoList(LinkerInitialized) { } AsanChunkFifoList() { clear(); } void Push(AsanChunk *n); void PushList(AsanChunkFifoList *q); AsanChunk *Pop(); uptr size() { return size_; } void clear() { IntrusiveList::clear(); size_ = 0; } private: uptr size_; }; struct AsanMapUnmapCallback { void OnMap(uptr p, uptr size) const; void OnUnmap(uptr p, uptr size) const; }; #if SANITIZER_CAN_USE_ALLOCATOR64 # if defined(__powerpc64__) const uptr kAllocatorSpace = 0xa0000000000ULL; const uptr kAllocatorSize = 0x20000000000ULL; // 2T. +typedef DefaultSizeClassMap SizeClassMap; +# elif defined(__aarch64__) && SANITIZER_ANDROID +const uptr kAllocatorSpace = 0x3000000000ULL; +const uptr kAllocatorSize = 0x2000000000ULL; // 128G. +typedef VeryCompactSizeClassMap SizeClassMap; # elif defined(__aarch64__) -// AArch64/SANITIZIER_CAN_USER_ALLOCATOR64 is only for 42-bit VMA +// AArch64/SANITIZER_CAN_USER_ALLOCATOR64 is only for 42-bit VMA // so no need to different values for different VMA. const uptr kAllocatorSpace = 0x10000000000ULL; const uptr kAllocatorSize = 0x10000000000ULL; // 3T. +typedef DefaultSizeClassMap SizeClassMap; +# elif SANITIZER_WINDOWS +const uptr kAllocatorSpace = ~(uptr)0; +const uptr kAllocatorSize = 0x8000000000ULL; // 500G +typedef DefaultSizeClassMap SizeClassMap; # else const uptr kAllocatorSpace = 0x600000000000ULL; const uptr kAllocatorSize = 0x40000000000ULL; // 4T. -# endif typedef DefaultSizeClassMap SizeClassMap; -typedef SizeClassAllocator64 PrimaryAllocator; +# endif +struct AP64 { // Allocator64 parameters. Deliberately using a short name. + static const uptr kSpaceBeg = kAllocatorSpace; + static const uptr kSpaceSize = kAllocatorSize; + static const uptr kMetadataSize = 0; + typedef __asan::SizeClassMap SizeClassMap; + typedef AsanMapUnmapCallback MapUnmapCallback; + static const uptr kFlags = 0; +}; + +typedef SizeClassAllocator64 PrimaryAllocator; #else // Fallback to SizeClassAllocator32. static const uptr kRegionSizeLog = 20; static const uptr kNumRegions = SANITIZER_MMAP_RANGE_SIZE >> kRegionSizeLog; # if SANITIZER_WORDSIZE == 32 typedef FlatByteMap ByteMap; # elif SANITIZER_WORDSIZE == 64 typedef TwoLevelByteMap<(kNumRegions >> 12), 1 << 12> ByteMap; # endif typedef CompactSizeClassMap SizeClassMap; typedef SizeClassAllocator32<0, SANITIZER_MMAP_RANGE_SIZE, 16, SizeClassMap, kRegionSizeLog, ByteMap, AsanMapUnmapCallback> PrimaryAllocator; #endif // SANITIZER_CAN_USE_ALLOCATOR64 static const uptr kNumberOfSizeClasses = SizeClassMap::kNumClasses; typedef SizeClassAllocatorLocalCache AllocatorCache; typedef LargeMmapAllocator SecondaryAllocator; typedef CombinedAllocator AsanAllocator; struct AsanThreadLocalMallocStorage { uptr quarantine_cache[16]; AllocatorCache allocator_cache; void CommitBack(); private: // These objects are allocated via mmap() and are zero-initialized. AsanThreadLocalMallocStorage() {} }; void *asan_memalign(uptr alignment, uptr size, BufferedStackTrace *stack, AllocType alloc_type); void asan_free(void *ptr, BufferedStackTrace *stack, AllocType alloc_type); void asan_sized_free(void *ptr, uptr size, BufferedStackTrace *stack, AllocType alloc_type); void *asan_malloc(uptr size, BufferedStackTrace *stack); void *asan_calloc(uptr nmemb, uptr size, BufferedStackTrace *stack); void *asan_realloc(void *p, uptr size, BufferedStackTrace *stack); void *asan_valloc(uptr size, BufferedStackTrace *stack); void *asan_pvalloc(uptr size, BufferedStackTrace *stack); int asan_posix_memalign(void **memptr, uptr alignment, uptr size, BufferedStackTrace *stack); uptr asan_malloc_usable_size(const void *ptr, uptr pc, uptr bp); uptr asan_mz_size(const void *ptr); void asan_mz_force_lock(); void asan_mz_force_unlock(); void PrintInternalAllocatorStats(); void AsanSoftRssLimitExceededCallback(bool exceeded); } // namespace __asan #endif // ASAN_ALLOCATOR_H Index: projects/clang400-import/contrib/compiler-rt/lib/asan/asan_debugging.cc =================================================================== --- projects/clang400-import/contrib/compiler-rt/lib/asan/asan_debugging.cc (revision 311696) +++ projects/clang400-import/contrib/compiler-rt/lib/asan/asan_debugging.cc (revision 311697) @@ -1,141 +1,146 @@ //===-- asan_debugging.cc -------------------------------------------------===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // This file is a part of AddressSanitizer, an address sanity checker. // // This file contains various functions that are generally useful to call when // using a debugger (LLDB, GDB). //===----------------------------------------------------------------------===// #include "asan_allocator.h" +#include "asan_descriptions.h" #include "asan_flags.h" #include "asan_internal.h" #include "asan_mapping.h" #include "asan_report.h" #include "asan_thread.h" -namespace __asan { +namespace { +using namespace __asan; -void GetInfoForStackVar(uptr addr, AddressDescription *descr, AsanThread *t) { - descr->name[0] = 0; - descr->region_address = 0; - descr->region_size = 0; - descr->region_kind = "stack"; - - AsanThread::StackFrameAccess access; - if (!t->GetStackFrameAccessByAddr(addr, &access)) - return; +static void FindInfoForStackVar(uptr addr, const char *frame_descr, uptr offset, + char *name, uptr name_size, + uptr ®ion_address, uptr ®ion_size) { InternalMmapVector vars(16); - if (!ParseFrameDescription(access.frame_descr, &vars)) { + if (!ParseFrameDescription(frame_descr, &vars)) { return; } for (uptr i = 0; i < vars.size(); i++) { - if (access.offset <= vars[i].beg + vars[i].size) { - internal_strncat(descr->name, vars[i].name_pos, - Min(descr->name_size, vars[i].name_len)); - descr->region_address = addr - (access.offset - vars[i].beg); - descr->region_size = vars[i].size; + if (offset <= vars[i].beg + vars[i].size) { + // We use name_len + 1 because strlcpy will guarantee a \0 at the end, so + // if we're limiting the copy due to name_len, we add 1 to ensure we copy + // the whole name and then terminate with '\0'. + internal_strlcpy(name, vars[i].name_pos, + Min(name_size, vars[i].name_len + 1)); + region_address = addr - (offset - vars[i].beg); + region_size = vars[i].size; return; } } } -void GetInfoForHeapAddress(uptr addr, AddressDescription *descr) { - AsanChunkView chunk = FindHeapChunkByAddress(addr); - - descr->name[0] = 0; - descr->region_address = 0; - descr->region_size = 0; - - if (!chunk.IsValid()) { - descr->region_kind = "heap-invalid"; - return; - } - - descr->region_address = chunk.Beg(); - descr->region_size = chunk.UsedSize(); - descr->region_kind = "heap"; -} - -void AsanLocateAddress(uptr addr, AddressDescription *descr) { - if (DescribeAddressIfShadow(addr, descr, /* print */ false)) { - return; - } - if (GetInfoForAddressIfGlobal(addr, descr)) { - return; - } - asanThreadRegistry().Lock(); - AsanThread *thread = FindThreadByStackAddress(addr); - asanThreadRegistry().Unlock(); - if (thread) { - GetInfoForStackVar(addr, descr, thread); - return; - } - GetInfoForHeapAddress(addr, descr); -} - -static uptr AsanGetStack(uptr addr, uptr *trace, u32 size, u32 *thread_id, +uptr AsanGetStack(uptr addr, uptr *trace, u32 size, u32 *thread_id, bool alloc_stack) { AsanChunkView chunk = FindHeapChunkByAddress(addr); if (!chunk.IsValid()) return 0; StackTrace stack(nullptr, 0); if (alloc_stack) { if (chunk.AllocTid() == kInvalidTid) return 0; stack = chunk.GetAllocStack(); if (thread_id) *thread_id = chunk.AllocTid(); } else { if (chunk.FreeTid() == kInvalidTid) return 0; stack = chunk.GetFreeStack(); if (thread_id) *thread_id = chunk.FreeTid(); } if (trace && size) { size = Min(size, Min(stack.size, kStackTraceMax)); for (uptr i = 0; i < size; i++) trace[i] = StackTrace::GetPreviousInstructionPc(stack.trace[i]); return size; } return 0; } -} // namespace __asan +} // namespace -using namespace __asan; - SANITIZER_INTERFACE_ATTRIBUTE const char *__asan_locate_address(uptr addr, char *name, uptr name_size, - uptr *region_address, uptr *region_size) { - AddressDescription descr = { name, name_size, 0, 0, nullptr }; - AsanLocateAddress(addr, &descr); - if (region_address) *region_address = descr.region_address; - if (region_size) *region_size = descr.region_size; - return descr.region_kind; + uptr *region_address_ptr, + uptr *region_size_ptr) { + AddressDescription descr(addr); + uptr region_address = 0; + uptr region_size = 0; + const char *region_kind = nullptr; + if (name && name_size > 0) name[0] = 0; + + if (auto shadow = descr.AsShadow()) { + // region_{address,size} are already 0 + switch (shadow->kind) { + case kShadowKindLow: + region_kind = "low shadow"; + break; + case kShadowKindGap: + region_kind = "shadow gap"; + break; + case kShadowKindHigh: + region_kind = "high shadow"; + break; + } + } else if (auto heap = descr.AsHeap()) { + region_kind = "heap"; + region_address = heap->chunk_access.chunk_begin; + region_size = heap->chunk_access.chunk_size; + } else if (auto stack = descr.AsStack()) { + region_kind = "stack"; + if (!stack->frame_descr) { + // region_{address,size} are already 0 + } else { + FindInfoForStackVar(addr, stack->frame_descr, stack->offset, name, + name_size, region_address, region_size); + } + } else if (auto global = descr.AsGlobal()) { + region_kind = "global"; + auto &g = global->globals[0]; + internal_strlcpy(name, g.name, name_size); + region_address = g.beg; + region_size = g.size; + } else { + // region_{address,size} are already 0 + region_kind = "heap-invalid"; + } + + CHECK(region_kind); + if (region_address_ptr) *region_address_ptr = region_address; + if (region_size_ptr) *region_size_ptr = region_size; + return region_kind; } SANITIZER_INTERFACE_ATTRIBUTE uptr __asan_get_alloc_stack(uptr addr, uptr *trace, uptr size, u32 *thread_id) { return AsanGetStack(addr, trace, size, thread_id, /* alloc_stack */ true); } SANITIZER_INTERFACE_ATTRIBUTE uptr __asan_get_free_stack(uptr addr, uptr *trace, uptr size, u32 *thread_id) { return AsanGetStack(addr, trace, size, thread_id, /* alloc_stack */ false); } SANITIZER_INTERFACE_ATTRIBUTE void __asan_get_shadow_mapping(uptr *shadow_scale, uptr *shadow_offset) { if (shadow_scale) *shadow_scale = SHADOW_SCALE; if (shadow_offset) *shadow_offset = SHADOW_OFFSET; } Index: projects/clang400-import/contrib/compiler-rt/lib/asan/asan_descriptions.cc =================================================================== --- projects/clang400-import/contrib/compiler-rt/lib/asan/asan_descriptions.cc (nonexistent) +++ projects/clang400-import/contrib/compiler-rt/lib/asan/asan_descriptions.cc (revision 311697) @@ -0,0 +1,486 @@ +//===-- asan_descriptions.cc ------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file is a part of AddressSanitizer, an address sanity checker. +// +// ASan functions for getting information about an address and/or printing it. +//===----------------------------------------------------------------------===// + +#include "asan_descriptions.h" +#include "asan_mapping.h" +#include "asan_report.h" +#include "asan_stack.h" +#include "sanitizer_common/sanitizer_stackdepot.h" + +namespace __asan { + +// Return " (thread_name) " or an empty string if the name is empty. +const char *ThreadNameWithParenthesis(AsanThreadContext *t, char buff[], + uptr buff_len) { + const char *name = t->name; + if (name[0] == '\0') return ""; + buff[0] = 0; + internal_strncat(buff, " (", 3); + internal_strncat(buff, name, buff_len - 4); + internal_strncat(buff, ")", 2); + return buff; +} + +const char *ThreadNameWithParenthesis(u32 tid, char buff[], uptr buff_len) { + if (tid == kInvalidTid) return ""; + asanThreadRegistry().CheckLocked(); + AsanThreadContext *t = GetThreadContextByTidLocked(tid); + return ThreadNameWithParenthesis(t, buff, buff_len); +} + +void DescribeThread(AsanThreadContext *context) { + CHECK(context); + asanThreadRegistry().CheckLocked(); + // No need to announce the main thread. + if (context->tid == 0 || context->announced) { + return; + } + context->announced = true; + char tname[128]; + InternalScopedString str(1024); + str.append("Thread T%d%s", context->tid, + ThreadNameWithParenthesis(context->tid, tname, sizeof(tname))); + if (context->parent_tid == kInvalidTid) { + str.append(" created by unknown thread\n"); + Printf("%s", str.data()); + return; + } + str.append( + " created by T%d%s here:\n", context->parent_tid, + ThreadNameWithParenthesis(context->parent_tid, tname, sizeof(tname))); + Printf("%s", str.data()); + StackDepotGet(context->stack_id).Print(); + // Recursively described parent thread if needed. + if (flags()->print_full_thread_history) { + AsanThreadContext *parent_context = + GetThreadContextByTidLocked(context->parent_tid); + DescribeThread(parent_context); + } +} + +// Shadow descriptions +static bool GetShadowKind(uptr addr, ShadowKind *shadow_kind) { + CHECK(!AddrIsInMem(addr)); + if (AddrIsInShadowGap(addr)) { + *shadow_kind = kShadowKindGap; + } else if (AddrIsInHighShadow(addr)) { + *shadow_kind = kShadowKindHigh; + } else if (AddrIsInLowShadow(addr)) { + *shadow_kind = kShadowKindLow; + } else { + CHECK(0 && "Address is not in memory and not in shadow?"); + return false; + } + return true; +} + +bool DescribeAddressIfShadow(uptr addr) { + ShadowAddressDescription descr; + if (!GetShadowAddressInformation(addr, &descr)) return false; + descr.Print(); + return true; +} + +bool GetShadowAddressInformation(uptr addr, ShadowAddressDescription *descr) { + if (AddrIsInMem(addr)) return false; + ShadowKind shadow_kind; + if (!GetShadowKind(addr, &shadow_kind)) return false; + if (shadow_kind != kShadowKindGap) descr->shadow_byte = *(u8 *)addr; + descr->addr = addr; + descr->kind = shadow_kind; + return true; +} + +// Heap descriptions +static void GetAccessToHeapChunkInformation(ChunkAccess *descr, + AsanChunkView chunk, uptr addr, + uptr access_size) { + descr->bad_addr = addr; + if (chunk.AddrIsAtLeft(addr, access_size, &descr->offset)) { + descr->access_type = kAccessTypeLeft; + } else if (chunk.AddrIsAtRight(addr, access_size, &descr->offset)) { + descr->access_type = kAccessTypeRight; + if (descr->offset < 0) { + descr->bad_addr -= descr->offset; + descr->offset = 0; + } + } else if (chunk.AddrIsInside(addr, access_size, &descr->offset)) { + descr->access_type = kAccessTypeInside; + } else { + descr->access_type = kAccessTypeUnknown; + } + descr->chunk_begin = chunk.Beg(); + descr->chunk_size = chunk.UsedSize(); + descr->alloc_type = chunk.GetAllocType(); +} + +static void PrintHeapChunkAccess(uptr addr, const ChunkAccess &descr) { + Decorator d; + InternalScopedString str(4096); + str.append("%s", d.Location()); + switch (descr.access_type) { + case kAccessTypeLeft: + str.append("%p is located %zd bytes to the left of", + (void *)descr.bad_addr, descr.offset); + break; + case kAccessTypeRight: + str.append("%p is located %zd bytes to the right of", + (void *)descr.bad_addr, descr.offset); + break; + case kAccessTypeInside: + str.append("%p is located %zd bytes inside of", (void *)descr.bad_addr, + descr.offset); + break; + case kAccessTypeUnknown: + str.append( + "%p is located somewhere around (this is AddressSanitizer bug!)", + (void *)descr.bad_addr); + } + str.append(" %zu-byte region [%p,%p)\n", descr.chunk_size, + (void *)descr.chunk_begin, + (void *)(descr.chunk_begin + descr.chunk_size)); + str.append("%s", d.EndLocation()); + Printf("%s", str.data()); +} + +bool GetHeapAddressInformation(uptr addr, uptr access_size, + HeapAddressDescription *descr) { + AsanChunkView chunk = FindHeapChunkByAddress(addr); + if (!chunk.IsValid()) { + return false; + } + descr->addr = addr; + GetAccessToHeapChunkInformation(&descr->chunk_access, chunk, addr, + access_size); + CHECK_NE(chunk.AllocTid(), kInvalidTid); + descr->alloc_tid = chunk.AllocTid(); + descr->alloc_stack_id = chunk.GetAllocStackId(); + descr->free_tid = chunk.FreeTid(); + if (descr->free_tid != kInvalidTid) + descr->free_stack_id = chunk.GetFreeStackId(); + return true; +} + +static StackTrace GetStackTraceFromId(u32 id) { + CHECK(id); + StackTrace res = StackDepotGet(id); + CHECK(res.trace); + return res; +} + +bool DescribeAddressIfHeap(uptr addr, uptr access_size) { + HeapAddressDescription descr; + if (!GetHeapAddressInformation(addr, access_size, &descr)) { + Printf( + "AddressSanitizer can not describe address in more detail " + "(wild memory access suspected).\n"); + return false; + } + descr.Print(); + return true; +} + +// Stack descriptions +bool GetStackAddressInformation(uptr addr, uptr access_size, + StackAddressDescription *descr) { + AsanThread *t = FindThreadByStackAddress(addr); + if (!t) return false; + + descr->addr = addr; + descr->tid = t->tid(); + // Try to fetch precise stack frame for this access. + AsanThread::StackFrameAccess access; + if (!t->GetStackFrameAccessByAddr(addr, &access)) { + descr->frame_descr = nullptr; + return true; + } + + descr->offset = access.offset; + descr->access_size = access_size; + descr->frame_pc = access.frame_pc; + descr->frame_descr = access.frame_descr; + +#if SANITIZER_PPC64V1 + // On PowerPC64 ELFv1, the address of a function actually points to a + // three-doubleword data structure with the first field containing + // the address of the function's code. + descr->frame_pc = *reinterpret_cast(descr->frame_pc); +#endif + descr->frame_pc += 16; + + return true; +} + +static void PrintAccessAndVarIntersection(const StackVarDescr &var, uptr addr, + uptr access_size, uptr prev_var_end, + uptr next_var_beg) { + uptr var_end = var.beg + var.size; + uptr addr_end = addr + access_size; + const char *pos_descr = nullptr; + // If the variable [var.beg, var_end) is the nearest variable to the + // current memory access, indicate it in the log. + if (addr >= var.beg) { + if (addr_end <= var_end) + pos_descr = "is inside"; // May happen if this is a use-after-return. + else if (addr < var_end) + pos_descr = "partially overflows"; + else if (addr_end <= next_var_beg && + next_var_beg - addr_end >= addr - var_end) + pos_descr = "overflows"; + } else { + if (addr_end > var.beg) + pos_descr = "partially underflows"; + else if (addr >= prev_var_end && addr - prev_var_end >= var.beg - addr_end) + pos_descr = "underflows"; + } + InternalScopedString str(1024); + str.append(" [%zd, %zd)", var.beg, var_end); + // Render variable name. + str.append(" '"); + for (uptr i = 0; i < var.name_len; ++i) { + str.append("%c", var.name_pos[i]); + } + str.append("'"); + if (pos_descr) { + Decorator d; + // FIXME: we may want to also print the size of the access here, + // but in case of accesses generated by memset it may be confusing. + str.append("%s <== Memory access at offset %zd %s this variable%s\n", + d.Location(), addr, pos_descr, d.EndLocation()); + } else { + str.append("\n"); + } + Printf("%s", str.data()); +} + +bool DescribeAddressIfStack(uptr addr, uptr access_size) { + StackAddressDescription descr; + if (!GetStackAddressInformation(addr, access_size, &descr)) return false; + descr.Print(); + return true; +} + +// Global descriptions +static void DescribeAddressRelativeToGlobal(uptr addr, uptr access_size, + const __asan_global &g) { + InternalScopedString str(4096); + Decorator d; + str.append("%s", d.Location()); + if (addr < g.beg) { + str.append("%p is located %zd bytes to the left", (void *)addr, + g.beg - addr); + } else if (addr + access_size > g.beg + g.size) { + if (addr < g.beg + g.size) addr = g.beg + g.size; + str.append("%p is located %zd bytes to the right", (void *)addr, + addr - (g.beg + g.size)); + } else { + // Can it happen? + str.append("%p is located %zd bytes inside", (void *)addr, addr - g.beg); + } + str.append(" of global variable '%s' defined in '", + MaybeDemangleGlobalName(g.name)); + PrintGlobalLocation(&str, g); + str.append("' (0x%zx) of size %zu\n", g.beg, g.size); + str.append("%s", d.EndLocation()); + PrintGlobalNameIfASCII(&str, g); + Printf("%s", str.data()); +} + +bool GetGlobalAddressInformation(uptr addr, uptr access_size, + GlobalAddressDescription *descr) { + descr->addr = addr; + int globals_num = GetGlobalsForAddress(addr, descr->globals, descr->reg_sites, + ARRAY_SIZE(descr->globals)); + descr->size = globals_num; + descr->access_size = access_size; + return globals_num != 0; +} + +bool DescribeAddressIfGlobal(uptr addr, uptr access_size, + const char *bug_type) { + GlobalAddressDescription descr; + if (!GetGlobalAddressInformation(addr, access_size, &descr)) return false; + + descr.Print(bug_type); + return true; +} + +void ShadowAddressDescription::Print() const { + Printf("Address %p is located in the %s area.\n", addr, ShadowNames[kind]); +} + +void GlobalAddressDescription::Print(const char *bug_type) const { + for (int i = 0; i < size; i++) { + DescribeAddressRelativeToGlobal(addr, access_size, globals[i]); + if (bug_type && + 0 == internal_strcmp(bug_type, "initialization-order-fiasco") && + reg_sites[i]) { + Printf(" registered at:\n"); + StackDepotGet(reg_sites[i]).Print(); + } + } +} + +void StackAddressDescription::Print() const { + Decorator d; + char tname[128]; + Printf("%s", d.Location()); + Printf("Address %p is located in stack of thread T%d%s", addr, tid, + ThreadNameWithParenthesis(tid, tname, sizeof(tname))); + + if (!frame_descr) { + Printf("%s\n", d.EndLocation()); + return; + } + Printf(" at offset %zu in frame%s\n", offset, d.EndLocation()); + + // Now we print the frame where the alloca has happened. + // We print this frame as a stack trace with one element. + // The symbolizer may print more than one frame if inlining was involved. + // The frame numbers may be different than those in the stack trace printed + // previously. That's unfortunate, but I have no better solution, + // especially given that the alloca may be from entirely different place + // (e.g. use-after-scope, or different thread's stack). + Printf("%s", d.EndLocation()); + StackTrace alloca_stack(&frame_pc, 1); + alloca_stack.Print(); + + InternalMmapVector vars(16); + if (!ParseFrameDescription(frame_descr, &vars)) { + Printf( + "AddressSanitizer can't parse the stack frame " + "descriptor: |%s|\n", + frame_descr); + // 'addr' is a stack address, so return true even if we can't parse frame + return; + } + uptr n_objects = vars.size(); + // Report the number of stack objects. + Printf(" This frame has %zu object(s):\n", n_objects); + + // Report all objects in this frame. + for (uptr i = 0; i < n_objects; i++) { + uptr prev_var_end = i ? vars[i - 1].beg + vars[i - 1].size : 0; + uptr next_var_beg = i + 1 < n_objects ? vars[i + 1].beg : ~(0UL); + PrintAccessAndVarIntersection(vars[i], offset, access_size, prev_var_end, + next_var_beg); + } + Printf( + "HINT: this may be a false positive if your program uses " + "some custom stack unwind mechanism or swapcontext\n"); + if (SANITIZER_WINDOWS) + Printf(" (longjmp, SEH and C++ exceptions *are* supported)\n"); + else + Printf(" (longjmp and C++ exceptions *are* supported)\n"); + + DescribeThread(GetThreadContextByTidLocked(tid)); +} + +void HeapAddressDescription::Print() const { + PrintHeapChunkAccess(addr, chunk_access); + + asanThreadRegistry().CheckLocked(); + AsanThreadContext *alloc_thread = GetThreadContextByTidLocked(alloc_tid); + StackTrace alloc_stack = GetStackTraceFromId(alloc_stack_id); + + char tname[128]; + Decorator d; + AsanThreadContext *free_thread = nullptr; + if (free_tid != kInvalidTid) { + free_thread = GetThreadContextByTidLocked(free_tid); + Printf("%sfreed by thread T%d%s here:%s\n", d.Allocation(), + free_thread->tid, + ThreadNameWithParenthesis(free_thread, tname, sizeof(tname)), + d.EndAllocation()); + StackTrace free_stack = GetStackTraceFromId(free_stack_id); + free_stack.Print(); + Printf("%spreviously allocated by thread T%d%s here:%s\n", d.Allocation(), + alloc_thread->tid, + ThreadNameWithParenthesis(alloc_thread, tname, sizeof(tname)), + d.EndAllocation()); + } else { + Printf("%sallocated by thread T%d%s here:%s\n", d.Allocation(), + alloc_thread->tid, + ThreadNameWithParenthesis(alloc_thread, tname, sizeof(tname)), + d.EndAllocation()); + } + alloc_stack.Print(); + DescribeThread(GetCurrentThread()); + if (free_thread) DescribeThread(free_thread); + DescribeThread(alloc_thread); +} + +AddressDescription::AddressDescription(uptr addr, uptr access_size, + bool shouldLockThreadRegistry) { + if (GetShadowAddressInformation(addr, &data.shadow)) { + data.kind = kAddressKindShadow; + return; + } + if (GetHeapAddressInformation(addr, access_size, &data.heap)) { + data.kind = kAddressKindHeap; + return; + } + + bool isStackMemory = false; + if (shouldLockThreadRegistry) { + ThreadRegistryLock l(&asanThreadRegistry()); + isStackMemory = GetStackAddressInformation(addr, access_size, &data.stack); + } else { + isStackMemory = GetStackAddressInformation(addr, access_size, &data.stack); + } + if (isStackMemory) { + data.kind = kAddressKindStack; + return; + } + + if (GetGlobalAddressInformation(addr, access_size, &data.global)) { + data.kind = kAddressKindGlobal; + return; + } + data.kind = kAddressKindWild; + addr = 0; +} + +void PrintAddressDescription(uptr addr, uptr access_size, + const char *bug_type) { + ShadowAddressDescription shadow_descr; + if (GetShadowAddressInformation(addr, &shadow_descr)) { + shadow_descr.Print(); + return; + } + + GlobalAddressDescription global_descr; + if (GetGlobalAddressInformation(addr, access_size, &global_descr)) { + global_descr.Print(bug_type); + return; + } + + StackAddressDescription stack_descr; + if (GetStackAddressInformation(addr, access_size, &stack_descr)) { + stack_descr.Print(); + return; + } + + HeapAddressDescription heap_descr; + if (GetHeapAddressInformation(addr, access_size, &heap_descr)) { + heap_descr.Print(); + return; + } + + // We exhausted our possibilities. Bail out. + Printf( + "AddressSanitizer can not describe address in more detail " + "(wild memory access suspected).\n"); +} +} // namespace __asan Property changes on: projects/clang400-import/contrib/compiler-rt/lib/asan/asan_descriptions.cc ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: projects/clang400-import/contrib/compiler-rt/lib/asan/asan_descriptions.h =================================================================== --- projects/clang400-import/contrib/compiler-rt/lib/asan/asan_descriptions.h (nonexistent) +++ projects/clang400-import/contrib/compiler-rt/lib/asan/asan_descriptions.h (revision 311697) @@ -0,0 +1,253 @@ +//===-- asan_descriptions.h -------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file is a part of AddressSanitizer, an address sanity checker. +// +// ASan-private header for asan_descriptions.cc. +// TODO(filcab): Most struct definitions should move to the interface headers. +//===----------------------------------------------------------------------===// +#ifndef ASAN_DESCRIPTIONS_H +#define ASAN_DESCRIPTIONS_H + +#include "asan_allocator.h" +#include "asan_thread.h" +#include "sanitizer_common/sanitizer_common.h" +#include "sanitizer_common/sanitizer_report_decorator.h" + +namespace __asan { + +void DescribeThread(AsanThreadContext *context); +static inline void DescribeThread(AsanThread *t) { + if (t) DescribeThread(t->context()); +} +const char *ThreadNameWithParenthesis(AsanThreadContext *t, char buff[], + uptr buff_len); +const char *ThreadNameWithParenthesis(u32 tid, char buff[], uptr buff_len); + +class Decorator : public __sanitizer::SanitizerCommonDecorator { + public: + Decorator() : SanitizerCommonDecorator() {} + const char *Access() { return Blue(); } + const char *EndAccess() { return Default(); } + const char *Location() { return Green(); } + const char *EndLocation() { return Default(); } + const char *Allocation() { return Magenta(); } + const char *EndAllocation() { return Default(); } + + const char *ShadowByte(u8 byte) { + switch (byte) { + case kAsanHeapLeftRedzoneMagic: + case kAsanArrayCookieMagic: + return Red(); + case kAsanHeapFreeMagic: + return Magenta(); + case kAsanStackLeftRedzoneMagic: + case kAsanStackMidRedzoneMagic: + case kAsanStackRightRedzoneMagic: + return Red(); + case kAsanStackAfterReturnMagic: + return Magenta(); + case kAsanInitializationOrderMagic: + return Cyan(); + case kAsanUserPoisonedMemoryMagic: + case kAsanContiguousContainerOOBMagic: + case kAsanAllocaLeftMagic: + case kAsanAllocaRightMagic: + return Blue(); + case kAsanStackUseAfterScopeMagic: + return Magenta(); + case kAsanGlobalRedzoneMagic: + return Red(); + case kAsanInternalHeapMagic: + return Yellow(); + case kAsanIntraObjectRedzone: + return Yellow(); + default: + return Default(); + } + } + const char *EndShadowByte() { return Default(); } + const char *MemoryByte() { return Magenta(); } + const char *EndMemoryByte() { return Default(); } +}; + +enum ShadowKind : u8 { + kShadowKindLow, + kShadowKindGap, + kShadowKindHigh, +}; +static const char *const ShadowNames[] = {"low shadow", "shadow gap", + "high shadow"}; + +struct ShadowAddressDescription { + uptr addr; + ShadowKind kind; + u8 shadow_byte; + + void Print() const; +}; + +bool GetShadowAddressInformation(uptr addr, ShadowAddressDescription *descr); +bool DescribeAddressIfShadow(uptr addr); + +enum AccessType { + kAccessTypeLeft, + kAccessTypeRight, + kAccessTypeInside, + kAccessTypeUnknown, // This means we have an AddressSanitizer bug! +}; + +struct ChunkAccess { + uptr bad_addr; + sptr offset; + uptr chunk_begin; + uptr chunk_size; + u32 access_type : 2; + u32 alloc_type : 2; +}; + +struct HeapAddressDescription { + uptr addr; + uptr alloc_tid; + uptr free_tid; + u32 alloc_stack_id; + u32 free_stack_id; + ChunkAccess chunk_access; + + void Print() const; +}; + +bool GetHeapAddressInformation(uptr addr, uptr access_size, + HeapAddressDescription *descr); +bool DescribeAddressIfHeap(uptr addr, uptr access_size = 1); + +struct StackAddressDescription { + uptr addr; + uptr tid; + uptr offset; + uptr frame_pc; + uptr access_size; + const char *frame_descr; + + void Print() const; +}; + +bool GetStackAddressInformation(uptr addr, uptr access_size, + StackAddressDescription *descr); + +struct GlobalAddressDescription { + uptr addr; + // Assume address is close to at most four globals. + static const int kMaxGlobals = 4; + __asan_global globals[kMaxGlobals]; + u32 reg_sites[kMaxGlobals]; + uptr access_size; + u8 size; + + void Print(const char *bug_type = "") const; +}; + +bool GetGlobalAddressInformation(uptr addr, uptr access_size, + GlobalAddressDescription *descr); +bool DescribeAddressIfGlobal(uptr addr, uptr access_size, const char *bug_type); + +// General function to describe an address. Will try to describe the address as +// a shadow, global (variable), stack, or heap address. +// bug_type is optional and is used for checking if we're reporting an +// initialization-order-fiasco +// The proper access_size should be passed for stack, global, and heap +// addresses. Defaults to 1. +// Each of the *AddressDescription functions has its own Print() member, which +// may take access_size and bug_type parameters if needed. +void PrintAddressDescription(uptr addr, uptr access_size = 1, + const char *bug_type = ""); + +enum AddressKind { + kAddressKindWild, + kAddressKindShadow, + kAddressKindHeap, + kAddressKindStack, + kAddressKindGlobal, +}; + +class AddressDescription { + struct AddressDescriptionData { + AddressKind kind; + union { + ShadowAddressDescription shadow; + HeapAddressDescription heap; + StackAddressDescription stack; + GlobalAddressDescription global; + uptr addr; + }; + }; + + AddressDescriptionData data; + + public: + AddressDescription() = default; + // shouldLockThreadRegistry allows us to skip locking if we're sure we already + // have done it. + AddressDescription(uptr addr, bool shouldLockThreadRegistry = true) + : AddressDescription(addr, 1, shouldLockThreadRegistry) {} + AddressDescription(uptr addr, uptr access_size, + bool shouldLockThreadRegistry = true); + + uptr Address() const { + switch (data.kind) { + case kAddressKindWild: + return data.addr; + case kAddressKindShadow: + return data.shadow.addr; + case kAddressKindHeap: + return data.heap.addr; + case kAddressKindStack: + return data.stack.addr; + case kAddressKindGlobal: + return data.global.addr; + } + UNREACHABLE("AddressInformation kind is invalid"); + } + void Print(const char *bug_descr = nullptr) const { + switch (data.kind) { + case kAddressKindWild: + Printf("Address %p is a wild pointer.\n", data.addr); + return; + case kAddressKindShadow: + return data.shadow.Print(); + case kAddressKindHeap: + return data.heap.Print(); + case kAddressKindStack: + return data.stack.Print(); + case kAddressKindGlobal: + // initialization-order-fiasco has a special Print() + return data.global.Print(bug_descr); + } + UNREACHABLE("AddressInformation kind is invalid"); + } + + void StoreTo(AddressDescriptionData *dst) const { *dst = data; } + + const ShadowAddressDescription *AsShadow() const { + return data.kind == kAddressKindShadow ? &data.shadow : nullptr; + } + const HeapAddressDescription *AsHeap() const { + return data.kind == kAddressKindHeap ? &data.heap : nullptr; + } + const StackAddressDescription *AsStack() const { + return data.kind == kAddressKindStack ? &data.stack : nullptr; + } + const GlobalAddressDescription *AsGlobal() const { + return data.kind == kAddressKindGlobal ? &data.global : nullptr; + } +}; + +} // namespace __asan + +#endif // ASAN_DESCRIPTIONS_H Property changes on: projects/clang400-import/contrib/compiler-rt/lib/asan/asan_descriptions.h ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: projects/clang400-import/contrib/compiler-rt/lib/asan/asan_errors.cc =================================================================== --- projects/clang400-import/contrib/compiler-rt/lib/asan/asan_errors.cc (nonexistent) +++ projects/clang400-import/contrib/compiler-rt/lib/asan/asan_errors.cc (revision 311697) @@ -0,0 +1,503 @@ +//===-- asan_errors.cc ------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file is a part of AddressSanitizer, an address sanity checker. +// +// ASan implementation for error structures. +//===----------------------------------------------------------------------===// + +#include "asan_errors.h" +#include +#include "asan_descriptions.h" +#include "asan_mapping.h" +#include "asan_report.h" +#include "asan_stack.h" +#include "sanitizer_common/sanitizer_stackdepot.h" + +namespace __asan { + +void ErrorStackOverflow::Print() { + Decorator d; + Printf("%s", d.Warning()); + Report( + "ERROR: AddressSanitizer: %s on address %p" + " (pc %p bp %p sp %p T%d)\n", scariness.GetDescription(), + (void *)addr, (void *)pc, (void *)bp, (void *)sp, tid); + Printf("%s", d.EndWarning()); + scariness.Print(); + BufferedStackTrace stack; + GetStackTraceWithPcBpAndContext(&stack, kStackTraceMax, pc, bp, context, + common_flags()->fast_unwind_on_fatal); + stack.Print(); + ReportErrorSummary(scariness.GetDescription(), &stack); +} + +static void MaybeDumpInstructionBytes(uptr pc) { + if (!flags()->dump_instruction_bytes || (pc < GetPageSizeCached())) return; + InternalScopedString str(1024); + str.append("First 16 instruction bytes at pc: "); + if (IsAccessibleMemoryRange(pc, 16)) { + for (int i = 0; i < 16; ++i) { + PrintMemoryByte(&str, "", ((u8 *)pc)[i], /*in_shadow*/ false, " "); + } + str.append("\n"); + } else { + str.append("unaccessible\n"); + } + Report("%s", str.data()); +} + +static void MaybeDumpRegisters(void *context) { + if (!flags()->dump_registers) return; + SignalContext::DumpAllRegisters(context); +} + +void ErrorDeadlySignal::Print() { + Decorator d; + Printf("%s", d.Warning()); + const char *description = DescribeSignalOrException(signo); + Report( + "ERROR: AddressSanitizer: %s on unknown address %p (pc %p bp %p sp %p " + "T%d)\n", + description, (void *)addr, (void *)pc, (void *)bp, (void *)sp, tid); + Printf("%s", d.EndWarning()); + if (pc < GetPageSizeCached()) Report("Hint: pc points to the zero page.\n"); + if (is_memory_access) { + const char *access_type = + write_flag == SignalContext::WRITE + ? "WRITE" + : (write_flag == SignalContext::READ ? "READ" : "UNKNOWN"); + Report("The signal is caused by a %s memory access.\n", access_type); + if (addr < GetPageSizeCached()) + Report("Hint: address points to the zero page.\n"); + } + scariness.Print(); + BufferedStackTrace stack; + GetStackTraceWithPcBpAndContext(&stack, kStackTraceMax, pc, bp, context, + common_flags()->fast_unwind_on_fatal); + stack.Print(); + MaybeDumpInstructionBytes(pc); + MaybeDumpRegisters(context); + Printf("AddressSanitizer can not provide additional info.\n"); + ReportErrorSummary(description, &stack); +} + +void ErrorDoubleFree::Print() { + Decorator d; + Printf("%s", d.Warning()); + char tname[128]; + Report( + "ERROR: AddressSanitizer: attempting %s on %p in " + "thread T%d%s:\n", + scariness.GetDescription(), addr_description.addr, tid, + ThreadNameWithParenthesis(tid, tname, sizeof(tname))); + Printf("%s", d.EndWarning()); + scariness.Print(); + GET_STACK_TRACE_FATAL(second_free_stack->trace[0], + second_free_stack->top_frame_bp); + stack.Print(); + addr_description.Print(); + ReportErrorSummary(scariness.GetDescription(), &stack); +} + +void ErrorNewDeleteSizeMismatch::Print() { + Decorator d; + Printf("%s", d.Warning()); + char tname[128]; + Report( + "ERROR: AddressSanitizer: %s on %p in thread " + "T%d%s:\n", + scariness.GetDescription(), addr_description.addr, tid, + ThreadNameWithParenthesis(tid, tname, sizeof(tname))); + Printf("%s object passed to delete has wrong type:\n", d.EndWarning()); + Printf( + " size of the allocated type: %zd bytes;\n" + " size of the deallocated type: %zd bytes.\n", + addr_description.chunk_access.chunk_size, delete_size); + CHECK_GT(free_stack->size, 0); + scariness.Print(); + GET_STACK_TRACE_FATAL(free_stack->trace[0], free_stack->top_frame_bp); + stack.Print(); + addr_description.Print(); + ReportErrorSummary(scariness.GetDescription(), &stack); + Report( + "HINT: if you don't care about these errors you may set " + "ASAN_OPTIONS=new_delete_type_mismatch=0\n"); +} + +void ErrorFreeNotMalloced::Print() { + Decorator d; + Printf("%s", d.Warning()); + char tname[128]; + Report( + "ERROR: AddressSanitizer: attempting free on address " + "which was not malloc()-ed: %p in thread T%d%s\n", + addr_description.Address(), tid, + ThreadNameWithParenthesis(tid, tname, sizeof(tname))); + Printf("%s", d.EndWarning()); + CHECK_GT(free_stack->size, 0); + scariness.Print(); + GET_STACK_TRACE_FATAL(free_stack->trace[0], free_stack->top_frame_bp); + stack.Print(); + addr_description.Print(); + ReportErrorSummary(scariness.GetDescription(), &stack); +} + +void ErrorAllocTypeMismatch::Print() { + static const char *alloc_names[] = {"INVALID", "malloc", "operator new", + "operator new []"}; + static const char *dealloc_names[] = {"INVALID", "free", "operator delete", + "operator delete []"}; + CHECK_NE(alloc_type, dealloc_type); + Decorator d; + Printf("%s", d.Warning()); + Report("ERROR: AddressSanitizer: %s (%s vs %s) on %p\n", + scariness.GetDescription(), + alloc_names[alloc_type], dealloc_names[dealloc_type], + addr_description.addr); + Printf("%s", d.EndWarning()); + CHECK_GT(dealloc_stack->size, 0); + scariness.Print(); + GET_STACK_TRACE_FATAL(dealloc_stack->trace[0], dealloc_stack->top_frame_bp); + stack.Print(); + addr_description.Print(); + ReportErrorSummary(scariness.GetDescription(), &stack); + Report( + "HINT: if you don't care about these errors you may set " + "ASAN_OPTIONS=alloc_dealloc_mismatch=0\n"); +} + +void ErrorMallocUsableSizeNotOwned::Print() { + Decorator d; + Printf("%s", d.Warning()); + Report( + "ERROR: AddressSanitizer: attempting to call malloc_usable_size() for " + "pointer which is not owned: %p\n", + addr_description.Address()); + Printf("%s", d.EndWarning()); + stack->Print(); + addr_description.Print(); + ReportErrorSummary(scariness.GetDescription(), stack); +} + +void ErrorSanitizerGetAllocatedSizeNotOwned::Print() { + Decorator d; + Printf("%s", d.Warning()); + Report( + "ERROR: AddressSanitizer: attempting to call " + "__sanitizer_get_allocated_size() for pointer which is not owned: %p\n", + addr_description.Address()); + Printf("%s", d.EndWarning()); + stack->Print(); + addr_description.Print(); + ReportErrorSummary(scariness.GetDescription(), stack); +} + +void ErrorStringFunctionMemoryRangesOverlap::Print() { + Decorator d; + char bug_type[100]; + internal_snprintf(bug_type, sizeof(bug_type), "%s-param-overlap", function); + Printf("%s", d.Warning()); + Report( + "ERROR: AddressSanitizer: %s: memory ranges [%p,%p) and [%p, %p) " + "overlap\n", + bug_type, addr1_description.Address(), + addr1_description.Address() + length1, addr2_description.Address(), + addr2_description.Address() + length2); + Printf("%s", d.EndWarning()); + scariness.Print(); + stack->Print(); + addr1_description.Print(); + addr2_description.Print(); + ReportErrorSummary(bug_type, stack); +} + +void ErrorStringFunctionSizeOverflow::Print() { + Decorator d; + Printf("%s", d.Warning()); + Report("ERROR: AddressSanitizer: %s: (size=%zd)\n", + scariness.GetDescription(), size); + Printf("%s", d.EndWarning()); + scariness.Print(); + stack->Print(); + addr_description.Print(); + ReportErrorSummary(scariness.GetDescription(), stack); +} + +void ErrorBadParamsToAnnotateContiguousContainer::Print() { + Report( + "ERROR: AddressSanitizer: bad parameters to " + "__sanitizer_annotate_contiguous_container:\n" + " beg : %p\n" + " end : %p\n" + " old_mid : %p\n" + " new_mid : %p\n", + beg, end, old_mid, new_mid); + uptr granularity = SHADOW_GRANULARITY; + if (!IsAligned(beg, granularity)) + Report("ERROR: beg is not aligned by %d\n", granularity); + stack->Print(); + ReportErrorSummary(scariness.GetDescription(), stack); +} + +void ErrorODRViolation::Print() { + Decorator d; + Printf("%s", d.Warning()); + Report("ERROR: AddressSanitizer: %s (%p):\n", scariness.GetDescription(), + global1.beg); + Printf("%s", d.EndWarning()); + InternalScopedString g1_loc(256), g2_loc(256); + PrintGlobalLocation(&g1_loc, global1); + PrintGlobalLocation(&g2_loc, global2); + Printf(" [1] size=%zd '%s' %s\n", global1.size, + MaybeDemangleGlobalName(global1.name), g1_loc.data()); + Printf(" [2] size=%zd '%s' %s\n", global2.size, + MaybeDemangleGlobalName(global2.name), g2_loc.data()); + if (stack_id1 && stack_id2) { + Printf("These globals were registered at these points:\n"); + Printf(" [1]:\n"); + StackDepotGet(stack_id1).Print(); + Printf(" [2]:\n"); + StackDepotGet(stack_id2).Print(); + } + Report( + "HINT: if you don't care about these errors you may set " + "ASAN_OPTIONS=detect_odr_violation=0\n"); + InternalScopedString error_msg(256); + error_msg.append("%s: global '%s' at %s", scariness.GetDescription(), + MaybeDemangleGlobalName(global1.name), g1_loc.data()); + ReportErrorSummary(error_msg.data()); +} + +void ErrorInvalidPointerPair::Print() { + Decorator d; + Printf("%s", d.Warning()); + Report("ERROR: AddressSanitizer: %s: %p %p\n", scariness.GetDescription(), + addr1_description.Address(), addr2_description.Address()); + Printf("%s", d.EndWarning()); + GET_STACK_TRACE_FATAL(pc, bp); + stack.Print(); + addr1_description.Print(); + addr2_description.Print(); + ReportErrorSummary(scariness.GetDescription(), &stack); +} + +static bool AdjacentShadowValuesAreFullyPoisoned(u8 *s) { + return s[-1] > 127 && s[1] > 127; +} + +ErrorGeneric::ErrorGeneric(u32 tid, uptr pc_, uptr bp_, uptr sp_, uptr addr, + bool is_write_, uptr access_size_) + : ErrorBase(tid), + addr_description(addr, access_size_, /*shouldLockThreadRegistry=*/false), + pc(pc_), + bp(bp_), + sp(sp_), + access_size(access_size_), + is_write(is_write_), + shadow_val(0) { + scariness.Clear(); + if (access_size) { + if (access_size <= 9) { + char desr[] = "?-byte"; + desr[0] = '0' + access_size; + scariness.Scare(access_size + access_size / 2, desr); + } else if (access_size >= 10) { + scariness.Scare(15, "multi-byte"); + } + is_write ? scariness.Scare(20, "write") : scariness.Scare(1, "read"); + + // Determine the error type. + bug_descr = "unknown-crash"; + if (AddrIsInMem(addr)) { + u8 *shadow_addr = (u8 *)MemToShadow(addr); + // If we are accessing 16 bytes, look at the second shadow byte. + if (*shadow_addr == 0 && access_size > SHADOW_GRANULARITY) shadow_addr++; + // If we are in the partial right redzone, look at the next shadow byte. + if (*shadow_addr > 0 && *shadow_addr < 128) shadow_addr++; + bool far_from_bounds = false; + shadow_val = *shadow_addr; + int bug_type_score = 0; + // For use-after-frees reads are almost as bad as writes. + int read_after_free_bonus = 0; + switch (shadow_val) { + case kAsanHeapLeftRedzoneMagic: + case kAsanArrayCookieMagic: + bug_descr = "heap-buffer-overflow"; + bug_type_score = 10; + far_from_bounds = AdjacentShadowValuesAreFullyPoisoned(shadow_addr); + break; + case kAsanHeapFreeMagic: + bug_descr = "heap-use-after-free"; + bug_type_score = 20; + if (!is_write) read_after_free_bonus = 18; + break; + case kAsanStackLeftRedzoneMagic: + bug_descr = "stack-buffer-underflow"; + bug_type_score = 25; + far_from_bounds = AdjacentShadowValuesAreFullyPoisoned(shadow_addr); + break; + case kAsanInitializationOrderMagic: + bug_descr = "initialization-order-fiasco"; + bug_type_score = 1; + break; + case kAsanStackMidRedzoneMagic: + case kAsanStackRightRedzoneMagic: + bug_descr = "stack-buffer-overflow"; + bug_type_score = 25; + far_from_bounds = AdjacentShadowValuesAreFullyPoisoned(shadow_addr); + break; + case kAsanStackAfterReturnMagic: + bug_descr = "stack-use-after-return"; + bug_type_score = 30; + if (!is_write) read_after_free_bonus = 18; + break; + case kAsanUserPoisonedMemoryMagic: + bug_descr = "use-after-poison"; + bug_type_score = 20; + break; + case kAsanContiguousContainerOOBMagic: + bug_descr = "container-overflow"; + bug_type_score = 10; + break; + case kAsanStackUseAfterScopeMagic: + bug_descr = "stack-use-after-scope"; + bug_type_score = 10; + break; + case kAsanGlobalRedzoneMagic: + bug_descr = "global-buffer-overflow"; + bug_type_score = 10; + far_from_bounds = AdjacentShadowValuesAreFullyPoisoned(shadow_addr); + break; + case kAsanIntraObjectRedzone: + bug_descr = "intra-object-overflow"; + bug_type_score = 10; + break; + case kAsanAllocaLeftMagic: + case kAsanAllocaRightMagic: + bug_descr = "dynamic-stack-buffer-overflow"; + bug_type_score = 25; + far_from_bounds = AdjacentShadowValuesAreFullyPoisoned(shadow_addr); + break; + } + scariness.Scare(bug_type_score + read_after_free_bonus, bug_descr); + if (far_from_bounds) scariness.Scare(10, "far-from-bounds"); + } + } +} + +static void PrintContainerOverflowHint() { + Printf("HINT: if you don't care about these errors you may set " + "ASAN_OPTIONS=detect_container_overflow=0.\n" + "If you suspect a false positive see also: " + "https://github.com/google/sanitizers/wiki/" + "AddressSanitizerContainerOverflow.\n"); +} + +static void PrintShadowByte(InternalScopedString *str, const char *before, + u8 byte, const char *after = "\n") { + PrintMemoryByte(str, before, byte, /*in_shadow*/true, after); +} + +static void PrintLegend(InternalScopedString *str) { + str->append( + "Shadow byte legend (one shadow byte represents %d " + "application bytes):\n", + (int)SHADOW_GRANULARITY); + PrintShadowByte(str, " Addressable: ", 0); + str->append(" Partially addressable: "); + for (u8 i = 1; i < SHADOW_GRANULARITY; i++) PrintShadowByte(str, "", i, " "); + str->append("\n"); + PrintShadowByte(str, " Heap left redzone: ", + kAsanHeapLeftRedzoneMagic); + PrintShadowByte(str, " Freed heap region: ", kAsanHeapFreeMagic); + PrintShadowByte(str, " Stack left redzone: ", + kAsanStackLeftRedzoneMagic); + PrintShadowByte(str, " Stack mid redzone: ", + kAsanStackMidRedzoneMagic); + PrintShadowByte(str, " Stack right redzone: ", + kAsanStackRightRedzoneMagic); + PrintShadowByte(str, " Stack after return: ", + kAsanStackAfterReturnMagic); + PrintShadowByte(str, " Stack use after scope: ", + kAsanStackUseAfterScopeMagic); + PrintShadowByte(str, " Global redzone: ", kAsanGlobalRedzoneMagic); + PrintShadowByte(str, " Global init order: ", + kAsanInitializationOrderMagic); + PrintShadowByte(str, " Poisoned by user: ", + kAsanUserPoisonedMemoryMagic); + PrintShadowByte(str, " Container overflow: ", + kAsanContiguousContainerOOBMagic); + PrintShadowByte(str, " Array cookie: ", + kAsanArrayCookieMagic); + PrintShadowByte(str, " Intra object redzone: ", + kAsanIntraObjectRedzone); + PrintShadowByte(str, " ASan internal: ", kAsanInternalHeapMagic); + PrintShadowByte(str, " Left alloca redzone: ", kAsanAllocaLeftMagic); + PrintShadowByte(str, " Right alloca redzone: ", kAsanAllocaRightMagic); +} + +static void PrintShadowBytes(InternalScopedString *str, const char *before, + u8 *bytes, u8 *guilty, uptr n) { + Decorator d; + if (before) str->append("%s%p:", before, bytes); + for (uptr i = 0; i < n; i++) { + u8 *p = bytes + i; + const char *before = + p == guilty ? "[" : (p - 1 == guilty && i != 0) ? "" : " "; + const char *after = p == guilty ? "]" : ""; + PrintShadowByte(str, before, *p, after); + } + str->append("\n"); +} + +static void PrintShadowMemoryForAddress(uptr addr) { + if (!AddrIsInMem(addr)) return; + uptr shadow_addr = MemToShadow(addr); + const uptr n_bytes_per_row = 16; + uptr aligned_shadow = shadow_addr & ~(n_bytes_per_row - 1); + InternalScopedString str(4096 * 8); + str.append("Shadow bytes around the buggy address:\n"); + for (int i = -5; i <= 5; i++) { + const char *prefix = (i == 0) ? "=>" : " "; + PrintShadowBytes(&str, prefix, (u8 *)(aligned_shadow + i * n_bytes_per_row), + (u8 *)shadow_addr, n_bytes_per_row); + } + if (flags()->print_legend) PrintLegend(&str); + Printf("%s", str.data()); +} + +void ErrorGeneric::Print() { + Decorator d; + Printf("%s", d.Warning()); + uptr addr = addr_description.Address(); + Report("ERROR: AddressSanitizer: %s on address %p at pc %p bp %p sp %p\n", + bug_descr, (void *)addr, pc, bp, sp); + Printf("%s", d.EndWarning()); + + char tname[128]; + Printf("%s%s of size %zu at %p thread T%d%s%s\n", d.Access(), + access_size ? (is_write ? "WRITE" : "READ") : "ACCESS", access_size, + (void *)addr, tid, + ThreadNameWithParenthesis(tid, tname, sizeof(tname)), d.EndAccess()); + + scariness.Print(); + GET_STACK_TRACE_FATAL(pc, bp); + stack.Print(); + + // Pass bug_descr because we have a special case for + // initialization-order-fiasco + addr_description.Print(bug_descr); + if (shadow_val == kAsanContiguousContainerOOBMagic) + PrintContainerOverflowHint(); + ReportErrorSummary(bug_descr, &stack); + PrintShadowMemoryForAddress(addr); +} + +} // namespace __asan Property changes on: projects/clang400-import/contrib/compiler-rt/lib/asan/asan_errors.cc ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: projects/clang400-import/contrib/compiler-rt/lib/asan/asan_errors.h =================================================================== --- projects/clang400-import/contrib/compiler-rt/lib/asan/asan_errors.h (nonexistent) +++ projects/clang400-import/contrib/compiler-rt/lib/asan/asan_errors.h (revision 311697) @@ -0,0 +1,390 @@ +//===-- asan_errors.h -------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file is a part of AddressSanitizer, an address sanity checker. +// +// ASan-private header for error structures. +//===----------------------------------------------------------------------===// +#ifndef ASAN_ERRORS_H +#define ASAN_ERRORS_H + +#include "asan_descriptions.h" +#include "asan_scariness_score.h" +#include "sanitizer_common/sanitizer_common.h" + +namespace __asan { + +struct ErrorBase { + ErrorBase() = default; + explicit ErrorBase(u32 tid_) : tid(tid_) {} + ScarinessScoreBase scariness; + u32 tid; +}; + +struct ErrorStackOverflow : ErrorBase { + uptr addr, pc, bp, sp; + // ErrorStackOverflow never owns the context. + void *context; + // VS2013 doesn't implement unrestricted unions, so we need a trivial default + // constructor + ErrorStackOverflow() = default; + ErrorStackOverflow(u32 tid, const SignalContext &sig) + : ErrorBase(tid), + addr(sig.addr), + pc(sig.pc), + bp(sig.bp), + sp(sig.sp), + context(sig.context) { + scariness.Clear(); + scariness.Scare(10, "stack-overflow"); + } + void Print(); +}; + +struct ErrorDeadlySignal : ErrorBase { + uptr addr, pc, bp, sp; + // ErrorDeadlySignal never owns the context. + void *context; + int signo; + SignalContext::WriteFlag write_flag; + bool is_memory_access; + // VS2013 doesn't implement unrestricted unions, so we need a trivial default + // constructor + ErrorDeadlySignal() = default; + ErrorDeadlySignal(u32 tid, const SignalContext &sig, int signo_) + : ErrorBase(tid), + addr(sig.addr), + pc(sig.pc), + bp(sig.bp), + sp(sig.sp), + context(sig.context), + signo(signo_), + write_flag(sig.write_flag), + is_memory_access(sig.is_memory_access) { + scariness.Clear(); + if (is_memory_access) { + if (addr < GetPageSizeCached()) { + scariness.Scare(10, "null-deref"); + } else if (addr == pc) { + scariness.Scare(60, "wild-jump"); + } else if (write_flag == SignalContext::WRITE) { + scariness.Scare(30, "wild-addr-write"); + } else if (write_flag == SignalContext::READ) { + scariness.Scare(20, "wild-addr-read"); + } else { + scariness.Scare(25, "wild-addr"); + } + } else { + scariness.Scare(10, "signal"); + } + } + void Print(); +}; + +struct ErrorDoubleFree : ErrorBase { + // ErrorDoubleFree doesn't own the stack trace. + const BufferedStackTrace *second_free_stack; + HeapAddressDescription addr_description; + // VS2013 doesn't implement unrestricted unions, so we need a trivial default + // constructor + ErrorDoubleFree() = default; + ErrorDoubleFree(u32 tid, BufferedStackTrace *stack, uptr addr) + : ErrorBase(tid), second_free_stack(stack) { + CHECK_GT(second_free_stack->size, 0); + GetHeapAddressInformation(addr, 1, &addr_description); + scariness.Clear(); + scariness.Scare(42, "double-free"); + } + void Print(); +}; + +struct ErrorNewDeleteSizeMismatch : ErrorBase { + // ErrorNewDeleteSizeMismatch doesn't own the stack trace. + const BufferedStackTrace *free_stack; + HeapAddressDescription addr_description; + uptr delete_size; + // VS2013 doesn't implement unrestricted unions, so we need a trivial default + // constructor + ErrorNewDeleteSizeMismatch() = default; + ErrorNewDeleteSizeMismatch(u32 tid, BufferedStackTrace *stack, uptr addr, + uptr delete_size_) + : ErrorBase(tid), free_stack(stack), delete_size(delete_size_) { + GetHeapAddressInformation(addr, 1, &addr_description); + scariness.Clear(); + scariness.Scare(10, "new-delete-type-mismatch"); + } + void Print(); +}; + +struct ErrorFreeNotMalloced : ErrorBase { + // ErrorFreeNotMalloced doesn't own the stack trace. + const BufferedStackTrace *free_stack; + AddressDescription addr_description; + // VS2013 doesn't implement unrestricted unions, so we need a trivial default + // constructor + ErrorFreeNotMalloced() = default; + ErrorFreeNotMalloced(u32 tid, BufferedStackTrace *stack, uptr addr) + : ErrorBase(tid), + free_stack(stack), + addr_description(addr, /*shouldLockThreadRegistry=*/false) { + scariness.Clear(); + scariness.Scare(40, "bad-free"); + } + void Print(); +}; + +struct ErrorAllocTypeMismatch : ErrorBase { + // ErrorAllocTypeMismatch doesn't own the stack trace. + const BufferedStackTrace *dealloc_stack; + HeapAddressDescription addr_description; + AllocType alloc_type, dealloc_type; + // VS2013 doesn't implement unrestricted unions, so we need a trivial default + // constructor + ErrorAllocTypeMismatch() = default; + ErrorAllocTypeMismatch(u32 tid, BufferedStackTrace *stack, uptr addr, + AllocType alloc_type_, AllocType dealloc_type_) + : ErrorBase(tid), + dealloc_stack(stack), + alloc_type(alloc_type_), + dealloc_type(dealloc_type_) { + GetHeapAddressInformation(addr, 1, &addr_description); + scariness.Clear(); + scariness.Scare(10, "alloc-dealloc-mismatch"); + }; + void Print(); +}; + +struct ErrorMallocUsableSizeNotOwned : ErrorBase { + // ErrorMallocUsableSizeNotOwned doesn't own the stack trace. + const BufferedStackTrace *stack; + AddressDescription addr_description; + // VS2013 doesn't implement unrestricted unions, so we need a trivial default + // constructor + ErrorMallocUsableSizeNotOwned() = default; + ErrorMallocUsableSizeNotOwned(u32 tid, BufferedStackTrace *stack_, uptr addr) + : ErrorBase(tid), + stack(stack_), + addr_description(addr, /*shouldLockThreadRegistry=*/false) { + scariness.Clear(); + scariness.Scare(10, "bad-malloc_usable_size"); + } + void Print(); +}; + +struct ErrorSanitizerGetAllocatedSizeNotOwned : ErrorBase { + // ErrorSanitizerGetAllocatedSizeNotOwned doesn't own the stack trace. + const BufferedStackTrace *stack; + AddressDescription addr_description; + // VS2013 doesn't implement unrestricted unions, so we need a trivial default + // constructor + ErrorSanitizerGetAllocatedSizeNotOwned() = default; + ErrorSanitizerGetAllocatedSizeNotOwned(u32 tid, BufferedStackTrace *stack_, + uptr addr) + : ErrorBase(tid), + stack(stack_), + addr_description(addr, /*shouldLockThreadRegistry=*/false) { + scariness.Clear(); + scariness.Scare(10, "bad-__sanitizer_get_allocated_size"); + } + void Print(); +}; + +struct ErrorStringFunctionMemoryRangesOverlap : ErrorBase { + // ErrorStringFunctionMemoryRangesOverlap doesn't own the stack trace. + const BufferedStackTrace *stack; + uptr length1, length2; + AddressDescription addr1_description; + AddressDescription addr2_description; + const char *function; + // VS2013 doesn't implement unrestricted unions, so we need a trivial default + // constructor + ErrorStringFunctionMemoryRangesOverlap() = default; + ErrorStringFunctionMemoryRangesOverlap(u32 tid, BufferedStackTrace *stack_, + uptr addr1, uptr length1_, uptr addr2, + uptr length2_, const char *function_) + : ErrorBase(tid), + stack(stack_), + length1(length1_), + length2(length2_), + addr1_description(addr1, length1, /*shouldLockThreadRegistry=*/false), + addr2_description(addr2, length2, /*shouldLockThreadRegistry=*/false), + function(function_) { + char bug_type[100]; + internal_snprintf(bug_type, sizeof(bug_type), "%s-param-overlap", function); + scariness.Clear(); + scariness.Scare(10, bug_type); + } + void Print(); +}; + +struct ErrorStringFunctionSizeOverflow : ErrorBase { + // ErrorStringFunctionSizeOverflow doesn't own the stack trace. + const BufferedStackTrace *stack; + AddressDescription addr_description; + uptr size; + // VS2013 doesn't implement unrestricted unions, so we need a trivial default + // constructor + ErrorStringFunctionSizeOverflow() = default; + ErrorStringFunctionSizeOverflow(u32 tid, BufferedStackTrace *stack_, + uptr addr, uptr size_) + : ErrorBase(tid), + stack(stack_), + addr_description(addr, /*shouldLockThreadRegistry=*/false), + size(size_) { + scariness.Clear(); + scariness.Scare(10, "negative-size-param"); + } + void Print(); +}; + +struct ErrorBadParamsToAnnotateContiguousContainer : ErrorBase { + // ErrorBadParamsToAnnotateContiguousContainer doesn't own the stack trace. + const BufferedStackTrace *stack; + uptr beg, end, old_mid, new_mid; + // VS2013 doesn't implement unrestricted unions, so we need a trivial default + // constructor + ErrorBadParamsToAnnotateContiguousContainer() = default; + // PS4: Do we want an AddressDescription for beg? + ErrorBadParamsToAnnotateContiguousContainer(u32 tid, + BufferedStackTrace *stack_, + uptr beg_, uptr end_, + uptr old_mid_, uptr new_mid_) + : ErrorBase(tid), + stack(stack_), + beg(beg_), + end(end_), + old_mid(old_mid_), + new_mid(new_mid_) { + scariness.Clear(); + scariness.Scare(10, "bad-__sanitizer_annotate_contiguous_container"); + } + void Print(); +}; + +struct ErrorODRViolation : ErrorBase { + __asan_global global1, global2; + u32 stack_id1, stack_id2; + // VS2013 doesn't implement unrestricted unions, so we need a trivial default + // constructor + ErrorODRViolation() = default; + ErrorODRViolation(u32 tid, const __asan_global *g1, u32 stack_id1_, + const __asan_global *g2, u32 stack_id2_) + : ErrorBase(tid), + global1(*g1), + global2(*g2), + stack_id1(stack_id1_), + stack_id2(stack_id2_) { + scariness.Clear(); + scariness.Scare(10, "odr-violation"); + } + void Print(); +}; + +struct ErrorInvalidPointerPair : ErrorBase { + uptr pc, bp, sp; + AddressDescription addr1_description; + AddressDescription addr2_description; + // VS2013 doesn't implement unrestricted unions, so we need a trivial default + // constructor + ErrorInvalidPointerPair() = default; + ErrorInvalidPointerPair(u32 tid, uptr pc_, uptr bp_, uptr sp_, uptr p1, + uptr p2) + : ErrorBase(tid), + pc(pc_), + bp(bp_), + sp(sp_), + addr1_description(p1, 1, /*shouldLockThreadRegistry=*/false), + addr2_description(p2, 1, /*shouldLockThreadRegistry=*/false) { + scariness.Clear(); + scariness.Scare(10, "invalid-pointer-pair"); + } + void Print(); +}; + +struct ErrorGeneric : ErrorBase { + AddressDescription addr_description; + uptr pc, bp, sp; + uptr access_size; + const char *bug_descr; + bool is_write; + u8 shadow_val; + // VS2013 doesn't implement unrestricted unions, so we need a trivial default + // constructor + ErrorGeneric() = default; + ErrorGeneric(u32 tid, uptr addr, uptr pc_, uptr bp_, uptr sp_, bool is_write_, + uptr access_size_); + void Print(); +}; + +// clang-format off +#define ASAN_FOR_EACH_ERROR_KIND(macro) \ + macro(StackOverflow) \ + macro(DeadlySignal) \ + macro(DoubleFree) \ + macro(NewDeleteSizeMismatch) \ + macro(FreeNotMalloced) \ + macro(AllocTypeMismatch) \ + macro(MallocUsableSizeNotOwned) \ + macro(SanitizerGetAllocatedSizeNotOwned) \ + macro(StringFunctionMemoryRangesOverlap) \ + macro(StringFunctionSizeOverflow) \ + macro(BadParamsToAnnotateContiguousContainer) \ + macro(ODRViolation) \ + macro(InvalidPointerPair) \ + macro(Generic) +// clang-format on + +#define ASAN_DEFINE_ERROR_KIND(name) kErrorKind##name, +#define ASAN_ERROR_DESCRIPTION_MEMBER(name) Error##name name; +#define ASAN_ERROR_DESCRIPTION_CONSTRUCTOR(name) \ + ErrorDescription(Error##name const &e) : kind(kErrorKind##name), name(e) {} +#define ASAN_ERROR_DESCRIPTION_PRINT(name) \ + case kErrorKind##name: \ + return name.Print(); + +enum ErrorKind { + kErrorKindInvalid = 0, + ASAN_FOR_EACH_ERROR_KIND(ASAN_DEFINE_ERROR_KIND) +}; + +struct ErrorDescription { + ErrorKind kind; + // We're using a tagged union because it allows us to have a trivially + // copiable type and use the same structures as the public interface. + // + // We can add a wrapper around it to make it "more c++-like", but that would + // add a lot of code and the benefit wouldn't be that big. + union { + ErrorBase Base; + ASAN_FOR_EACH_ERROR_KIND(ASAN_ERROR_DESCRIPTION_MEMBER) + }; + + ErrorDescription() { internal_memset(this, 0, sizeof(*this)); } + ASAN_FOR_EACH_ERROR_KIND(ASAN_ERROR_DESCRIPTION_CONSTRUCTOR) + + bool IsValid() { return kind != kErrorKindInvalid; } + void Print() { + switch (kind) { + ASAN_FOR_EACH_ERROR_KIND(ASAN_ERROR_DESCRIPTION_PRINT) + case kErrorKindInvalid: + CHECK(0); + } + CHECK(0); + } +}; + +#undef ASAN_FOR_EACH_ERROR_KIND +#undef ASAN_DEFINE_ERROR_KIND +#undef ASAN_ERROR_DESCRIPTION_MEMBER +#undef ASAN_ERROR_DESCRIPTION_CONSTRUCTOR +#undef ASAN_ERROR_DESCRIPTION_PRINT + +} // namespace __asan + +#endif // ASAN_ERRORS_H Property changes on: projects/clang400-import/contrib/compiler-rt/lib/asan/asan_errors.h ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: projects/clang400-import/contrib/compiler-rt/lib/asan/asan_fake_stack.cc =================================================================== --- projects/clang400-import/contrib/compiler-rt/lib/asan/asan_fake_stack.cc (revision 311696) +++ projects/clang400-import/contrib/compiler-rt/lib/asan/asan_fake_stack.cc (revision 311697) @@ -1,283 +1,283 @@ //===-- asan_fake_stack.cc ------------------------------------------------===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // This file is a part of AddressSanitizer, an address sanity checker. // // FakeStack is used to detect use-after-return bugs. //===----------------------------------------------------------------------===// #include "asan_allocator.h" #include "asan_poisoning.h" #include "asan_thread.h" namespace __asan { static const u64 kMagic1 = kAsanStackAfterReturnMagic; static const u64 kMagic2 = (kMagic1 << 8) | kMagic1; static const u64 kMagic4 = (kMagic2 << 16) | kMagic2; static const u64 kMagic8 = (kMagic4 << 32) | kMagic4; static const u64 kAllocaRedzoneSize = 32UL; static const u64 kAllocaRedzoneMask = 31UL; // For small size classes inline PoisonShadow for better performance. ALWAYS_INLINE void SetShadow(uptr ptr, uptr size, uptr class_id, u64 magic) { CHECK_EQ(SHADOW_SCALE, 3); // This code expects SHADOW_SCALE=3. u64 *shadow = reinterpret_cast(MemToShadow(ptr)); if (class_id <= 6) { for (uptr i = 0; i < (((uptr)1) << class_id); i++) { shadow[i] = magic; // Make sure this does not become memset. SanitizerBreakOptimization(nullptr); } } else { // The size class is too big, it's cheaper to poison only size bytes. PoisonShadow(ptr, size, static_cast(magic)); } } FakeStack *FakeStack::Create(uptr stack_size_log) { static uptr kMinStackSizeLog = 16; static uptr kMaxStackSizeLog = FIRST_32_SECOND_64(24, 28); if (stack_size_log < kMinStackSizeLog) stack_size_log = kMinStackSizeLog; if (stack_size_log > kMaxStackSizeLog) stack_size_log = kMaxStackSizeLog; uptr size = RequiredSize(stack_size_log); FakeStack *res = reinterpret_cast( flags()->uar_noreserve ? MmapNoReserveOrDie(size, "FakeStack") : MmapOrDie(size, "FakeStack")); res->stack_size_log_ = stack_size_log; u8 *p = reinterpret_cast(res); VReport(1, "T%d: FakeStack created: %p -- %p stack_size_log: %zd; " "mmapped %zdK, noreserve=%d \n", GetCurrentTidOrInvalid(), p, p + FakeStack::RequiredSize(stack_size_log), stack_size_log, size >> 10, flags()->uar_noreserve); return res; } void FakeStack::Destroy(int tid) { PoisonAll(0); if (Verbosity() >= 2) { InternalScopedString str(kNumberOfSizeClasses * 50); for (uptr class_id = 0; class_id < kNumberOfSizeClasses; class_id++) str.append("%zd: %zd/%zd; ", class_id, hint_position_[class_id], NumberOfFrames(stack_size_log(), class_id)); Report("T%d: FakeStack destroyed: %s\n", tid, str.data()); } uptr size = RequiredSize(stack_size_log_); FlushUnneededASanShadowMemory(reinterpret_cast(this), size); UnmapOrDie(this, size); } void FakeStack::PoisonAll(u8 magic) { PoisonShadow(reinterpret_cast(this), RequiredSize(stack_size_log()), magic); } #if !defined(_MSC_VER) || defined(__clang__) ALWAYS_INLINE USED #endif FakeFrame *FakeStack::Allocate(uptr stack_size_log, uptr class_id, uptr real_stack) { CHECK_LT(class_id, kNumberOfSizeClasses); if (needs_gc_) GC(real_stack); uptr &hint_position = hint_position_[class_id]; const int num_iter = NumberOfFrames(stack_size_log, class_id); u8 *flags = GetFlags(stack_size_log, class_id); for (int i = 0; i < num_iter; i++) { uptr pos = ModuloNumberOfFrames(stack_size_log, class_id, hint_position++); // This part is tricky. On one hand, checking and setting flags[pos] // should be atomic to ensure async-signal safety. But on the other hand, // if the signal arrives between checking and setting flags[pos], the // signal handler's fake stack will start from a different hint_position // and so will not touch this particular byte. So, it is safe to do this - // with regular non-atimic load and store (at least I was not able to make + // with regular non-atomic load and store (at least I was not able to make // this code crash). if (flags[pos]) continue; flags[pos] = 1; FakeFrame *res = reinterpret_cast( GetFrame(stack_size_log, class_id, pos)); res->real_stack = real_stack; *SavedFlagPtr(reinterpret_cast(res), class_id) = &flags[pos]; return res; } return nullptr; // We are out of fake stack. } uptr FakeStack::AddrIsInFakeStack(uptr ptr, uptr *frame_beg, uptr *frame_end) { uptr stack_size_log = this->stack_size_log(); uptr beg = reinterpret_cast(GetFrame(stack_size_log, 0, 0)); uptr end = reinterpret_cast(this) + RequiredSize(stack_size_log); if (ptr < beg || ptr >= end) return 0; uptr class_id = (ptr - beg) >> stack_size_log; uptr base = beg + (class_id << stack_size_log); CHECK_LE(base, ptr); CHECK_LT(ptr, base + (((uptr)1) << stack_size_log)); uptr pos = (ptr - base) >> (kMinStackFrameSizeLog + class_id); uptr res = base + pos * BytesInSizeClass(class_id); *frame_end = res + BytesInSizeClass(class_id); *frame_beg = res + sizeof(FakeFrame); return res; } void FakeStack::HandleNoReturn() { needs_gc_ = true; } // When throw, longjmp or some such happens we don't call OnFree() and // as the result may leak one or more fake frames, but the good news is that // we are notified about all such events by HandleNoReturn(). // If we recently had such no-return event we need to collect garbage frames. // We do it based on their 'real_stack' values -- everything that is lower // than the current real_stack is garbage. NOINLINE void FakeStack::GC(uptr real_stack) { uptr collected = 0; for (uptr class_id = 0; class_id < kNumberOfSizeClasses; class_id++) { u8 *flags = GetFlags(stack_size_log(), class_id); for (uptr i = 0, n = NumberOfFrames(stack_size_log(), class_id); i < n; i++) { if (flags[i] == 0) continue; // not allocated. FakeFrame *ff = reinterpret_cast( GetFrame(stack_size_log(), class_id, i)); if (ff->real_stack < real_stack) { flags[i] = 0; collected++; } } } needs_gc_ = false; } void FakeStack::ForEachFakeFrame(RangeIteratorCallback callback, void *arg) { for (uptr class_id = 0; class_id < kNumberOfSizeClasses; class_id++) { u8 *flags = GetFlags(stack_size_log(), class_id); for (uptr i = 0, n = NumberOfFrames(stack_size_log(), class_id); i < n; i++) { if (flags[i] == 0) continue; // not allocated. FakeFrame *ff = reinterpret_cast( GetFrame(stack_size_log(), class_id, i)); uptr begin = reinterpret_cast(ff); callback(begin, begin + FakeStack::BytesInSizeClass(class_id), arg); } } } #if SANITIZER_LINUX && !SANITIZER_ANDROID static THREADLOCAL FakeStack *fake_stack_tls; FakeStack *GetTLSFakeStack() { return fake_stack_tls; } void SetTLSFakeStack(FakeStack *fs) { fake_stack_tls = fs; } #else FakeStack *GetTLSFakeStack() { return 0; } void SetTLSFakeStack(FakeStack *fs) { } #endif // SANITIZER_LINUX && !SANITIZER_ANDROID static FakeStack *GetFakeStack() { AsanThread *t = GetCurrentThread(); if (!t) return nullptr; return t->fake_stack(); } static FakeStack *GetFakeStackFast() { if (FakeStack *fs = GetTLSFakeStack()) return fs; if (!__asan_option_detect_stack_use_after_return) return nullptr; return GetFakeStack(); } ALWAYS_INLINE uptr OnMalloc(uptr class_id, uptr size) { FakeStack *fs = GetFakeStackFast(); if (!fs) return 0; uptr local_stack; uptr real_stack = reinterpret_cast(&local_stack); FakeFrame *ff = fs->Allocate(fs->stack_size_log(), class_id, real_stack); if (!ff) return 0; // Out of fake stack. uptr ptr = reinterpret_cast(ff); SetShadow(ptr, size, class_id, 0); return ptr; } ALWAYS_INLINE void OnFree(uptr ptr, uptr class_id, uptr size) { FakeStack::Deallocate(ptr, class_id); SetShadow(ptr, size, class_id, kMagic8); } } // namespace __asan // ---------------------- Interface ---------------- {{{1 using namespace __asan; #define DEFINE_STACK_MALLOC_FREE_WITH_CLASS_ID(class_id) \ extern "C" SANITIZER_INTERFACE_ATTRIBUTE uptr \ __asan_stack_malloc_##class_id(uptr size) { \ return OnMalloc(class_id, size); \ } \ extern "C" SANITIZER_INTERFACE_ATTRIBUTE void __asan_stack_free_##class_id( \ uptr ptr, uptr size) { \ OnFree(ptr, class_id, size); \ } DEFINE_STACK_MALLOC_FREE_WITH_CLASS_ID(0) DEFINE_STACK_MALLOC_FREE_WITH_CLASS_ID(1) DEFINE_STACK_MALLOC_FREE_WITH_CLASS_ID(2) DEFINE_STACK_MALLOC_FREE_WITH_CLASS_ID(3) DEFINE_STACK_MALLOC_FREE_WITH_CLASS_ID(4) DEFINE_STACK_MALLOC_FREE_WITH_CLASS_ID(5) DEFINE_STACK_MALLOC_FREE_WITH_CLASS_ID(6) DEFINE_STACK_MALLOC_FREE_WITH_CLASS_ID(7) DEFINE_STACK_MALLOC_FREE_WITH_CLASS_ID(8) DEFINE_STACK_MALLOC_FREE_WITH_CLASS_ID(9) DEFINE_STACK_MALLOC_FREE_WITH_CLASS_ID(10) extern "C" { SANITIZER_INTERFACE_ATTRIBUTE void *__asan_get_current_fake_stack() { return GetFakeStackFast(); } SANITIZER_INTERFACE_ATTRIBUTE void *__asan_addr_is_in_fake_stack(void *fake_stack, void *addr, void **beg, void **end) { FakeStack *fs = reinterpret_cast(fake_stack); if (!fs) return nullptr; uptr frame_beg, frame_end; FakeFrame *frame = reinterpret_cast(fs->AddrIsInFakeStack( reinterpret_cast(addr), &frame_beg, &frame_end)); if (!frame) return nullptr; if (frame->magic != kCurrentStackFrameMagic) return nullptr; if (beg) *beg = reinterpret_cast(frame_beg); if (end) *end = reinterpret_cast(frame_end); return reinterpret_cast(frame->real_stack); } SANITIZER_INTERFACE_ATTRIBUTE void __asan_alloca_poison(uptr addr, uptr size) { uptr LeftRedzoneAddr = addr - kAllocaRedzoneSize; uptr PartialRzAddr = addr + size; uptr RightRzAddr = (PartialRzAddr + kAllocaRedzoneMask) & ~kAllocaRedzoneMask; uptr PartialRzAligned = PartialRzAddr & ~(SHADOW_GRANULARITY - 1); FastPoisonShadow(LeftRedzoneAddr, kAllocaRedzoneSize, kAsanAllocaLeftMagic); FastPoisonShadowPartialRightRedzone( PartialRzAligned, PartialRzAddr % SHADOW_GRANULARITY, RightRzAddr - PartialRzAligned, kAsanAllocaRightMagic); FastPoisonShadow(RightRzAddr, kAllocaRedzoneSize, kAsanAllocaRightMagic); } SANITIZER_INTERFACE_ATTRIBUTE void __asan_allocas_unpoison(uptr top, uptr bottom) { if ((!top) || (top > bottom)) return; REAL(memset)(reinterpret_cast(MemToShadow(top)), 0, (bottom - top) / SHADOW_GRANULARITY); } } // extern "C" Index: projects/clang400-import/contrib/compiler-rt/lib/asan/asan_fake_stack.h =================================================================== --- projects/clang400-import/contrib/compiler-rt/lib/asan/asan_fake_stack.h (revision 311696) +++ projects/clang400-import/contrib/compiler-rt/lib/asan/asan_fake_stack.h (revision 311697) @@ -1,176 +1,176 @@ //===-- asan_fake_stack.h ---------------------------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // This file is a part of AddressSanitizer, an address sanity checker. // // ASan-private header for asan_fake_stack.cc, implements FakeStack. //===----------------------------------------------------------------------===// #ifndef ASAN_FAKE_STACK_H #define ASAN_FAKE_STACK_H #include "sanitizer_common/sanitizer_common.h" namespace __asan { // Fake stack frame contains local variables of one function. struct FakeFrame { uptr magic; // Modified by the instrumented code. uptr descr; // Modified by the instrumented code. uptr pc; // Modified by the instrumented code. uptr real_stack; }; // For each thread we create a fake stack and place stack objects on this fake // stack instead of the real stack. The fake stack is not really a stack but // a fast malloc-like allocator so that when a function exits the fake stack // is not popped but remains there for quite some time until gets used again. // So, we poison the objects on the fake stack when function returns. // It helps us find use-after-return bugs. // // The FakeStack objects is allocated by a single mmap call and has no other // pointers. The size of the fake stack depends on the actual thread stack size // and thus can not be a constant. // stack_size is a power of two greater or equal to the thread's stack size; // we store it as its logarithm (stack_size_log). // FakeStack has kNumberOfSizeClasses (11) size classes, each size class // is a power of two, starting from 64 bytes. Each size class occupies // stack_size bytes and thus can allocate // NumberOfFrames=(stack_size/BytesInSizeClass) fake frames (also a power of 2). // For each size class we have NumberOfFrames allocation flags, // each flag indicates whether the given frame is currently allocated. // All flags for size classes 0 .. 10 are stored in a single contiguous region // followed by another contiguous region which contains the actual memory for // size classes. The addresses are computed by GetFlags and GetFrame without // any memory accesses solely based on 'this' and stack_size_log. // Allocate() flips the appropriate allocation flag atomically, thus achieving // async-signal safety. // This allocator does not have quarantine per se, but it tries to allocate the -// frames in round robin fasion to maximize the delay between a deallocation +// frames in round robin fashion to maximize the delay between a deallocation // and the next allocation. class FakeStack { static const uptr kMinStackFrameSizeLog = 6; // Min frame is 64B. static const uptr kMaxStackFrameSizeLog = 16; // Max stack frame is 64K. public: static const uptr kNumberOfSizeClasses = kMaxStackFrameSizeLog - kMinStackFrameSizeLog + 1; // CTOR: create the FakeStack as a single mmap-ed object. static FakeStack *Create(uptr stack_size_log); void Destroy(int tid); // stack_size_log is at least 15 (stack_size >= 32K). static uptr SizeRequiredForFlags(uptr stack_size_log) { return ((uptr)1) << (stack_size_log + 1 - kMinStackFrameSizeLog); } // Each size class occupies stack_size bytes. static uptr SizeRequiredForFrames(uptr stack_size_log) { return (((uptr)1) << stack_size_log) * kNumberOfSizeClasses; } // Number of bytes requires for the whole object. static uptr RequiredSize(uptr stack_size_log) { return kFlagsOffset + SizeRequiredForFlags(stack_size_log) + SizeRequiredForFrames(stack_size_log); } // Offset of the given flag from the first flag. // The flags for class 0 begin at offset 000000000 // The flags for class 1 begin at offset 100000000 // ....................2................ 110000000 // ....................3................ 111000000 // and so on. static uptr FlagsOffset(uptr stack_size_log, uptr class_id) { uptr t = kNumberOfSizeClasses - 1 - class_id; const uptr all_ones = (((uptr)1) << (kNumberOfSizeClasses - 1)) - 1; return ((all_ones >> t) << t) << (stack_size_log - 15); } static uptr NumberOfFrames(uptr stack_size_log, uptr class_id) { return ((uptr)1) << (stack_size_log - kMinStackFrameSizeLog - class_id); } - // Divide n by the numbe of frames in size class. + // Divide n by the number of frames in size class. static uptr ModuloNumberOfFrames(uptr stack_size_log, uptr class_id, uptr n) { return n & (NumberOfFrames(stack_size_log, class_id) - 1); } - // The the pointer to the flags of the given class_id. + // The pointer to the flags of the given class_id. u8 *GetFlags(uptr stack_size_log, uptr class_id) { return reinterpret_cast(this) + kFlagsOffset + FlagsOffset(stack_size_log, class_id); } // Get frame by class_id and pos. u8 *GetFrame(uptr stack_size_log, uptr class_id, uptr pos) { return reinterpret_cast(this) + kFlagsOffset + SizeRequiredForFlags(stack_size_log) + (((uptr)1) << stack_size_log) * class_id + BytesInSizeClass(class_id) * pos; } // Allocate the fake frame. FakeFrame *Allocate(uptr stack_size_log, uptr class_id, uptr real_stack); // Deallocate the fake frame: read the saved flag address and write 0 there. static void Deallocate(uptr x, uptr class_id) { **SavedFlagPtr(x, class_id) = 0; } // Poison the entire FakeStack's shadow with the magic value. void PoisonAll(u8 magic); // Return the beginning of the FakeFrame or 0 if the address is not ours. uptr AddrIsInFakeStack(uptr addr, uptr *frame_beg, uptr *frame_end); USED uptr AddrIsInFakeStack(uptr addr) { uptr t1, t2; return AddrIsInFakeStack(addr, &t1, &t2); } // Number of bytes in a fake frame of this size class. static uptr BytesInSizeClass(uptr class_id) { return ((uptr)1) << (class_id + kMinStackFrameSizeLog); } // The fake frame is guaranteed to have a right redzone. // We use the last word of that redzone to store the address of the flag // that corresponds to the current frame to make faster deallocation. static u8 **SavedFlagPtr(uptr x, uptr class_id) { return reinterpret_cast(x + BytesInSizeClass(class_id) - sizeof(x)); } uptr stack_size_log() const { return stack_size_log_; } void HandleNoReturn(); void GC(uptr real_stack); void ForEachFakeFrame(RangeIteratorCallback callback, void *arg); private: FakeStack() { } static const uptr kFlagsOffset = 4096; // This is were the flags begin. // Must match the number of uses of DEFINE_STACK_MALLOC_FREE_WITH_CLASS_ID COMPILER_CHECK(kNumberOfSizeClasses == 11); static const uptr kMaxStackMallocSize = ((uptr)1) << kMaxStackFrameSizeLog; uptr hint_position_[kNumberOfSizeClasses]; uptr stack_size_log_; // a bit is set if something was allocated from the corresponding size class. bool needs_gc_; }; FakeStack *GetTLSFakeStack(); void SetTLSFakeStack(FakeStack *fs); } // namespace __asan #endif // ASAN_FAKE_STACK_H Index: projects/clang400-import/contrib/compiler-rt/lib/asan/asan_flags.cc =================================================================== --- projects/clang400-import/contrib/compiler-rt/lib/asan/asan_flags.cc (revision 311696) +++ projects/clang400-import/contrib/compiler-rt/lib/asan/asan_flags.cc (revision 311697) @@ -1,179 +1,189 @@ //===-- asan_flags.cc -------------------------------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // This file is a part of AddressSanitizer, an address sanity checker. // // ASan flag parsing logic. //===----------------------------------------------------------------------===// #include "asan_activation.h" #include "asan_flags.h" #include "asan_interface_internal.h" #include "asan_stack.h" #include "lsan/lsan_common.h" #include "sanitizer_common/sanitizer_common.h" #include "sanitizer_common/sanitizer_flags.h" #include "sanitizer_common/sanitizer_flag_parser.h" #include "ubsan/ubsan_flags.h" #include "ubsan/ubsan_platform.h" namespace __asan { Flags asan_flags_dont_use_directly; // use via flags(). static const char *MaybeCallAsanDefaultOptions() { return (&__asan_default_options) ? __asan_default_options() : ""; } static const char *MaybeUseAsanDefaultOptionsCompileDefinition() { #ifdef ASAN_DEFAULT_OPTIONS // Stringize the macro value. # define ASAN_STRINGIZE(x) #x # define ASAN_STRINGIZE_OPTIONS(options) ASAN_STRINGIZE(options) return ASAN_STRINGIZE_OPTIONS(ASAN_DEFAULT_OPTIONS); #else return ""; #endif } void Flags::SetDefaults() { #define ASAN_FLAG(Type, Name, DefaultValue, Description) Name = DefaultValue; #include "asan_flags.inc" #undef ASAN_FLAG } static void RegisterAsanFlags(FlagParser *parser, Flags *f) { #define ASAN_FLAG(Type, Name, DefaultValue, Description) \ RegisterFlag(parser, #Name, Description, &f->Name); #include "asan_flags.inc" #undef ASAN_FLAG } void InitializeFlags() { // Set the default values and prepare for parsing ASan and common flags. SetCommonFlagsDefaults(); { CommonFlags cf; cf.CopyFrom(*common_flags()); cf.detect_leaks = CAN_SANITIZE_LEAKS; cf.external_symbolizer_path = GetEnv("ASAN_SYMBOLIZER_PATH"); cf.malloc_context_size = kDefaultMallocContextSize; cf.intercept_tls_get_addr = true; cf.exitcode = 1; OverrideCommonFlags(cf); } Flags *f = flags(); f->SetDefaults(); FlagParser asan_parser; RegisterAsanFlags(&asan_parser, f); RegisterCommonFlags(&asan_parser); // Set the default values and prepare for parsing LSan and UBSan flags // (which can also overwrite common flags). #if CAN_SANITIZE_LEAKS __lsan::Flags *lf = __lsan::flags(); lf->SetDefaults(); FlagParser lsan_parser; __lsan::RegisterLsanFlags(&lsan_parser, lf); RegisterCommonFlags(&lsan_parser); #endif #if CAN_SANITIZE_UB __ubsan::Flags *uf = __ubsan::flags(); uf->SetDefaults(); FlagParser ubsan_parser; __ubsan::RegisterUbsanFlags(&ubsan_parser, uf); RegisterCommonFlags(&ubsan_parser); #endif // Override from ASan compile definition. const char *asan_compile_def = MaybeUseAsanDefaultOptionsCompileDefinition(); asan_parser.ParseString(asan_compile_def); // Override from user-specified string. const char *asan_default_options = MaybeCallAsanDefaultOptions(); asan_parser.ParseString(asan_default_options); #if CAN_SANITIZE_UB const char *ubsan_default_options = __ubsan::MaybeCallUbsanDefaultOptions(); ubsan_parser.ParseString(ubsan_default_options); #endif // Override from command line. asan_parser.ParseString(GetEnv("ASAN_OPTIONS")); #if CAN_SANITIZE_LEAKS lsan_parser.ParseString(GetEnv("LSAN_OPTIONS")); #endif #if CAN_SANITIZE_UB ubsan_parser.ParseString(GetEnv("UBSAN_OPTIONS")); #endif InitializeCommonFlags(); // TODO(eugenis): dump all flags at verbosity>=2? if (Verbosity()) ReportUnrecognizedFlags(); if (common_flags()->help) { // TODO(samsonov): print all of the flags (ASan, LSan, common). asan_parser.PrintFlagDescriptions(); } // Flag validation: if (!CAN_SANITIZE_LEAKS && common_flags()->detect_leaks) { Report("%s: detect_leaks is not supported on this platform.\n", SanitizerToolName); Die(); } // Make "strict_init_order" imply "check_initialization_order". // TODO(samsonov): Use a single runtime flag for an init-order checker. if (f->strict_init_order) { f->check_initialization_order = true; } CHECK_LE((uptr)common_flags()->malloc_context_size, kStackTraceMax); CHECK_LE(f->min_uar_stack_size_log, f->max_uar_stack_size_log); CHECK_GE(f->redzone, 16); CHECK_GE(f->max_redzone, f->redzone); CHECK_LE(f->max_redzone, 2048); CHECK(IsPowerOfTwo(f->redzone)); CHECK(IsPowerOfTwo(f->max_redzone)); // quarantine_size is deprecated but we still honor it. // quarantine_size can not be used together with quarantine_size_mb. if (f->quarantine_size >= 0 && f->quarantine_size_mb >= 0) { Report("%s: please use either 'quarantine_size' (deprecated) or " "quarantine_size_mb, but not both\n", SanitizerToolName); Die(); } if (f->quarantine_size >= 0) f->quarantine_size_mb = f->quarantine_size >> 20; if (f->quarantine_size_mb < 0) { const int kDefaultQuarantineSizeMb = - (ASAN_LOW_MEMORY) ? 1UL << 6 : 1UL << 8; + (ASAN_LOW_MEMORY) ? 1UL << 4 : 1UL << 8; f->quarantine_size_mb = kDefaultQuarantineSizeMb; + } + if (f->thread_local_quarantine_size_kb < 0) { + const u32 kDefaultThreadLocalQuarantineSizeKb = + // It is not advised to go lower than 64Kb, otherwise quarantine batches + // pushed from thread local quarantine to global one will create too + // much overhead. One quarantine batch size is 8Kb and it holds up to + // 1021 chunk, which amounts to 1/8 memory overhead per batch when + // thread local quarantine is set to 64Kb. + (ASAN_LOW_MEMORY) ? 1 << 6 : FIRST_32_SECOND_64(1 << 8, 1 << 10); + f->thread_local_quarantine_size_kb = kDefaultThreadLocalQuarantineSizeKb; } if (!f->replace_str && common_flags()->intercept_strlen) { Report("WARNING: strlen interceptor is enabled even though replace_str=0. " "Use intercept_strlen=0 to disable it."); } if (!f->replace_str && common_flags()->intercept_strchr) { Report("WARNING: strchr* interceptors are enabled even though " "replace_str=0. Use intercept_strchr=0 to disable them."); } } } // namespace __asan #if !SANITIZER_SUPPORTS_WEAK_HOOKS extern "C" { SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE const char* __asan_default_options() { return ""; } } // extern "C" #endif Index: projects/clang400-import/contrib/compiler-rt/lib/asan/asan_flags.inc =================================================================== --- projects/clang400-import/contrib/compiler-rt/lib/asan/asan_flags.inc (revision 311696) +++ projects/clang400-import/contrib/compiler-rt/lib/asan/asan_flags.inc (revision 311697) @@ -1,141 +1,150 @@ //===-- asan_flags.inc ------------------------------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // ASan runtime flags. // //===----------------------------------------------------------------------===// #ifndef ASAN_FLAG # error "Define ASAN_FLAG prior to including this file!" #endif // ASAN_FLAG(Type, Name, DefaultValue, Description) // See COMMON_FLAG in sanitizer_flags.inc for more details. ASAN_FLAG(int, quarantine_size, -1, "Deprecated, please use quarantine_size_mb.") ASAN_FLAG(int, quarantine_size_mb, -1, "Size (in Mb) of quarantine used to detect use-after-free " "errors. Lower value may reduce memory usage but increase the " "chance of false negatives.") +ASAN_FLAG(int, thread_local_quarantine_size_kb, -1, + "Size (in Kb) of thread local quarantine used to detect " + "use-after-free errors. Lower value may reduce memory usage but " + "increase the chance of false negatives. It is not advised to go " + "lower than 64Kb, otherwise frequent transfers to global quarantine " + "might affect performance.") ASAN_FLAG(int, redzone, 16, "Minimal size (in bytes) of redzones around heap objects. " "Requirement: redzone >= 16, is a power of two.") ASAN_FLAG(int, max_redzone, 2048, "Maximal size (in bytes) of redzones around heap objects.") ASAN_FLAG( bool, debug, false, "If set, prints some debugging information and does additional checks.") ASAN_FLAG( int, report_globals, 1, "Controls the way to handle globals (0 - don't detect buffer overflow on " "globals, 1 - detect buffer overflow, 2 - print data about registered " "globals).") ASAN_FLAG(bool, check_initialization_order, false, "If set, attempts to catch initialization order issues.") ASAN_FLAG( bool, replace_str, true, "If set, uses custom wrappers and replacements for libc string functions " "to find more errors.") ASAN_FLAG(bool, replace_intrin, true, "If set, uses custom wrappers for memset/memcpy/memmove intrinsics.") ASAN_FLAG(bool, detect_stack_use_after_return, false, "Enables stack-use-after-return checking at run-time.") ASAN_FLAG(int, min_uar_stack_size_log, 16, // We can't do smaller anyway. "Minimum fake stack size log.") ASAN_FLAG(int, max_uar_stack_size_log, 20, // 1Mb per size class, i.e. ~11Mb per thread "Maximum fake stack size log.") ASAN_FLAG(bool, uar_noreserve, false, "Use mmap with 'noreserve' flag to allocate fake stack.") ASAN_FLAG( int, max_malloc_fill_size, 0x1000, // By default, fill only the first 4K. "ASan allocator flag. max_malloc_fill_size is the maximal amount of " "bytes that will be filled with malloc_fill_byte on malloc.") ASAN_FLAG(int, malloc_fill_byte, 0xbe, "Value used to fill the newly allocated memory.") ASAN_FLAG(bool, allow_user_poisoning, true, "If set, user may manually mark memory regions as poisoned or " "unpoisoned.") ASAN_FLAG( int, sleep_before_dying, 0, "Number of seconds to sleep between printing an error report and " "terminating the program. Useful for debugging purposes (e.g. when one " "needs to attach gdb).") ASAN_FLAG(bool, check_malloc_usable_size, true, "Allows the users to work around the bug in Nvidia drivers prior to " "295.*.") ASAN_FLAG(bool, unmap_shadow_on_exit, false, "If set, explicitly unmaps the (huge) shadow at exit.") ASAN_FLAG(bool, protect_shadow_gap, true, "If set, mprotect the shadow gap") ASAN_FLAG(bool, print_stats, false, "Print various statistics after printing an error message or if " "atexit=1.") ASAN_FLAG(bool, print_legend, true, "Print the legend for the shadow bytes.") ASAN_FLAG(bool, print_scariness, false, "Print the scariness score. Experimental.") ASAN_FLAG(bool, atexit, false, "If set, prints ASan exit stats even after program terminates " "successfully.") ASAN_FLAG( bool, print_full_thread_history, true, "If set, prints thread creation stacks for the threads involved in the " "report and their ancestors up to the main thread.") ASAN_FLAG( bool, poison_heap, true, "Poison (or not) the heap memory on [de]allocation. Zero value is useful " "for benchmarking the allocator or instrumentator.") ASAN_FLAG(bool, poison_partial, true, "If true, poison partially addressable 8-byte aligned words " "(default=true). This flag affects heap and global buffers, but not " "stack buffers.") ASAN_FLAG(bool, poison_array_cookie, true, "Poison (or not) the array cookie after operator new[].") // Turn off alloc/dealloc mismatch checker on Mac and Windows for now. // https://github.com/google/sanitizers/issues/131 // https://github.com/google/sanitizers/issues/309 // TODO(glider,timurrrr): Fix known issues and enable this back. ASAN_FLAG(bool, alloc_dealloc_mismatch, - (SANITIZER_MAC == 0) && (SANITIZER_WINDOWS == 0), + !SANITIZER_MAC && !SANITIZER_WINDOWS && !SANITIZER_ANDROID, "Report errors on malloc/delete, new/free, new/delete[], etc.") ASAN_FLAG(bool, new_delete_type_mismatch, true, "Report errors on mismatch between size of new and delete.") ASAN_FLAG( bool, strict_init_order, false, "If true, assume that dynamic initializers can never access globals from " "other modules, even if the latter are already initialized.") ASAN_FLAG( bool, start_deactivated, false, "If true, ASan tweaks a bunch of other flags (quarantine, redzone, heap " "poisoning) to reduce memory consumption as much as possible, and " "restores them to original values when the first instrumented module is " "loaded into the process. This is mainly intended to be used on " "Android. ") ASAN_FLAG( int, detect_invalid_pointer_pairs, 0, "If non-zero, try to detect operations like <, <=, >, >= and - on " "invalid pointer pairs (e.g. when pointers belong to different objects). " "The bigger the value the harder we try.") ASAN_FLAG( bool, detect_container_overflow, true, "If true, honor the container overflow annotations. See " "https://github.com/google/sanitizers/wiki/AddressSanitizerContainerOverflow") ASAN_FLAG(int, detect_odr_violation, 2, "If >=2, detect violation of One-Definition-Rule (ODR); " "If ==1, detect ODR-violation only if the two variables " "have different sizes") ASAN_FLAG(bool, dump_instruction_bytes, false, "If true, dump 16 bytes starting at the instruction that caused SEGV") +ASAN_FLAG(bool, dump_registers, true, + "If true, dump values of CPU registers when SEGV happens. Only " + "available on OS X for now.") ASAN_FLAG(const char *, suppressions, "", "Suppressions file name.") ASAN_FLAG(bool, halt_on_error, true, "Crash the program after printing the first error report " "(WARNING: USE AT YOUR OWN RISK!)") ASAN_FLAG(bool, use_odr_indicator, false, "Use special ODR indicator symbol for ODR violation detection") Index: projects/clang400-import/contrib/compiler-rt/lib/asan/asan_globals.cc =================================================================== --- projects/clang400-import/contrib/compiler-rt/lib/asan/asan_globals.cc (revision 311696) +++ projects/clang400-import/contrib/compiler-rt/lib/asan/asan_globals.cc (revision 311697) @@ -1,383 +1,432 @@ //===-- asan_globals.cc ---------------------------------------------------===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // This file is a part of AddressSanitizer, an address sanity checker. // // Handle globals. //===----------------------------------------------------------------------===// #include "asan_interceptors.h" #include "asan_internal.h" #include "asan_mapping.h" #include "asan_poisoning.h" #include "asan_report.h" #include "asan_stack.h" #include "asan_stats.h" #include "asan_suppressions.h" #include "asan_thread.h" #include "sanitizer_common/sanitizer_common.h" #include "sanitizer_common/sanitizer_mutex.h" #include "sanitizer_common/sanitizer_placement_new.h" #include "sanitizer_common/sanitizer_stackdepot.h" +#include "sanitizer_common/sanitizer_symbolizer.h" namespace __asan { typedef __asan_global Global; struct ListOfGlobals { const Global *g; ListOfGlobals *next; }; static BlockingMutex mu_for_globals(LINKER_INITIALIZED); static LowLevelAllocator allocator_for_globals; static ListOfGlobals *list_of_all_globals; static const int kDynamicInitGlobalsInitialCapacity = 512; struct DynInitGlobal { Global g; bool initialized; }; typedef InternalMmapVector VectorOfGlobals; // Lazy-initialized and never deleted. static VectorOfGlobals *dynamic_init_globals; // We want to remember where a certain range of globals was registered. struct GlobalRegistrationSite { u32 stack_id; Global *g_first, *g_last; }; typedef InternalMmapVector GlobalRegistrationSiteVector; static GlobalRegistrationSiteVector *global_registration_site_vector; ALWAYS_INLINE void PoisonShadowForGlobal(const Global *g, u8 value) { FastPoisonShadow(g->beg, g->size_with_redzone, value); } ALWAYS_INLINE void PoisonRedZones(const Global &g) { uptr aligned_size = RoundUpTo(g.size, SHADOW_GRANULARITY); FastPoisonShadow(g.beg + aligned_size, g.size_with_redzone - aligned_size, kAsanGlobalRedzoneMagic); if (g.size != aligned_size) { FastPoisonShadowPartialRightRedzone( g.beg + RoundDownTo(g.size, SHADOW_GRANULARITY), g.size % SHADOW_GRANULARITY, SHADOW_GRANULARITY, kAsanGlobalRedzoneMagic); } } const uptr kMinimalDistanceFromAnotherGlobal = 64; static bool IsAddressNearGlobal(uptr addr, const __asan_global &g) { if (addr <= g.beg - kMinimalDistanceFromAnotherGlobal) return false; if (addr >= g.beg + g.size_with_redzone) return false; return true; } static void ReportGlobal(const Global &g, const char *prefix) { Report("%s Global[%p]: beg=%p size=%zu/%zu name=%s module=%s dyn_init=%zu\n", prefix, &g, (void *)g.beg, g.size, g.size_with_redzone, g.name, g.module_name, g.has_dynamic_init); if (g.location) { Report(" location (%p): name=%s[%p], %d %d\n", g.location, g.location->filename, g.location->filename, g.location->line_no, g.location->column_no); } } static u32 FindRegistrationSite(const Global *g) { mu_for_globals.CheckLocked(); CHECK(global_registration_site_vector); for (uptr i = 0, n = global_registration_site_vector->size(); i < n; i++) { GlobalRegistrationSite &grs = (*global_registration_site_vector)[i]; if (g >= grs.g_first && g <= grs.g_last) return grs.stack_id; } return 0; } int GetGlobalsForAddress(uptr addr, Global *globals, u32 *reg_sites, int max_globals) { if (!flags()->report_globals) return 0; BlockingMutexLock lock(&mu_for_globals); int res = 0; for (ListOfGlobals *l = list_of_all_globals; l; l = l->next) { const Global &g = *l->g; if (flags()->report_globals >= 2) ReportGlobal(g, "Search"); if (IsAddressNearGlobal(addr, g)) { globals[res] = g; if (reg_sites) reg_sites[res] = FindRegistrationSite(&g); res++; if (res == max_globals) break; } } return res; } -bool GetInfoForAddressIfGlobal(uptr addr, AddressDescription *descr) { - Global g = {}; - if (GetGlobalsForAddress(addr, &g, nullptr, 1)) { - internal_strncpy(descr->name, g.name, descr->name_size); - descr->region_address = g.beg; - descr->region_size = g.size; - descr->region_kind = "global"; - return true; - } - return false; -} - enum GlobalSymbolState { UNREGISTERED = 0, REGISTERED = 1 }; // Check ODR violation for given global G via special ODR indicator. We use // this method in case compiler instruments global variables through their // local aliases. static void CheckODRViolationViaIndicator(const Global *g) { u8 *odr_indicator = reinterpret_cast(g->odr_indicator); if (*odr_indicator == UNREGISTERED) { *odr_indicator = REGISTERED; return; } // If *odr_indicator is DEFINED, some module have already registered // externally visible symbol with the same name. This is an ODR violation. for (ListOfGlobals *l = list_of_all_globals; l; l = l->next) { if (g->odr_indicator == l->g->odr_indicator && (flags()->detect_odr_violation >= 2 || g->size != l->g->size) && !IsODRViolationSuppressed(g->name)) ReportODRViolation(g, FindRegistrationSite(g), l->g, FindRegistrationSite(l->g)); } } // Check ODR violation for given global G by checking if it's already poisoned. // We use this method in case compiler doesn't use private aliases for global // variables. static void CheckODRViolationViaPoisoning(const Global *g) { if (__asan_region_is_poisoned(g->beg, g->size_with_redzone)) { // This check may not be enough: if the first global is much larger // the entire redzone of the second global may be within the first global. for (ListOfGlobals *l = list_of_all_globals; l; l = l->next) { if (g->beg == l->g->beg && (flags()->detect_odr_violation >= 2 || g->size != l->g->size) && !IsODRViolationSuppressed(g->name)) ReportODRViolation(g, FindRegistrationSite(g), l->g, FindRegistrationSite(l->g)); } } } // Clang provides two different ways for global variables protection: // it can poison the global itself or its private alias. In former // case we may poison same symbol multiple times, that can help us to // cheaply detect ODR violation: if we try to poison an already poisoned // global, we have ODR violation error. // In latter case, we poison each symbol exactly once, so we use special // indicator symbol to perform similar check. // In either case, compiler provides a special odr_indicator field to Global // structure, that can contain two kinds of values: // 1) Non-zero value. In this case, odr_indicator is an address of // corresponding indicator variable for given global. // 2) Zero. This means that we don't use private aliases for global variables // and can freely check ODR violation with the first method. // // This routine chooses between two different methods of ODR violation // detection. static inline bool UseODRIndicator(const Global *g) { // Use ODR indicator method iff use_odr_indicator flag is set and // indicator symbol address is not 0. return flags()->use_odr_indicator && g->odr_indicator > 0; } // Register a global variable. // This function may be called more than once for every global // so we store the globals in a map. static void RegisterGlobal(const Global *g) { CHECK(asan_inited); if (flags()->report_globals >= 2) ReportGlobal(*g, "Added"); CHECK(flags()->report_globals); CHECK(AddrIsInMem(g->beg)); if (!AddrIsAlignedByGranularity(g->beg)) { Report("The following global variable is not properly aligned.\n"); Report("This may happen if another global with the same name\n"); Report("resides in another non-instrumented module.\n"); Report("Or the global comes from a C file built w/o -fno-common.\n"); Report("In either case this is likely an ODR violation bug,\n"); Report("but AddressSanitizer can not provide more details.\n"); ReportODRViolation(g, FindRegistrationSite(g), g, FindRegistrationSite(g)); CHECK(AddrIsAlignedByGranularity(g->beg)); } CHECK(AddrIsAlignedByGranularity(g->size_with_redzone)); if (flags()->detect_odr_violation) { // Try detecting ODR (One Definition Rule) violation, i.e. the situation // where two globals with the same name are defined in different modules. if (UseODRIndicator(g)) CheckODRViolationViaIndicator(g); else CheckODRViolationViaPoisoning(g); } if (CanPoisonMemory()) PoisonRedZones(*g); ListOfGlobals *l = new(allocator_for_globals) ListOfGlobals; l->g = g; l->next = list_of_all_globals; list_of_all_globals = l; if (g->has_dynamic_init) { if (!dynamic_init_globals) { dynamic_init_globals = new(allocator_for_globals) VectorOfGlobals(kDynamicInitGlobalsInitialCapacity); } DynInitGlobal dyn_global = { *g, false }; dynamic_init_globals->push_back(dyn_global); } } static void UnregisterGlobal(const Global *g) { CHECK(asan_inited); if (flags()->report_globals >= 2) ReportGlobal(*g, "Removed"); CHECK(flags()->report_globals); CHECK(AddrIsInMem(g->beg)); CHECK(AddrIsAlignedByGranularity(g->beg)); CHECK(AddrIsAlignedByGranularity(g->size_with_redzone)); if (CanPoisonMemory()) PoisonShadowForGlobal(g, 0); // We unpoison the shadow memory for the global but we do not remove it from // the list because that would require O(n^2) time with the current list // implementation. It might not be worth doing anyway. // Release ODR indicator. if (UseODRIndicator(g)) { u8 *odr_indicator = reinterpret_cast(g->odr_indicator); *odr_indicator = UNREGISTERED; } } void StopInitOrderChecking() { BlockingMutexLock lock(&mu_for_globals); if (!flags()->check_initialization_order || !dynamic_init_globals) return; flags()->check_initialization_order = false; for (uptr i = 0, n = dynamic_init_globals->size(); i < n; ++i) { DynInitGlobal &dyn_g = (*dynamic_init_globals)[i]; const Global *g = &dyn_g.g; // Unpoison the whole global. PoisonShadowForGlobal(g, 0); // Poison redzones back. PoisonRedZones(*g); } } +static bool IsASCII(unsigned char c) { return /*0x00 <= c &&*/ c <= 0x7F; } + +const char *MaybeDemangleGlobalName(const char *name) { + // We can spoil names of globals with C linkage, so use an heuristic + // approach to check if the name should be demangled. + bool should_demangle = false; + if (name[0] == '_' && name[1] == 'Z') + should_demangle = true; + else if (SANITIZER_WINDOWS && name[0] == '\01' && name[1] == '?') + should_demangle = true; + + return should_demangle ? Symbolizer::GetOrInit()->Demangle(name) : name; +} + +// Check if the global is a zero-terminated ASCII string. If so, print it. +void PrintGlobalNameIfASCII(InternalScopedString *str, const __asan_global &g) { + for (uptr p = g.beg; p < g.beg + g.size - 1; p++) { + unsigned char c = *(unsigned char *)p; + if (c == '\0' || !IsASCII(c)) return; + } + if (*(char *)(g.beg + g.size - 1) != '\0') return; + str->append(" '%s' is ascii string '%s'\n", MaybeDemangleGlobalName(g.name), + (char *)g.beg); +} + +static const char *GlobalFilename(const __asan_global &g) { + const char *res = g.module_name; + // Prefer the filename from source location, if is available. + if (g.location) res = g.location->filename; + CHECK(res); + return res; +} + +void PrintGlobalLocation(InternalScopedString *str, const __asan_global &g) { + str->append("%s", GlobalFilename(g)); + if (!g.location) return; + if (g.location->line_no) str->append(":%d", g.location->line_no); + if (g.location->column_no) str->append(":%d", g.location->column_no); +} + } // namespace __asan // ---------------------- Interface ---------------- {{{1 using namespace __asan; // NOLINT // Apply __asan_register_globals to all globals found in the same loaded // executable or shared library as `flag'. The flag tracks whether globals have // already been registered or not for this image. void __asan_register_image_globals(uptr *flag) { if (*flag) return; AsanApplyToGlobals(__asan_register_globals, flag); *flag = 1; } // This mirrors __asan_register_image_globals. void __asan_unregister_image_globals(uptr *flag) { if (!*flag) return; AsanApplyToGlobals(__asan_unregister_globals, flag); *flag = 0; } // Register an array of globals. void __asan_register_globals(__asan_global *globals, uptr n) { if (!flags()->report_globals) return; GET_STACK_TRACE_MALLOC; u32 stack_id = StackDepotPut(stack); BlockingMutexLock lock(&mu_for_globals); if (!global_registration_site_vector) global_registration_site_vector = new(allocator_for_globals) GlobalRegistrationSiteVector(128); GlobalRegistrationSite site = {stack_id, &globals[0], &globals[n - 1]}; global_registration_site_vector->push_back(site); if (flags()->report_globals >= 2) { PRINT_CURRENT_STACK(); Printf("=== ID %d; %p %p\n", stack_id, &globals[0], &globals[n - 1]); } for (uptr i = 0; i < n; i++) { + if (SANITIZER_WINDOWS && globals[i].beg == 0) { + // The MSVC incremental linker may pad globals out to 256 bytes. As long + // as __asan_global is less than 256 bytes large and its size is a power + // of two, we can skip over the padding. + static_assert( + sizeof(__asan_global) < 256 && + (sizeof(__asan_global) & (sizeof(__asan_global) - 1)) == 0, + "sizeof(__asan_global) incompatible with incremental linker padding"); + // If these are padding bytes, the rest of the global should be zero. + CHECK(globals[i].size == 0 && globals[i].size_with_redzone == 0 && + globals[i].name == nullptr && globals[i].module_name == nullptr && + globals[i].odr_indicator == 0); + continue; + } RegisterGlobal(&globals[i]); } } // Unregister an array of globals. // We must do this when a shared objects gets dlclosed. void __asan_unregister_globals(__asan_global *globals, uptr n) { if (!flags()->report_globals) return; BlockingMutexLock lock(&mu_for_globals); for (uptr i = 0; i < n; i++) { + if (SANITIZER_WINDOWS && globals[i].beg == 0) { + // Skip globals that look like padding from the MSVC incremental linker. + // See comment in __asan_register_globals. + continue; + } UnregisterGlobal(&globals[i]); } } // This method runs immediately prior to dynamic initialization in each TU, // when all dynamically initialized globals are unpoisoned. This method // poisons all global variables not defined in this TU, so that a dynamic // initializer can only touch global variables in the same TU. void __asan_before_dynamic_init(const char *module_name) { if (!flags()->check_initialization_order || - !CanPoisonMemory()) + !CanPoisonMemory() || + !dynamic_init_globals) return; bool strict_init_order = flags()->strict_init_order; - CHECK(dynamic_init_globals); CHECK(module_name); CHECK(asan_inited); BlockingMutexLock lock(&mu_for_globals); if (flags()->report_globals >= 3) Printf("DynInitPoison module: %s\n", module_name); for (uptr i = 0, n = dynamic_init_globals->size(); i < n; ++i) { DynInitGlobal &dyn_g = (*dynamic_init_globals)[i]; const Global *g = &dyn_g.g; if (dyn_g.initialized) continue; if (g->module_name != module_name) PoisonShadowForGlobal(g, kAsanInitializationOrderMagic); else if (!strict_init_order) dyn_g.initialized = true; } } // This method runs immediately after dynamic initialization in each TU, when // all dynamically initialized globals except for those defined in the current // TU are poisoned. It simply unpoisons all dynamically initialized globals. void __asan_after_dynamic_init() { if (!flags()->check_initialization_order || - !CanPoisonMemory()) + !CanPoisonMemory() || + !dynamic_init_globals) return; CHECK(asan_inited); BlockingMutexLock lock(&mu_for_globals); // FIXME: Optionally report that we're unpoisoning globals from a module. for (uptr i = 0, n = dynamic_init_globals->size(); i < n; ++i) { DynInitGlobal &dyn_g = (*dynamic_init_globals)[i]; const Global *g = &dyn_g.g; if (!dyn_g.initialized) { // Unpoison the whole global. PoisonShadowForGlobal(g, 0); // Poison redzones back. PoisonRedZones(*g); } } } Index: projects/clang400-import/contrib/compiler-rt/lib/asan/asan_globals_win.cc =================================================================== --- projects/clang400-import/contrib/compiler-rt/lib/asan/asan_globals_win.cc (nonexistent) +++ projects/clang400-import/contrib/compiler-rt/lib/asan/asan_globals_win.cc (revision 311697) @@ -0,0 +1,62 @@ +//===-- asan_globals_win.cc -----------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Global registration code that is linked into every Windows DLL and EXE. +// +//===----------------------------------------------------------------------===// + +#include "asan_interface_internal.h" +#if SANITIZER_WINDOWS + +namespace __asan { + +#pragma section(".ASAN$GA", read, write) // NOLINT +#pragma section(".ASAN$GZ", read, write) // NOLINT +extern "C" __declspec(allocate(".ASAN$GA")) +__asan_global __asan_globals_start = {}; +extern "C" __declspec(allocate(".ASAN$GZ")) +__asan_global __asan_globals_end = {}; +#pragma comment(linker, "/merge:.ASAN=.data") + +static void call_on_globals(void (*hook)(__asan_global *, uptr)) { + __asan_global *start = &__asan_globals_start + 1; + __asan_global *end = &__asan_globals_end; + uptr bytediff = (uptr)end - (uptr)start; + if (bytediff % sizeof(__asan_global) != 0) { +#ifdef ASAN_DLL_THUNK + __debugbreak(); +#else + CHECK("corrupt asan global array"); +#endif + } + // We know end >= start because the linker sorts the portion after the dollar + // sign alphabetically. + uptr n = end - start; + hook(start, n); +} + +static void register_dso_globals() { + call_on_globals(&__asan_register_globals); +} + +static void unregister_dso_globals() { + call_on_globals(&__asan_unregister_globals); +} + +// Register globals +#pragma section(".CRT$XCU", long, read) // NOLINT +#pragma section(".CRT$XTX", long, read) // NOLINT +extern "C" __declspec(allocate(".CRT$XCU")) +void (*const __asan_dso_reg_hook)() = ®ister_dso_globals; +extern "C" __declspec(allocate(".CRT$XTX")) +void (*const __asan_dso_unreg_hook)() = &unregister_dso_globals; + +} // namespace __asan + +#endif // SANITIZER_WINDOWS Property changes on: projects/clang400-import/contrib/compiler-rt/lib/asan/asan_globals_win.cc ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: projects/clang400-import/contrib/compiler-rt/lib/asan/asan_globals_win.h =================================================================== --- projects/clang400-import/contrib/compiler-rt/lib/asan/asan_globals_win.h (nonexistent) +++ projects/clang400-import/contrib/compiler-rt/lib/asan/asan_globals_win.h (revision 311697) @@ -0,0 +1,34 @@ +//===-- asan_globals_win.h --------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Interface to the Windows-specific global management code. Separated into a +// standalone header to allow inclusion from asan_win_dynamic_runtime_thunk, +// which defines symbols that clash with other sanitizer headers. +// +//===----------------------------------------------------------------------===// + +#ifndef ASAN_GLOBALS_WIN_H +#define ASAN_GLOBALS_WIN_H + +#if !defined(_MSC_VER) +#error "this file is Windows-only, and uses MSVC pragmas" +#endif + +#if defined(_WIN64) +#define SANITIZER_SYM_PREFIX +#else +#define SANITIZER_SYM_PREFIX "_" +#endif + +// Use this macro to force linking asan_globals_win.cc into the DSO. +#define ASAN_LINK_GLOBALS_WIN() \ + __pragma( \ + comment(linker, "/include:" SANITIZER_SYM_PREFIX "__asan_dso_reg_hook")) + +#endif // ASAN_GLOBALS_WIN_H Property changes on: projects/clang400-import/contrib/compiler-rt/lib/asan/asan_globals_win.h ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: projects/clang400-import/contrib/compiler-rt/lib/asan/asan_interceptors.cc =================================================================== --- projects/clang400-import/contrib/compiler-rt/lib/asan/asan_interceptors.cc (revision 311696) +++ projects/clang400-import/contrib/compiler-rt/lib/asan/asan_interceptors.cc (revision 311697) @@ -1,806 +1,785 @@ //===-- asan_interceptors.cc ----------------------------------------------===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // This file is a part of AddressSanitizer, an address sanity checker. // // Intercept various libc functions. //===----------------------------------------------------------------------===// #include "asan_interceptors.h" #include "asan_allocator.h" #include "asan_internal.h" #include "asan_mapping.h" #include "asan_poisoning.h" #include "asan_report.h" #include "asan_stack.h" #include "asan_stats.h" #include "asan_suppressions.h" #include "lsan/lsan_common.h" #include "sanitizer_common/sanitizer_libc.h" #if SANITIZER_POSIX #include "sanitizer_common/sanitizer_posix.h" #endif #if defined(__i386) && SANITIZER_LINUX #define ASAN_PTHREAD_CREATE_VERSION "GLIBC_2.1" #elif defined(__mips__) && SANITIZER_LINUX #define ASAN_PTHREAD_CREATE_VERSION "GLIBC_2.2" #endif namespace __asan { // Return true if we can quickly decide that the region is unpoisoned. static inline bool QuickCheckForUnpoisonedRegion(uptr beg, uptr size) { if (size == 0) return true; if (size <= 32) return !AddressIsPoisoned(beg) && !AddressIsPoisoned(beg + size - 1) && !AddressIsPoisoned(beg + size / 2); return false; } struct AsanInterceptorContext { const char *interceptor_name; }; // We implement ACCESS_MEMORY_RANGE, ASAN_READ_RANGE, // and ASAN_WRITE_RANGE as macro instead of function so // that no extra frames are created, and stack trace contains // relevant information only. // We check all shadow bytes. #define ACCESS_MEMORY_RANGE(ctx, offset, size, isWrite) do { \ uptr __offset = (uptr)(offset); \ uptr __size = (uptr)(size); \ uptr __bad = 0; \ if (__offset > __offset + __size) { \ GET_STACK_TRACE_FATAL_HERE; \ ReportStringFunctionSizeOverflow(__offset, __size, &stack); \ } \ if (!QuickCheckForUnpoisonedRegion(__offset, __size) && \ (__bad = __asan_region_is_poisoned(__offset, __size))) { \ AsanInterceptorContext *_ctx = (AsanInterceptorContext *)ctx; \ bool suppressed = false; \ if (_ctx) { \ suppressed = IsInterceptorSuppressed(_ctx->interceptor_name); \ if (!suppressed && HaveStackTraceBasedSuppressions()) { \ GET_STACK_TRACE_FATAL_HERE; \ suppressed = IsStackTraceSuppressed(&stack); \ } \ } \ if (!suppressed) { \ GET_CURRENT_PC_BP_SP; \ ReportGenericError(pc, bp, sp, __bad, isWrite, __size, 0, false);\ } \ } \ } while (0) +// memcpy is called during __asan_init() from the internals of printf(...). +// We do not treat memcpy with to==from as a bug. +// See http://llvm.org/bugs/show_bug.cgi?id=11763. +#define ASAN_MEMCPY_IMPL(ctx, to, from, size) \ + do { \ + if (UNLIKELY(!asan_inited)) return internal_memcpy(to, from, size); \ + if (asan_init_is_running) { \ + return REAL(memcpy)(to, from, size); \ + } \ + ENSURE_ASAN_INITED(); \ + if (flags()->replace_intrin) { \ + if (to != from) { \ + CHECK_RANGES_OVERLAP("memcpy", to, size, from, size); \ + } \ + ASAN_READ_RANGE(ctx, from, size); \ + ASAN_WRITE_RANGE(ctx, to, size); \ + } \ + return REAL(memcpy)(to, from, size); \ + } while (0) + +// memset is called inside Printf. +#define ASAN_MEMSET_IMPL(ctx, block, c, size) \ + do { \ + if (UNLIKELY(!asan_inited)) return internal_memset(block, c, size); \ + if (asan_init_is_running) { \ + return REAL(memset)(block, c, size); \ + } \ + ENSURE_ASAN_INITED(); \ + if (flags()->replace_intrin) { \ + ASAN_WRITE_RANGE(ctx, block, size); \ + } \ + return REAL(memset)(block, c, size); \ + } while (0) + +#define ASAN_MEMMOVE_IMPL(ctx, to, from, size) \ + do { \ + if (UNLIKELY(!asan_inited)) return internal_memmove(to, from, size); \ + ENSURE_ASAN_INITED(); \ + if (flags()->replace_intrin) { \ + ASAN_READ_RANGE(ctx, from, size); \ + ASAN_WRITE_RANGE(ctx, to, size); \ + } \ + return internal_memmove(to, from, size); \ + } while (0) + #define ASAN_READ_RANGE(ctx, offset, size) \ ACCESS_MEMORY_RANGE(ctx, offset, size, false) #define ASAN_WRITE_RANGE(ctx, offset, size) \ ACCESS_MEMORY_RANGE(ctx, offset, size, true) #define ASAN_READ_STRING_OF_LEN(ctx, s, len, n) \ ASAN_READ_RANGE((ctx), (s), \ common_flags()->strict_string_checks ? (len) + 1 : (n)) #define ASAN_READ_STRING(ctx, s, n) \ ASAN_READ_STRING_OF_LEN((ctx), (s), REAL(strlen)(s), (n)) // Behavior of functions like "memcpy" or "strcpy" is undefined // if memory intervals overlap. We report error in this case. // Macro is used to avoid creation of new frames. static inline bool RangesOverlap(const char *offset1, uptr length1, const char *offset2, uptr length2) { return !((offset1 + length1 <= offset2) || (offset2 + length2 <= offset1)); } #define CHECK_RANGES_OVERLAP(name, _offset1, length1, _offset2, length2) do { \ const char *offset1 = (const char*)_offset1; \ const char *offset2 = (const char*)_offset2; \ if (RangesOverlap(offset1, length1, offset2, length2)) { \ GET_STACK_TRACE_FATAL_HERE; \ ReportStringFunctionMemoryRangesOverlap(name, offset1, length1, \ offset2, length2, &stack); \ } \ } while (0) static inline uptr MaybeRealStrnlen(const char *s, uptr maxlen) { #if SANITIZER_INTERCEPT_STRNLEN if (REAL(strnlen)) { return REAL(strnlen)(s, maxlen); } #endif return internal_strnlen(s, maxlen); } void SetThreadName(const char *name) { AsanThread *t = GetCurrentThread(); if (t) asanThreadRegistry().SetThreadName(t->tid(), name); } int OnExit() { // FIXME: ask frontend whether we need to return failure. return 0; } } // namespace __asan // ---------------------- Wrappers ---------------- {{{1 using namespace __asan; // NOLINT DECLARE_REAL_AND_INTERCEPTOR(void *, malloc, uptr) DECLARE_REAL_AND_INTERCEPTOR(void, free, void *) #define ASAN_INTERCEPTOR_ENTER(ctx, func) \ AsanInterceptorContext _ctx = {#func}; \ ctx = (void *)&_ctx; \ (void) ctx; \ #define COMMON_INTERCEPT_FUNCTION(name) ASAN_INTERCEPT_FUNC(name) #define COMMON_INTERCEPT_FUNCTION_VER(name, ver) \ ASAN_INTERCEPT_FUNC_VER(name, ver) #define COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ptr, size) \ ASAN_WRITE_RANGE(ctx, ptr, size) #define COMMON_INTERCEPTOR_READ_RANGE(ctx, ptr, size) \ ASAN_READ_RANGE(ctx, ptr, size) #define COMMON_INTERCEPTOR_ENTER(ctx, func, ...) \ ASAN_INTERCEPTOR_ENTER(ctx, func); \ do { \ if (asan_init_is_running) \ return REAL(func)(__VA_ARGS__); \ if (SANITIZER_MAC && UNLIKELY(!asan_inited)) \ return REAL(func)(__VA_ARGS__); \ ENSURE_ASAN_INITED(); \ } while (false) #define COMMON_INTERCEPTOR_DIR_ACQUIRE(ctx, path) \ do { \ } while (false) #define COMMON_INTERCEPTOR_FD_ACQUIRE(ctx, fd) \ do { \ } while (false) #define COMMON_INTERCEPTOR_FD_RELEASE(ctx, fd) \ do { \ } while (false) #define COMMON_INTERCEPTOR_FD_SOCKET_ACCEPT(ctx, fd, newfd) \ do { \ } while (false) #define COMMON_INTERCEPTOR_SET_THREAD_NAME(ctx, name) SetThreadName(name) // Should be asanThreadRegistry().SetThreadNameByUserId(thread, name) // But asan does not remember UserId's for threads (pthread_t); // and remembers all ever existed threads, so the linear search by UserId // can be slow. #define COMMON_INTERCEPTOR_SET_PTHREAD_NAME(ctx, thread, name) \ do { \ } while (false) #define COMMON_INTERCEPTOR_BLOCK_REAL(name) REAL(name) // Strict init-order checking is dlopen-hostile: // https://github.com/google/sanitizers/issues/178 #define COMMON_INTERCEPTOR_ON_DLOPEN(filename, flag) \ if (flags()->strict_init_order) { \ StopInitOrderChecking(); \ } #define COMMON_INTERCEPTOR_ON_EXIT(ctx) OnExit() #define COMMON_INTERCEPTOR_LIBRARY_LOADED(filename, handle) \ CoverageUpdateMapping() #define COMMON_INTERCEPTOR_LIBRARY_UNLOADED() CoverageUpdateMapping() #define COMMON_INTERCEPTOR_NOTHING_IS_INITIALIZED (!asan_inited) #define COMMON_INTERCEPTOR_GET_TLS_RANGE(begin, end) \ if (AsanThread *t = GetCurrentThread()) { \ *begin = t->tls_begin(); \ *end = t->tls_end(); \ } else { \ *begin = *end = 0; \ } -// Asan needs custom handling of these: -#undef SANITIZER_INTERCEPT_MEMSET -#undef SANITIZER_INTERCEPT_MEMMOVE -#undef SANITIZER_INTERCEPT_MEMCPY + +#define COMMON_INTERCEPTOR_MEMMOVE_IMPL(ctx, to, from, size) \ + do { \ + ASAN_INTERCEPTOR_ENTER(ctx, memmove); \ + ASAN_MEMMOVE_IMPL(ctx, to, from, size); \ + } while (false) + +#define COMMON_INTERCEPTOR_MEMCPY_IMPL(ctx, to, from, size) \ + do { \ + ASAN_INTERCEPTOR_ENTER(ctx, memcpy); \ + ASAN_MEMCPY_IMPL(ctx, to, from, size); \ + } while (false) + +#define COMMON_INTERCEPTOR_MEMSET_IMPL(ctx, block, c, size) \ + do { \ + ASAN_INTERCEPTOR_ENTER(ctx, memset); \ + ASAN_MEMSET_IMPL(ctx, block, c, size); \ + } while (false) + #include "sanitizer_common/sanitizer_common_interceptors.inc" // Syscall interceptors don't have contexts, we don't support suppressions // for them. #define COMMON_SYSCALL_PRE_READ_RANGE(p, s) ASAN_READ_RANGE(nullptr, p, s) #define COMMON_SYSCALL_PRE_WRITE_RANGE(p, s) ASAN_WRITE_RANGE(nullptr, p, s) #define COMMON_SYSCALL_POST_READ_RANGE(p, s) \ do { \ (void)(p); \ (void)(s); \ } while (false) #define COMMON_SYSCALL_POST_WRITE_RANGE(p, s) \ do { \ (void)(p); \ (void)(s); \ } while (false) #include "sanitizer_common/sanitizer_common_syscalls.inc" struct ThreadStartParam { atomic_uintptr_t t; atomic_uintptr_t is_registered; }; #if ASAN_INTERCEPT_PTHREAD_CREATE static thread_return_t THREAD_CALLING_CONV asan_thread_start(void *arg) { ThreadStartParam *param = reinterpret_cast(arg); AsanThread *t = nullptr; while ((t = reinterpret_cast( atomic_load(¶m->t, memory_order_acquire))) == nullptr) internal_sched_yield(); SetCurrentThread(t); return t->ThreadStart(GetTid(), ¶m->is_registered); } INTERCEPTOR(int, pthread_create, void *thread, void *attr, void *(*start_routine)(void*), void *arg) { EnsureMainThreadIDIsCorrect(); // Strict init-order checking is thread-hostile. if (flags()->strict_init_order) StopInitOrderChecking(); GET_STACK_TRACE_THREAD; int detached = 0; if (attr) REAL(pthread_attr_getdetachstate)(attr, &detached); ThreadStartParam param; atomic_store(¶m.t, 0, memory_order_relaxed); atomic_store(¶m.is_registered, 0, memory_order_relaxed); int result; { // Ignore all allocations made by pthread_create: thread stack/TLS may be // stored by pthread for future reuse even after thread destruction, and // the linked list it's stored in doesn't even hold valid pointers to the // objects, the latter are calculated by obscure pointer arithmetic. #if CAN_SANITIZE_LEAKS __lsan::ScopedInterceptorDisabler disabler; #endif result = REAL(pthread_create)(thread, attr, asan_thread_start, ¶m); } if (result == 0) { u32 current_tid = GetCurrentTidOrInvalid(); AsanThread *t = AsanThread::Create(start_routine, arg, current_tid, &stack, detached); atomic_store(¶m.t, reinterpret_cast(t), memory_order_release); // Wait until the AsanThread object is initialized and the ThreadRegistry // entry is in "started" state. One reason for this is that after this // interceptor exits, the child thread's stack may be the only thing holding // the |arg| pointer. This may cause LSan to report a leak if leak checking // happens at a point when the interceptor has already exited, but the stack // range for the child thread is not yet known. while (atomic_load(¶m.is_registered, memory_order_acquire) == 0) internal_sched_yield(); } return result; } INTERCEPTOR(int, pthread_join, void *t, void **arg) { return real_pthread_join(t, arg); } DEFINE_REAL_PTHREAD_FUNCTIONS #endif // ASAN_INTERCEPT_PTHREAD_CREATE #if ASAN_INTERCEPT_SIGNAL_AND_SIGACTION #if SANITIZER_ANDROID INTERCEPTOR(void*, bsd_signal, int signum, void *handler) { if (!IsHandledDeadlySignal(signum) || common_flags()->allow_user_segv_handler) { return REAL(bsd_signal)(signum, handler); } return 0; } #endif INTERCEPTOR(void*, signal, int signum, void *handler) { if (!IsHandledDeadlySignal(signum) || common_flags()->allow_user_segv_handler) { return REAL(signal)(signum, handler); } return nullptr; } INTERCEPTOR(int, sigaction, int signum, const struct sigaction *act, struct sigaction *oldact) { if (!IsHandledDeadlySignal(signum) || common_flags()->allow_user_segv_handler) { return REAL(sigaction)(signum, act, oldact); } return 0; } namespace __sanitizer { int real_sigaction(int signum, const void *act, void *oldact) { return REAL(sigaction)(signum, (const struct sigaction *)act, (struct sigaction *)oldact); } } // namespace __sanitizer #elif SANITIZER_POSIX // We need to have defined REAL(sigaction) on posix systems. DEFINE_REAL(int, sigaction, int signum, const struct sigaction *act, struct sigaction *oldact) #endif // ASAN_INTERCEPT_SIGNAL_AND_SIGACTION #if ASAN_INTERCEPT_SWAPCONTEXT static void ClearShadowMemoryForContextStack(uptr stack, uptr ssize) { // Align to page size. uptr PageSize = GetPageSizeCached(); uptr bottom = stack & ~(PageSize - 1); ssize += stack - bottom; ssize = RoundUpTo(ssize, PageSize); static const uptr kMaxSaneContextStackSize = 1 << 22; // 4 Mb if (AddrIsInMem(bottom) && ssize && ssize <= kMaxSaneContextStackSize) { PoisonShadow(bottom, ssize, 0); } } INTERCEPTOR(int, swapcontext, struct ucontext_t *oucp, struct ucontext_t *ucp) { static bool reported_warning = false; if (!reported_warning) { Report("WARNING: ASan doesn't fully support makecontext/swapcontext " "functions and may produce false positives in some cases!\n"); reported_warning = true; } // Clear shadow memory for new context (it may share stack // with current context). uptr stack, ssize; ReadContextStack(ucp, &stack, &ssize); ClearShadowMemoryForContextStack(stack, ssize); int res = REAL(swapcontext)(oucp, ucp); // swapcontext technically does not return, but program may swap context to // "oucp" later, that would look as if swapcontext() returned 0. // We need to clear shadow for ucp once again, as it may be in arbitrary // state. ClearShadowMemoryForContextStack(stack, ssize); return res; } #endif // ASAN_INTERCEPT_SWAPCONTEXT INTERCEPTOR(void, longjmp, void *env, int val) { __asan_handle_no_return(); REAL(longjmp)(env, val); } #if ASAN_INTERCEPT__LONGJMP INTERCEPTOR(void, _longjmp, void *env, int val) { __asan_handle_no_return(); REAL(_longjmp)(env, val); } #endif #if ASAN_INTERCEPT_SIGLONGJMP INTERCEPTOR(void, siglongjmp, void *env, int val) { __asan_handle_no_return(); REAL(siglongjmp)(env, val); } #endif #if ASAN_INTERCEPT___CXA_THROW INTERCEPTOR(void, __cxa_throw, void *a, void *b, void *c) { CHECK(REAL(__cxa_throw)); __asan_handle_no_return(); REAL(__cxa_throw)(a, b, c); } #endif -// memcpy is called during __asan_init() from the internals of printf(...). -// We do not treat memcpy with to==from as a bug. -// See http://llvm.org/bugs/show_bug.cgi?id=11763. -#define ASAN_MEMCPY_IMPL(ctx, to, from, size) do { \ - if (UNLIKELY(!asan_inited)) return internal_memcpy(to, from, size); \ - if (asan_init_is_running) { \ - return REAL(memcpy)(to, from, size); \ - } \ - ENSURE_ASAN_INITED(); \ - if (flags()->replace_intrin) { \ - if (to != from) { \ - CHECK_RANGES_OVERLAP("memcpy", to, size, from, size); \ - } \ - ASAN_READ_RANGE(ctx, from, size); \ - ASAN_WRITE_RANGE(ctx, to, size); \ - } \ - return REAL(memcpy)(to, from, size); \ - } while (0) - - void *__asan_memcpy(void *to, const void *from, uptr size) { ASAN_MEMCPY_IMPL(nullptr, to, from, size); } -// memset is called inside Printf. -#define ASAN_MEMSET_IMPL(ctx, block, c, size) do { \ - if (UNLIKELY(!asan_inited)) return internal_memset(block, c, size); \ - if (asan_init_is_running) { \ - return REAL(memset)(block, c, size); \ - } \ - ENSURE_ASAN_INITED(); \ - if (flags()->replace_intrin) { \ - ASAN_WRITE_RANGE(ctx, block, size); \ - } \ - return REAL(memset)(block, c, size); \ - } while (0) - void *__asan_memset(void *block, int c, uptr size) { ASAN_MEMSET_IMPL(nullptr, block, c, size); } -#define ASAN_MEMMOVE_IMPL(ctx, to, from, size) do { \ - if (UNLIKELY(!asan_inited)) \ - return internal_memmove(to, from, size); \ - ENSURE_ASAN_INITED(); \ - if (flags()->replace_intrin) { \ - ASAN_READ_RANGE(ctx, from, size); \ - ASAN_WRITE_RANGE(ctx, to, size); \ - } \ - return internal_memmove(to, from, size); \ - } while (0) - void *__asan_memmove(void *to, const void *from, uptr size) { ASAN_MEMMOVE_IMPL(nullptr, to, from, size); } -INTERCEPTOR(void*, memmove, void *to, const void *from, uptr size) { - void *ctx; - ASAN_INTERCEPTOR_ENTER(ctx, memmove); - ASAN_MEMMOVE_IMPL(ctx, to, from, size); -} - -INTERCEPTOR(void*, memcpy, void *to, const void *from, uptr size) { - void *ctx; - ASAN_INTERCEPTOR_ENTER(ctx, memcpy); -#if !SANITIZER_MAC - ASAN_MEMCPY_IMPL(ctx, to, from, size); -#else - // At least on 10.7 and 10.8 both memcpy() and memmove() are being replaced - // with WRAP(memcpy). As a result, false positives are reported for memmove() - // calls. If we just disable error reporting with - // ASAN_OPTIONS=replace_intrin=0, memmove() is still replaced with - // internal_memcpy(), which may lead to crashes, see - // http://llvm.org/bugs/show_bug.cgi?id=16362. - ASAN_MEMMOVE_IMPL(ctx, to, from, size); -#endif // !SANITIZER_MAC -} - -INTERCEPTOR(void*, memset, void *block, int c, uptr size) { - void *ctx; - ASAN_INTERCEPTOR_ENTER(ctx, memset); - ASAN_MEMSET_IMPL(ctx, block, c, size); -} - #if ASAN_INTERCEPT_INDEX # if ASAN_USE_ALIAS_ATTRIBUTE_FOR_INDEX INTERCEPTOR(char*, index, const char *string, int c) ALIAS(WRAPPER_NAME(strchr)); # else # if SANITIZER_MAC DECLARE_REAL(char*, index, const char *string, int c) OVERRIDE_FUNCTION(index, strchr); # else DEFINE_REAL(char*, index, const char *string, int c) # endif # endif #endif // ASAN_INTERCEPT_INDEX // For both strcat() and strncat() we need to check the validity of |to| // argument irrespective of the |from| length. INTERCEPTOR(char*, strcat, char *to, const char *from) { // NOLINT void *ctx; ASAN_INTERCEPTOR_ENTER(ctx, strcat); // NOLINT ENSURE_ASAN_INITED(); if (flags()->replace_str) { uptr from_length = REAL(strlen)(from); ASAN_READ_RANGE(ctx, from, from_length + 1); uptr to_length = REAL(strlen)(to); ASAN_READ_STRING_OF_LEN(ctx, to, to_length, to_length); ASAN_WRITE_RANGE(ctx, to + to_length, from_length + 1); // If the copying actually happens, the |from| string should not overlap // with the resulting string starting at |to|, which has a length of // to_length + from_length + 1. if (from_length > 0) { CHECK_RANGES_OVERLAP("strcat", to, from_length + to_length + 1, from, from_length + 1); } } return REAL(strcat)(to, from); // NOLINT } INTERCEPTOR(char*, strncat, char *to, const char *from, uptr size) { void *ctx; ASAN_INTERCEPTOR_ENTER(ctx, strncat); ENSURE_ASAN_INITED(); if (flags()->replace_str) { uptr from_length = MaybeRealStrnlen(from, size); uptr copy_length = Min(size, from_length + 1); ASAN_READ_RANGE(ctx, from, copy_length); uptr to_length = REAL(strlen)(to); ASAN_READ_STRING_OF_LEN(ctx, to, to_length, to_length); ASAN_WRITE_RANGE(ctx, to + to_length, from_length + 1); if (from_length > 0) { CHECK_RANGES_OVERLAP("strncat", to, to_length + copy_length + 1, from, copy_length); } } return REAL(strncat)(to, from, size); } INTERCEPTOR(char*, strcpy, char *to, const char *from) { // NOLINT void *ctx; ASAN_INTERCEPTOR_ENTER(ctx, strcpy); // NOLINT #if SANITIZER_MAC if (UNLIKELY(!asan_inited)) return REAL(strcpy)(to, from); // NOLINT #endif // strcpy is called from malloc_default_purgeable_zone() // in __asan::ReplaceSystemAlloc() on Mac. if (asan_init_is_running) { return REAL(strcpy)(to, from); // NOLINT } ENSURE_ASAN_INITED(); if (flags()->replace_str) { uptr from_size = REAL(strlen)(from) + 1; CHECK_RANGES_OVERLAP("strcpy", to, from_size, from, from_size); ASAN_READ_RANGE(ctx, from, from_size); ASAN_WRITE_RANGE(ctx, to, from_size); } return REAL(strcpy)(to, from); // NOLINT } INTERCEPTOR(char*, strdup, const char *s) { void *ctx; ASAN_INTERCEPTOR_ENTER(ctx, strdup); if (UNLIKELY(!asan_inited)) return internal_strdup(s); ENSURE_ASAN_INITED(); uptr length = REAL(strlen)(s); if (flags()->replace_str) { ASAN_READ_RANGE(ctx, s, length + 1); } GET_STACK_TRACE_MALLOC; void *new_mem = asan_malloc(length + 1, &stack); REAL(memcpy)(new_mem, s, length + 1); return reinterpret_cast(new_mem); } #if ASAN_INTERCEPT___STRDUP INTERCEPTOR(char*, __strdup, const char *s) { void *ctx; ASAN_INTERCEPTOR_ENTER(ctx, strdup); if (UNLIKELY(!asan_inited)) return internal_strdup(s); ENSURE_ASAN_INITED(); uptr length = REAL(strlen)(s); if (flags()->replace_str) { ASAN_READ_RANGE(ctx, s, length + 1); } GET_STACK_TRACE_MALLOC; void *new_mem = asan_malloc(length + 1, &stack); REAL(memcpy)(new_mem, s, length + 1); return reinterpret_cast(new_mem); } #endif // ASAN_INTERCEPT___STRDUP INTERCEPTOR(SIZE_T, wcslen, const wchar_t *s) { void *ctx; ASAN_INTERCEPTOR_ENTER(ctx, wcslen); SIZE_T length = internal_wcslen(s); if (!asan_init_is_running) { ENSURE_ASAN_INITED(); ASAN_READ_RANGE(ctx, s, (length + 1) * sizeof(wchar_t)); } return length; } INTERCEPTOR(char*, strncpy, char *to, const char *from, uptr size) { void *ctx; ASAN_INTERCEPTOR_ENTER(ctx, strncpy); ENSURE_ASAN_INITED(); if (flags()->replace_str) { uptr from_size = Min(size, MaybeRealStrnlen(from, size) + 1); CHECK_RANGES_OVERLAP("strncpy", to, from_size, from, from_size); ASAN_READ_RANGE(ctx, from, from_size); ASAN_WRITE_RANGE(ctx, to, size); } return REAL(strncpy)(to, from, size); } INTERCEPTOR(long, strtol, const char *nptr, // NOLINT char **endptr, int base) { void *ctx; ASAN_INTERCEPTOR_ENTER(ctx, strtol); ENSURE_ASAN_INITED(); if (!flags()->replace_str) { return REAL(strtol)(nptr, endptr, base); } char *real_endptr; long result = REAL(strtol)(nptr, &real_endptr, base); // NOLINT StrtolFixAndCheck(ctx, nptr, endptr, real_endptr, base); return result; } INTERCEPTOR(int, atoi, const char *nptr) { void *ctx; ASAN_INTERCEPTOR_ENTER(ctx, atoi); #if SANITIZER_MAC if (UNLIKELY(!asan_inited)) return REAL(atoi)(nptr); #endif ENSURE_ASAN_INITED(); if (!flags()->replace_str) { return REAL(atoi)(nptr); } char *real_endptr; // "man atoi" tells that behavior of atoi(nptr) is the same as // strtol(nptr, 0, 10), i.e. it sets errno to ERANGE if the // parsed integer can't be stored in *long* type (even if it's // different from int). So, we just imitate this behavior. int result = REAL(strtol)(nptr, &real_endptr, 10); FixRealStrtolEndptr(nptr, &real_endptr); ASAN_READ_STRING(ctx, nptr, (real_endptr - nptr) + 1); return result; } INTERCEPTOR(long, atol, const char *nptr) { // NOLINT void *ctx; ASAN_INTERCEPTOR_ENTER(ctx, atol); #if SANITIZER_MAC if (UNLIKELY(!asan_inited)) return REAL(atol)(nptr); #endif ENSURE_ASAN_INITED(); if (!flags()->replace_str) { return REAL(atol)(nptr); } char *real_endptr; long result = REAL(strtol)(nptr, &real_endptr, 10); // NOLINT FixRealStrtolEndptr(nptr, &real_endptr); ASAN_READ_STRING(ctx, nptr, (real_endptr - nptr) + 1); return result; } #if ASAN_INTERCEPT_ATOLL_AND_STRTOLL INTERCEPTOR(long long, strtoll, const char *nptr, // NOLINT char **endptr, int base) { void *ctx; ASAN_INTERCEPTOR_ENTER(ctx, strtoll); ENSURE_ASAN_INITED(); if (!flags()->replace_str) { return REAL(strtoll)(nptr, endptr, base); } char *real_endptr; long long result = REAL(strtoll)(nptr, &real_endptr, base); // NOLINT StrtolFixAndCheck(ctx, nptr, endptr, real_endptr, base); return result; } INTERCEPTOR(long long, atoll, const char *nptr) { // NOLINT void *ctx; ASAN_INTERCEPTOR_ENTER(ctx, atoll); ENSURE_ASAN_INITED(); if (!flags()->replace_str) { return REAL(atoll)(nptr); } char *real_endptr; long long result = REAL(strtoll)(nptr, &real_endptr, 10); // NOLINT FixRealStrtolEndptr(nptr, &real_endptr); ASAN_READ_STRING(ctx, nptr, (real_endptr - nptr) + 1); return result; } #endif // ASAN_INTERCEPT_ATOLL_AND_STRTOLL #if ASAN_INTERCEPT___CXA_ATEXIT static void AtCxaAtexit(void *unused) { (void)unused; StopInitOrderChecking(); } INTERCEPTOR(int, __cxa_atexit, void (*func)(void *), void *arg, void *dso_handle) { #if SANITIZER_MAC if (UNLIKELY(!asan_inited)) return REAL(__cxa_atexit)(func, arg, dso_handle); #endif ENSURE_ASAN_INITED(); int res = REAL(__cxa_atexit)(func, arg, dso_handle); REAL(__cxa_atexit)(AtCxaAtexit, nullptr, nullptr); return res; } #endif // ASAN_INTERCEPT___CXA_ATEXIT #if ASAN_INTERCEPT_FORK INTERCEPTOR(int, fork, void) { ENSURE_ASAN_INITED(); if (common_flags()->coverage) CovBeforeFork(); int pid = REAL(fork)(); if (common_flags()->coverage) CovAfterFork(pid); return pid; } #endif // ASAN_INTERCEPT_FORK // ---------------------- InitializeAsanInterceptors ---------------- {{{1 namespace __asan { void InitializeAsanInterceptors() { static bool was_called_once; - CHECK(was_called_once == false); + CHECK(!was_called_once); was_called_once = true; InitializeCommonInterceptors(); - - // Intercept mem* functions. - ASAN_INTERCEPT_FUNC(memcpy); - ASAN_INTERCEPT_FUNC(memset); - if (PLATFORM_HAS_DIFFERENT_MEMCPY_AND_MEMMOVE) { - // In asan, REAL(memmove) is not used, but it is used in msan. - ASAN_INTERCEPT_FUNC(memmove); - } - CHECK(REAL(memcpy)); // Intercept str* functions. ASAN_INTERCEPT_FUNC(strcat); // NOLINT ASAN_INTERCEPT_FUNC(strcpy); // NOLINT ASAN_INTERCEPT_FUNC(wcslen); ASAN_INTERCEPT_FUNC(strncat); ASAN_INTERCEPT_FUNC(strncpy); ASAN_INTERCEPT_FUNC(strdup); #if ASAN_INTERCEPT___STRDUP ASAN_INTERCEPT_FUNC(__strdup); #endif #if ASAN_INTERCEPT_INDEX && ASAN_USE_ALIAS_ATTRIBUTE_FOR_INDEX ASAN_INTERCEPT_FUNC(index); #endif ASAN_INTERCEPT_FUNC(atoi); ASAN_INTERCEPT_FUNC(atol); ASAN_INTERCEPT_FUNC(strtol); #if ASAN_INTERCEPT_ATOLL_AND_STRTOLL ASAN_INTERCEPT_FUNC(atoll); ASAN_INTERCEPT_FUNC(strtoll); #endif // Intecept signal- and jump-related functions. ASAN_INTERCEPT_FUNC(longjmp); #if ASAN_INTERCEPT_SIGNAL_AND_SIGACTION ASAN_INTERCEPT_FUNC(sigaction); #if SANITIZER_ANDROID ASAN_INTERCEPT_FUNC(bsd_signal); #endif ASAN_INTERCEPT_FUNC(signal); #endif #if ASAN_INTERCEPT_SWAPCONTEXT ASAN_INTERCEPT_FUNC(swapcontext); #endif #if ASAN_INTERCEPT__LONGJMP ASAN_INTERCEPT_FUNC(_longjmp); #endif #if ASAN_INTERCEPT_SIGLONGJMP ASAN_INTERCEPT_FUNC(siglongjmp); #endif // Intercept exception handling functions. #if ASAN_INTERCEPT___CXA_THROW ASAN_INTERCEPT_FUNC(__cxa_throw); #endif // Intercept threading-related functions #if ASAN_INTERCEPT_PTHREAD_CREATE #if defined(ASAN_PTHREAD_CREATE_VERSION) ASAN_INTERCEPT_FUNC_VER(pthread_create, ASAN_PTHREAD_CREATE_VERSION); #else ASAN_INTERCEPT_FUNC(pthread_create); #endif ASAN_INTERCEPT_FUNC(pthread_join); #endif // Intercept atexit function. #if ASAN_INTERCEPT___CXA_ATEXIT ASAN_INTERCEPT_FUNC(__cxa_atexit); #endif #if ASAN_INTERCEPT_FORK ASAN_INTERCEPT_FUNC(fork); #endif InitializePlatformInterceptors(); VReport(1, "AddressSanitizer: libc interceptors initialized\n"); } } // namespace __asan Index: projects/clang400-import/contrib/compiler-rt/lib/asan/asan_interface_internal.h =================================================================== --- projects/clang400-import/contrib/compiler-rt/lib/asan/asan_interface_internal.h (revision 311696) +++ projects/clang400-import/contrib/compiler-rt/lib/asan/asan_interface_internal.h (revision 311697) @@ -1,228 +1,247 @@ //===-- asan_interface_internal.h -------------------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // This file is a part of AddressSanitizer, an address sanity checker. // // This header declares the AddressSanitizer runtime interface functions. // The runtime library has to define these functions so the instrumented program // could call them. // // See also include/sanitizer/asan_interface.h //===----------------------------------------------------------------------===// #ifndef ASAN_INTERFACE_INTERNAL_H #define ASAN_INTERFACE_INTERNAL_H #include "sanitizer_common/sanitizer_internal_defs.h" #include "asan_init_version.h" using __sanitizer::uptr; +using __sanitizer::u64; +using __sanitizer::u32; extern "C" { // This function should be called at the very beginning of the process, // before any instrumented code is executed and before any call to malloc. SANITIZER_INTERFACE_ATTRIBUTE void __asan_init(); // This function exists purely to get a linker/loader error when using // incompatible versions of instrumentation and runtime library. Please note // that __asan_version_mismatch_check is a macro that is replaced with // __asan_version_mismatch_check_vXXX at compile-time. SANITIZER_INTERFACE_ATTRIBUTE void __asan_version_mismatch_check(); // This structure is used to describe the source location of a place where // global was defined. struct __asan_global_source_location { const char *filename; int line_no; int column_no; }; // This structure describes an instrumented global variable. struct __asan_global { uptr beg; // The address of the global. uptr size; // The original size of the global. uptr size_with_redzone; // The size with the redzone. const char *name; // Name as a C string. const char *module_name; // Module name as a C string. This pointer is a // unique identifier of a module. uptr has_dynamic_init; // Non-zero if the global has dynamic initializer. __asan_global_source_location *location; // Source location of a global, // or NULL if it is unknown. uptr odr_indicator; // The address of the ODR indicator symbol. }; // These functions can be called on some platforms to find globals in the same // loaded image as `flag' and apply __asan_(un)register_globals to them, // filtering out redundant calls. SANITIZER_INTERFACE_ATTRIBUTE void __asan_register_image_globals(uptr *flag); SANITIZER_INTERFACE_ATTRIBUTE void __asan_unregister_image_globals(uptr *flag); // These two functions should be called by the instrumented code. // 'globals' is an array of structures describing 'n' globals. SANITIZER_INTERFACE_ATTRIBUTE void __asan_register_globals(__asan_global *globals, uptr n); SANITIZER_INTERFACE_ATTRIBUTE void __asan_unregister_globals(__asan_global *globals, uptr n); // These two functions should be called before and after dynamic initializers // of a single module run, respectively. SANITIZER_INTERFACE_ATTRIBUTE void __asan_before_dynamic_init(const char *module_name); SANITIZER_INTERFACE_ATTRIBUTE void __asan_after_dynamic_init(); + // Sets bytes of the given range of the shadow memory into specific value. + SANITIZER_INTERFACE_ATTRIBUTE + void __asan_set_shadow_00(uptr addr, uptr size); + SANITIZER_INTERFACE_ATTRIBUTE + void __asan_set_shadow_f1(uptr addr, uptr size); + SANITIZER_INTERFACE_ATTRIBUTE + void __asan_set_shadow_f2(uptr addr, uptr size); + SANITIZER_INTERFACE_ATTRIBUTE + void __asan_set_shadow_f3(uptr addr, uptr size); + SANITIZER_INTERFACE_ATTRIBUTE + void __asan_set_shadow_f5(uptr addr, uptr size); + SANITIZER_INTERFACE_ATTRIBUTE + void __asan_set_shadow_f8(uptr addr, uptr size); + // These two functions are used by instrumented code in the // use-after-scope mode. They mark memory for local variables as // unaddressable when they leave scope and addressable before the // function exits. SANITIZER_INTERFACE_ATTRIBUTE void __asan_poison_stack_memory(uptr addr, uptr size); SANITIZER_INTERFACE_ATTRIBUTE void __asan_unpoison_stack_memory(uptr addr, uptr size); // Performs cleanup before a NoReturn function. Must be called before things // like _exit and execl to avoid false positives on stack. SANITIZER_INTERFACE_ATTRIBUTE void __asan_handle_no_return(); SANITIZER_INTERFACE_ATTRIBUTE void __asan_poison_memory_region(void const volatile *addr, uptr size); SANITIZER_INTERFACE_ATTRIBUTE void __asan_unpoison_memory_region(void const volatile *addr, uptr size); SANITIZER_INTERFACE_ATTRIBUTE int __asan_address_is_poisoned(void const volatile *addr); SANITIZER_INTERFACE_ATTRIBUTE uptr __asan_region_is_poisoned(uptr beg, uptr size); SANITIZER_INTERFACE_ATTRIBUTE void __asan_describe_address(uptr addr); SANITIZER_INTERFACE_ATTRIBUTE int __asan_report_present(); SANITIZER_INTERFACE_ATTRIBUTE uptr __asan_get_report_pc(); SANITIZER_INTERFACE_ATTRIBUTE uptr __asan_get_report_bp(); SANITIZER_INTERFACE_ATTRIBUTE uptr __asan_get_report_sp(); SANITIZER_INTERFACE_ATTRIBUTE uptr __asan_get_report_address(); SANITIZER_INTERFACE_ATTRIBUTE int __asan_get_report_access_type(); SANITIZER_INTERFACE_ATTRIBUTE uptr __asan_get_report_access_size(); SANITIZER_INTERFACE_ATTRIBUTE const char * __asan_get_report_description(); SANITIZER_INTERFACE_ATTRIBUTE const char * __asan_locate_address(uptr addr, char *name, uptr name_size, uptr *region_address, uptr *region_size); SANITIZER_INTERFACE_ATTRIBUTE uptr __asan_get_alloc_stack(uptr addr, uptr *trace, uptr size, u32 *thread_id); SANITIZER_INTERFACE_ATTRIBUTE uptr __asan_get_free_stack(uptr addr, uptr *trace, uptr size, u32 *thread_id); SANITIZER_INTERFACE_ATTRIBUTE void __asan_get_shadow_mapping(uptr *shadow_scale, uptr *shadow_offset); SANITIZER_INTERFACE_ATTRIBUTE void __asan_report_error(uptr pc, uptr bp, uptr sp, uptr addr, int is_write, uptr access_size, u32 exp); SANITIZER_INTERFACE_ATTRIBUTE void __asan_set_death_callback(void (*callback)(void)); SANITIZER_INTERFACE_ATTRIBUTE void __asan_set_error_report_callback(void (*callback)(const char*)); SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE /* OPTIONAL */ void __asan_on_error(); SANITIZER_INTERFACE_ATTRIBUTE void __asan_print_accumulated_stats(); SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE /* OPTIONAL */ const char* __asan_default_options(); + + SANITIZER_INTERFACE_ATTRIBUTE + extern uptr __asan_shadow_memory_dynamic_address; // Global flag, copy of ASAN_OPTIONS=detect_stack_use_after_return SANITIZER_INTERFACE_ATTRIBUTE extern int __asan_option_detect_stack_use_after_return; SANITIZER_INTERFACE_ATTRIBUTE extern uptr *__asan_test_only_reported_buggy_pointer; SANITIZER_INTERFACE_ATTRIBUTE void __asan_load1(uptr p); SANITIZER_INTERFACE_ATTRIBUTE void __asan_load2(uptr p); SANITIZER_INTERFACE_ATTRIBUTE void __asan_load4(uptr p); SANITIZER_INTERFACE_ATTRIBUTE void __asan_load8(uptr p); SANITIZER_INTERFACE_ATTRIBUTE void __asan_load16(uptr p); SANITIZER_INTERFACE_ATTRIBUTE void __asan_store1(uptr p); SANITIZER_INTERFACE_ATTRIBUTE void __asan_store2(uptr p); SANITIZER_INTERFACE_ATTRIBUTE void __asan_store4(uptr p); SANITIZER_INTERFACE_ATTRIBUTE void __asan_store8(uptr p); SANITIZER_INTERFACE_ATTRIBUTE void __asan_store16(uptr p); SANITIZER_INTERFACE_ATTRIBUTE void __asan_loadN(uptr p, uptr size); SANITIZER_INTERFACE_ATTRIBUTE void __asan_storeN(uptr p, uptr size); SANITIZER_INTERFACE_ATTRIBUTE void __asan_load1_noabort(uptr p); SANITIZER_INTERFACE_ATTRIBUTE void __asan_load2_noabort(uptr p); SANITIZER_INTERFACE_ATTRIBUTE void __asan_load4_noabort(uptr p); SANITIZER_INTERFACE_ATTRIBUTE void __asan_load8_noabort(uptr p); SANITIZER_INTERFACE_ATTRIBUTE void __asan_load16_noabort(uptr p); SANITIZER_INTERFACE_ATTRIBUTE void __asan_store1_noabort(uptr p); SANITIZER_INTERFACE_ATTRIBUTE void __asan_store2_noabort(uptr p); SANITIZER_INTERFACE_ATTRIBUTE void __asan_store4_noabort(uptr p); SANITIZER_INTERFACE_ATTRIBUTE void __asan_store8_noabort(uptr p); SANITIZER_INTERFACE_ATTRIBUTE void __asan_store16_noabort(uptr p); SANITIZER_INTERFACE_ATTRIBUTE void __asan_loadN_noabort(uptr p, uptr size); SANITIZER_INTERFACE_ATTRIBUTE void __asan_storeN_noabort(uptr p, uptr size); SANITIZER_INTERFACE_ATTRIBUTE void __asan_exp_load1(uptr p, u32 exp); SANITIZER_INTERFACE_ATTRIBUTE void __asan_exp_load2(uptr p, u32 exp); SANITIZER_INTERFACE_ATTRIBUTE void __asan_exp_load4(uptr p, u32 exp); SANITIZER_INTERFACE_ATTRIBUTE void __asan_exp_load8(uptr p, u32 exp); SANITIZER_INTERFACE_ATTRIBUTE void __asan_exp_load16(uptr p, u32 exp); SANITIZER_INTERFACE_ATTRIBUTE void __asan_exp_store1(uptr p, u32 exp); SANITIZER_INTERFACE_ATTRIBUTE void __asan_exp_store2(uptr p, u32 exp); SANITIZER_INTERFACE_ATTRIBUTE void __asan_exp_store4(uptr p, u32 exp); SANITIZER_INTERFACE_ATTRIBUTE void __asan_exp_store8(uptr p, u32 exp); SANITIZER_INTERFACE_ATTRIBUTE void __asan_exp_store16(uptr p, u32 exp); SANITIZER_INTERFACE_ATTRIBUTE void __asan_exp_loadN(uptr p, uptr size, u32 exp); SANITIZER_INTERFACE_ATTRIBUTE void __asan_exp_storeN(uptr p, uptr size, u32 exp); SANITIZER_INTERFACE_ATTRIBUTE void* __asan_memcpy(void *dst, const void *src, uptr size); SANITIZER_INTERFACE_ATTRIBUTE void* __asan_memset(void *s, int c, uptr n); SANITIZER_INTERFACE_ATTRIBUTE void* __asan_memmove(void* dest, const void* src, uptr n); SANITIZER_INTERFACE_ATTRIBUTE void __asan_poison_cxx_array_cookie(uptr p); SANITIZER_INTERFACE_ATTRIBUTE uptr __asan_load_cxx_array_cookie(uptr *p); SANITIZER_INTERFACE_ATTRIBUTE void __asan_poison_intra_object_redzone(uptr p, uptr size); SANITIZER_INTERFACE_ATTRIBUTE void __asan_unpoison_intra_object_redzone(uptr p, uptr size); SANITIZER_INTERFACE_ATTRIBUTE void __asan_alloca_poison(uptr addr, uptr size); SANITIZER_INTERFACE_ATTRIBUTE void __asan_allocas_unpoison(uptr top, uptr bottom); } // extern "C" #endif // ASAN_INTERFACE_INTERNAL_H Index: projects/clang400-import/contrib/compiler-rt/lib/asan/asan_internal.h =================================================================== --- projects/clang400-import/contrib/compiler-rt/lib/asan/asan_internal.h (revision 311696) +++ projects/clang400-import/contrib/compiler-rt/lib/asan/asan_internal.h (revision 311697) @@ -1,158 +1,148 @@ //===-- asan_internal.h -----------------------------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // This file is a part of AddressSanitizer, an address sanity checker. // // ASan-private header which defines various general utilities. //===----------------------------------------------------------------------===// #ifndef ASAN_INTERNAL_H #define ASAN_INTERNAL_H #include "asan_flags.h" #include "asan_interface_internal.h" #include "sanitizer_common/sanitizer_common.h" #include "sanitizer_common/sanitizer_internal_defs.h" #include "sanitizer_common/sanitizer_stacktrace.h" #include "sanitizer_common/sanitizer_libc.h" #if __has_feature(address_sanitizer) || defined(__SANITIZE_ADDRESS__) # error "The AddressSanitizer run-time should not be" " instrumented by AddressSanitizer" #endif // Build-time configuration options. // If set, asan will intercept C++ exception api call(s). #ifndef ASAN_HAS_EXCEPTIONS # define ASAN_HAS_EXCEPTIONS 1 #endif // If set, values like allocator chunk size, as well as defaults for some flags // will be changed towards less memory overhead. #ifndef ASAN_LOW_MEMORY -# if SANITIZER_IOS || (SANITIZER_WORDSIZE == 32) +# if SANITIZER_IOS || SANITIZER_ANDROID # define ASAN_LOW_MEMORY 1 # else # define ASAN_LOW_MEMORY 0 # endif #endif #ifndef ASAN_DYNAMIC # ifdef PIC # define ASAN_DYNAMIC 1 # else # define ASAN_DYNAMIC 0 # endif #endif // All internal functions in asan reside inside the __asan namespace // to avoid namespace collisions with the user programs. // Separate namespace also makes it simpler to distinguish the asan run-time // functions from the instrumented user code in a profile. namespace __asan { class AsanThread; using __sanitizer::StackTrace; void AsanInitFromRtl(); // asan_win.cc void InitializePlatformExceptionHandlers(); +// asan_win.cc / asan_posix.cc +const char *DescribeSignalOrException(int signo); + // asan_rtl.cc void NORETURN ShowStatsAndAbort(); // asan_malloc_linux.cc / asan_malloc_mac.cc void ReplaceSystemMalloc(); // asan_linux.cc / asan_mac.cc / asan_win.cc void *AsanDoesNotSupportStaticLinkage(); void AsanCheckDynamicRTPrereqs(); void AsanCheckIncompatibleRT(); // Support function for __asan_(un)register_image_globals. Searches for the // loaded image containing `needle' and then enumerates all global metadata // structures declared in that image, applying `op' (e.g., // __asan_(un)register_globals) to them. typedef void (*globals_op_fptr)(__asan_global *, uptr); void AsanApplyToGlobals(globals_op_fptr op, const void *needle); void AsanOnDeadlySignal(int, void *siginfo, void *context); void ReadContextStack(void *context, uptr *stack, uptr *ssize); void StopInitOrderChecking(); // Wrapper for TLS/TSD. void AsanTSDInit(void (*destructor)(void *tsd)); void *AsanTSDGet(); void AsanTSDSet(void *tsd); void PlatformTSDDtor(void *tsd); void AppendToErrorMessageBuffer(const char *buffer); void *AsanDlSymNext(const char *sym); void ReserveShadowMemoryRange(uptr beg, uptr end, const char *name); -// Platform-specific options. -#if SANITIZER_MAC -bool PlatformHasDifferentMemcpyAndMemmove(); -# define PLATFORM_HAS_DIFFERENT_MEMCPY_AND_MEMMOVE \ - (PlatformHasDifferentMemcpyAndMemmove()) -#elif SANITIZER_WINDOWS64 -# define PLATFORM_HAS_DIFFERENT_MEMCPY_AND_MEMMOVE false -#else -# define PLATFORM_HAS_DIFFERENT_MEMCPY_AND_MEMMOVE true -#endif // SANITIZER_MAC - // Add convenient macro for interface functions that may be represented as // weak hooks. #define ASAN_MALLOC_HOOK(ptr, size) \ do { \ if (&__sanitizer_malloc_hook) __sanitizer_malloc_hook(ptr, size); \ RunMallocHooks(ptr, size); \ } while (false) #define ASAN_FREE_HOOK(ptr) \ do { \ if (&__sanitizer_free_hook) __sanitizer_free_hook(ptr); \ RunFreeHooks(ptr); \ } while (false) #define ASAN_ON_ERROR() \ if (&__asan_on_error) __asan_on_error() extern int asan_inited; // Used to avoid infinite recursion in __asan_init(). extern bool asan_init_is_running; extern void (*death_callback)(void); // These magic values are written to shadow for better error reporting. const int kAsanHeapLeftRedzoneMagic = 0xfa; -const int kAsanHeapRightRedzoneMagic = 0xfb; const int kAsanHeapFreeMagic = 0xfd; const int kAsanStackLeftRedzoneMagic = 0xf1; const int kAsanStackMidRedzoneMagic = 0xf2; const int kAsanStackRightRedzoneMagic = 0xf3; -const int kAsanStackPartialRedzoneMagic = 0xf4; const int kAsanStackAfterReturnMagic = 0xf5; const int kAsanInitializationOrderMagic = 0xf6; const int kAsanUserPoisonedMemoryMagic = 0xf7; const int kAsanContiguousContainerOOBMagic = 0xfc; const int kAsanStackUseAfterScopeMagic = 0xf8; const int kAsanGlobalRedzoneMagic = 0xf9; const int kAsanInternalHeapMagic = 0xfe; const int kAsanArrayCookieMagic = 0xac; const int kAsanIntraObjectRedzone = 0xbb; const int kAsanAllocaLeftMagic = 0xca; const int kAsanAllocaRightMagic = 0xcb; static const uptr kCurrentStackFrameMagic = 0x41B58AB3; static const uptr kRetiredStackFrameMagic = 0x45E0360E; } // namespace __asan #endif // ASAN_INTERNAL_H Index: projects/clang400-import/contrib/compiler-rt/lib/asan/asan_mac.cc =================================================================== --- projects/clang400-import/contrib/compiler-rt/lib/asan/asan_mac.cc (revision 311696) +++ projects/clang400-import/contrib/compiler-rt/lib/asan/asan_mac.cc (revision 311697) @@ -1,296 +1,287 @@ //===-- asan_mac.cc -------------------------------------------------------===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // This file is a part of AddressSanitizer, an address sanity checker. // // Mac-specific details. //===----------------------------------------------------------------------===// #include "sanitizer_common/sanitizer_platform.h" #if SANITIZER_MAC #include "asan_interceptors.h" #include "asan_internal.h" #include "asan_mapping.h" #include "asan_stack.h" #include "asan_thread.h" #include "sanitizer_common/sanitizer_atomic.h" #include "sanitizer_common/sanitizer_libc.h" #include "sanitizer_common/sanitizer_mac.h" #include #include #include #include #include #include #include #include // for free() #include #include #include #include #include // from , but we don't have that file on iOS extern "C" { extern char ***_NSGetArgv(void); extern char ***_NSGetEnviron(void); } namespace __asan { void InitializePlatformInterceptors() {} void InitializePlatformExceptionHandlers() {} -bool PlatformHasDifferentMemcpyAndMemmove() { - // On OS X 10.7 memcpy() and memmove() are both resolved - // into memmove$VARIANT$sse42. - // See also https://github.com/google/sanitizers/issues/34. - // TODO(glider): need to check dynamically that memcpy() and memmove() are - // actually the same function. - return GetMacosVersion() == MACOS_VERSION_SNOW_LEOPARD; -} - // No-op. Mac does not support static linkage anyway. void *AsanDoesNotSupportStaticLinkage() { return 0; } // No-op. Mac does not support static linkage anyway. void AsanCheckDynamicRTPrereqs() {} // No-op. Mac does not support static linkage anyway. void AsanCheckIncompatibleRT() {} void AsanApplyToGlobals(globals_op_fptr op, const void *needle) { // Find the Mach-O header for the image containing the needle Dl_info info; int err = dladdr(needle, &info); if (err == 0) return; #if __LP64__ const struct mach_header_64 *mh = (struct mach_header_64 *)info.dli_fbase; #else const struct mach_header *mh = (struct mach_header *)info.dli_fbase; #endif // Look up the __asan_globals section in that image and register its globals unsigned long size = 0; __asan_global *globals = (__asan_global *)getsectiondata( mh, "__DATA", "__asan_globals", &size); if (!globals) return; if (size % sizeof(__asan_global) != 0) return; op(globals, size / sizeof(__asan_global)); } void ReadContextStack(void *context, uptr *stack, uptr *ssize) { UNIMPLEMENTED(); } // Support for the following functions from libdispatch on Mac OS: // dispatch_async_f() // dispatch_async() // dispatch_sync_f() // dispatch_sync() // dispatch_after_f() // dispatch_after() // dispatch_group_async_f() // dispatch_group_async() // TODO(glider): libdispatch API contains other functions that we don't support // yet. // // dispatch_sync() and dispatch_sync_f() are synchronous, although chances are // they can cause jobs to run on a thread different from the current one. // TODO(glider): if so, we need a test for this (otherwise we should remove // them). // // The following functions use dispatch_barrier_async_f() (which isn't a library // function but is exported) and are thus supported: // dispatch_source_set_cancel_handler_f() // dispatch_source_set_cancel_handler() // dispatch_source_set_event_handler_f() // dispatch_source_set_event_handler() // // The reference manual for Grand Central Dispatch is available at // http://developer.apple.com/library/mac/#documentation/Performance/Reference/GCD_libdispatch_Ref/Reference/reference.html // The implementation details are at // http://libdispatch.macosforge.org/trac/browser/trunk/src/queue.c typedef void* dispatch_group_t; typedef void* dispatch_queue_t; typedef void* dispatch_source_t; typedef u64 dispatch_time_t; typedef void (*dispatch_function_t)(void *block); typedef void* (*worker_t)(void *block); // A wrapper for the ObjC blocks used to support libdispatch. typedef struct { void *block; dispatch_function_t func; u32 parent_tid; } asan_block_context_t; ALWAYS_INLINE void asan_register_worker_thread(int parent_tid, StackTrace *stack) { AsanThread *t = GetCurrentThread(); if (!t) { t = AsanThread::Create(/* start_routine */ nullptr, /* arg */ nullptr, parent_tid, stack, /* detached */ true); t->Init(); asanThreadRegistry().StartThread(t->tid(), 0, 0); SetCurrentThread(t); } } // For use by only those functions that allocated the context via // alloc_asan_context(). extern "C" void asan_dispatch_call_block_and_release(void *block) { GET_STACK_TRACE_THREAD; asan_block_context_t *context = (asan_block_context_t*)block; VReport(2, "asan_dispatch_call_block_and_release(): " "context: %p, pthread_self: %p\n", block, pthread_self()); asan_register_worker_thread(context->parent_tid, &stack); // Call the original dispatcher for the block. context->func(context->block); asan_free(context, &stack, FROM_MALLOC); } } // namespace __asan using namespace __asan; // NOLINT // Wrap |ctxt| and |func| into an asan_block_context_t. // The caller retains control of the allocated context. extern "C" asan_block_context_t *alloc_asan_context(void *ctxt, dispatch_function_t func, BufferedStackTrace *stack) { asan_block_context_t *asan_ctxt = (asan_block_context_t*) asan_malloc(sizeof(asan_block_context_t), stack); asan_ctxt->block = ctxt; asan_ctxt->func = func; asan_ctxt->parent_tid = GetCurrentTidOrInvalid(); return asan_ctxt; } // Define interceptor for dispatch_*_f function with the three most common // parameters: dispatch_queue_t, context, dispatch_function_t. #define INTERCEPT_DISPATCH_X_F_3(dispatch_x_f) \ INTERCEPTOR(void, dispatch_x_f, dispatch_queue_t dq, void *ctxt, \ dispatch_function_t func) { \ GET_STACK_TRACE_THREAD; \ asan_block_context_t *asan_ctxt = alloc_asan_context(ctxt, func, &stack); \ if (Verbosity() >= 2) { \ Report(#dispatch_x_f "(): context: %p, pthread_self: %p\n", \ asan_ctxt, pthread_self()); \ PRINT_CURRENT_STACK(); \ } \ return REAL(dispatch_x_f)(dq, (void*)asan_ctxt, \ asan_dispatch_call_block_and_release); \ } INTERCEPT_DISPATCH_X_F_3(dispatch_async_f) INTERCEPT_DISPATCH_X_F_3(dispatch_sync_f) INTERCEPT_DISPATCH_X_F_3(dispatch_barrier_async_f) INTERCEPTOR(void, dispatch_after_f, dispatch_time_t when, dispatch_queue_t dq, void *ctxt, dispatch_function_t func) { GET_STACK_TRACE_THREAD; asan_block_context_t *asan_ctxt = alloc_asan_context(ctxt, func, &stack); if (Verbosity() >= 2) { Report("dispatch_after_f: %p\n", asan_ctxt); PRINT_CURRENT_STACK(); } return REAL(dispatch_after_f)(when, dq, (void*)asan_ctxt, asan_dispatch_call_block_and_release); } INTERCEPTOR(void, dispatch_group_async_f, dispatch_group_t group, dispatch_queue_t dq, void *ctxt, dispatch_function_t func) { GET_STACK_TRACE_THREAD; asan_block_context_t *asan_ctxt = alloc_asan_context(ctxt, func, &stack); if (Verbosity() >= 2) { Report("dispatch_group_async_f(): context: %p, pthread_self: %p\n", asan_ctxt, pthread_self()); PRINT_CURRENT_STACK(); } REAL(dispatch_group_async_f)(group, dq, (void*)asan_ctxt, asan_dispatch_call_block_and_release); } #if !defined(MISSING_BLOCKS_SUPPORT) extern "C" { void dispatch_async(dispatch_queue_t dq, void(^work)(void)); void dispatch_group_async(dispatch_group_t dg, dispatch_queue_t dq, void(^work)(void)); void dispatch_after(dispatch_time_t when, dispatch_queue_t queue, void(^work)(void)); void dispatch_source_set_cancel_handler(dispatch_source_t ds, void(^work)(void)); void dispatch_source_set_event_handler(dispatch_source_t ds, void(^work)(void)); } #define GET_ASAN_BLOCK(work) \ void (^asan_block)(void); \ int parent_tid = GetCurrentTidOrInvalid(); \ asan_block = ^(void) { \ GET_STACK_TRACE_THREAD; \ asan_register_worker_thread(parent_tid, &stack); \ work(); \ } INTERCEPTOR(void, dispatch_async, dispatch_queue_t dq, void(^work)(void)) { ENABLE_FRAME_POINTER; GET_ASAN_BLOCK(work); REAL(dispatch_async)(dq, asan_block); } INTERCEPTOR(void, dispatch_group_async, dispatch_group_t dg, dispatch_queue_t dq, void(^work)(void)) { ENABLE_FRAME_POINTER; GET_ASAN_BLOCK(work); REAL(dispatch_group_async)(dg, dq, asan_block); } INTERCEPTOR(void, dispatch_after, dispatch_time_t when, dispatch_queue_t queue, void(^work)(void)) { ENABLE_FRAME_POINTER; GET_ASAN_BLOCK(work); REAL(dispatch_after)(when, queue, asan_block); } INTERCEPTOR(void, dispatch_source_set_cancel_handler, dispatch_source_t ds, void(^work)(void)) { if (!work) { REAL(dispatch_source_set_cancel_handler)(ds, work); return; } ENABLE_FRAME_POINTER; GET_ASAN_BLOCK(work); REAL(dispatch_source_set_cancel_handler)(ds, asan_block); } INTERCEPTOR(void, dispatch_source_set_event_handler, dispatch_source_t ds, void(^work)(void)) { ENABLE_FRAME_POINTER; GET_ASAN_BLOCK(work); REAL(dispatch_source_set_event_handler)(ds, asan_block); } #endif #endif // SANITIZER_MAC Index: projects/clang400-import/contrib/compiler-rt/lib/asan/asan_malloc_linux.cc =================================================================== --- projects/clang400-import/contrib/compiler-rt/lib/asan/asan_malloc_linux.cc (revision 311696) +++ projects/clang400-import/contrib/compiler-rt/lib/asan/asan_malloc_linux.cc (revision 311697) @@ -1,209 +1,215 @@ //===-- asan_malloc_linux.cc ----------------------------------------------===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // This file is a part of AddressSanitizer, an address sanity checker. // // Linux-specific malloc interception. // We simply define functions like malloc, free, realloc, etc. // They will replace the corresponding libc functions automagically. //===----------------------------------------------------------------------===// #include "sanitizer_common/sanitizer_platform.h" #if SANITIZER_FREEBSD || SANITIZER_LINUX #include "sanitizer_common/sanitizer_tls_get_addr.h" #include "asan_allocator.h" #include "asan_interceptors.h" #include "asan_internal.h" #include "asan_stack.h" // ---------------------- Replacement functions ---------------- {{{1 using namespace __asan; // NOLINT static uptr allocated_for_dlsym; static const uptr kDlsymAllocPoolSize = 1024; static uptr alloc_memory_for_dlsym[kDlsymAllocPoolSize]; static bool IsInDlsymAllocPool(const void *ptr) { uptr off = (uptr)ptr - (uptr)alloc_memory_for_dlsym; return off < sizeof(alloc_memory_for_dlsym); } static void *AllocateFromLocalPool(uptr size_in_bytes) { uptr size_in_words = RoundUpTo(size_in_bytes, kWordSize) / kWordSize; void *mem = (void*)&alloc_memory_for_dlsym[allocated_for_dlsym]; allocated_for_dlsym += size_in_words; CHECK_LT(allocated_for_dlsym, kDlsymAllocPoolSize); return mem; } INTERCEPTOR(void, free, void *ptr) { GET_STACK_TRACE_FREE; if (UNLIKELY(IsInDlsymAllocPool(ptr))) return; asan_free(ptr, &stack, FROM_MALLOC); } INTERCEPTOR(void, cfree, void *ptr) { GET_STACK_TRACE_FREE; if (UNLIKELY(IsInDlsymAllocPool(ptr))) return; asan_free(ptr, &stack, FROM_MALLOC); } INTERCEPTOR(void*, malloc, uptr size) { if (UNLIKELY(!asan_inited)) // Hack: dlsym calls malloc before REAL(malloc) is retrieved from dlsym. return AllocateFromLocalPool(size); GET_STACK_TRACE_MALLOC; return asan_malloc(size, &stack); } INTERCEPTOR(void*, calloc, uptr nmemb, uptr size) { if (UNLIKELY(!asan_inited)) // Hack: dlsym calls calloc before REAL(calloc) is retrieved from dlsym. return AllocateFromLocalPool(nmemb * size); GET_STACK_TRACE_MALLOC; return asan_calloc(nmemb, size, &stack); } INTERCEPTOR(void*, realloc, void *ptr, uptr size) { GET_STACK_TRACE_MALLOC; if (UNLIKELY(IsInDlsymAllocPool(ptr))) { uptr offset = (uptr)ptr - (uptr)alloc_memory_for_dlsym; uptr copy_size = Min(size, kDlsymAllocPoolSize - offset); - void *new_ptr = asan_malloc(size, &stack); + void *new_ptr; + if (UNLIKELY(!asan_inited)) { + new_ptr = AllocateFromLocalPool(size); + } else { + copy_size = size; + new_ptr = asan_malloc(copy_size, &stack); + } internal_memcpy(new_ptr, ptr, copy_size); return new_ptr; } return asan_realloc(ptr, size, &stack); } INTERCEPTOR(void*, memalign, uptr boundary, uptr size) { GET_STACK_TRACE_MALLOC; return asan_memalign(boundary, size, &stack, FROM_MALLOC); } INTERCEPTOR(void*, aligned_alloc, uptr boundary, uptr size) { GET_STACK_TRACE_MALLOC; return asan_memalign(boundary, size, &stack, FROM_MALLOC); } INTERCEPTOR(void*, __libc_memalign, uptr boundary, uptr size) { GET_STACK_TRACE_MALLOC; void *res = asan_memalign(boundary, size, &stack, FROM_MALLOC); DTLS_on_libc_memalign(res, size); return res; } INTERCEPTOR(uptr, malloc_usable_size, void *ptr) { GET_CURRENT_PC_BP_SP; (void)sp; return asan_malloc_usable_size(ptr, pc, bp); } // We avoid including malloc.h for portability reasons. // man mallinfo says the fields are "long", but the implementation uses int. // It doesn't matter much -- we just need to make sure that the libc's mallinfo // is not called. struct fake_mallinfo { int x[10]; }; INTERCEPTOR(struct fake_mallinfo, mallinfo, void) { struct fake_mallinfo res; REAL(memset)(&res, 0, sizeof(res)); return res; } INTERCEPTOR(int, mallopt, int cmd, int value) { return -1; } INTERCEPTOR(int, posix_memalign, void **memptr, uptr alignment, uptr size) { GET_STACK_TRACE_MALLOC; // Printf("posix_memalign: %zx %zu\n", alignment, size); return asan_posix_memalign(memptr, alignment, size, &stack); } INTERCEPTOR(void*, valloc, uptr size) { GET_STACK_TRACE_MALLOC; return asan_valloc(size, &stack); } INTERCEPTOR(void*, pvalloc, uptr size) { GET_STACK_TRACE_MALLOC; return asan_pvalloc(size, &stack); } INTERCEPTOR(void, malloc_stats, void) { __asan_print_accumulated_stats(); } #if SANITIZER_ANDROID // Format of __libc_malloc_dispatch has changed in Android L. // While we are moving towards a solution that does not depend on bionic // internals, here is something to support both K* and L releases. struct MallocDebugK { void *(*malloc)(uptr bytes); void (*free)(void *mem); void *(*calloc)(uptr n_elements, uptr elem_size); void *(*realloc)(void *oldMem, uptr bytes); void *(*memalign)(uptr alignment, uptr bytes); uptr (*malloc_usable_size)(void *mem); }; struct MallocDebugL { void *(*calloc)(uptr n_elements, uptr elem_size); void (*free)(void *mem); fake_mallinfo (*mallinfo)(void); void *(*malloc)(uptr bytes); uptr (*malloc_usable_size)(void *mem); void *(*memalign)(uptr alignment, uptr bytes); int (*posix_memalign)(void **memptr, uptr alignment, uptr size); void* (*pvalloc)(uptr size); void *(*realloc)(void *oldMem, uptr bytes); void* (*valloc)(uptr size); }; ALIGNED(32) const MallocDebugK asan_malloc_dispatch_k = { WRAP(malloc), WRAP(free), WRAP(calloc), WRAP(realloc), WRAP(memalign), WRAP(malloc_usable_size)}; ALIGNED(32) const MallocDebugL asan_malloc_dispatch_l = { WRAP(calloc), WRAP(free), WRAP(mallinfo), WRAP(malloc), WRAP(malloc_usable_size), WRAP(memalign), WRAP(posix_memalign), WRAP(pvalloc), WRAP(realloc), WRAP(valloc)}; namespace __asan { void ReplaceSystemMalloc() { void **__libc_malloc_dispatch_p = (void **)AsanDlSymNext("__libc_malloc_dispatch"); if (__libc_malloc_dispatch_p) { // Decide on K vs L dispatch format by the presence of // __libc_malloc_default_dispatch export in libc. void *default_dispatch_p = AsanDlSymNext("__libc_malloc_default_dispatch"); if (default_dispatch_p) *__libc_malloc_dispatch_p = (void *)&asan_malloc_dispatch_k; else *__libc_malloc_dispatch_p = (void *)&asan_malloc_dispatch_l; } } } // namespace __asan #else // SANITIZER_ANDROID namespace __asan { void ReplaceSystemMalloc() { } } // namespace __asan #endif // SANITIZER_ANDROID #endif // SANITIZER_FREEBSD || SANITIZER_LINUX Index: projects/clang400-import/contrib/compiler-rt/lib/asan/asan_malloc_win.cc =================================================================== --- projects/clang400-import/contrib/compiler-rt/lib/asan/asan_malloc_win.cc (revision 311696) +++ projects/clang400-import/contrib/compiler-rt/lib/asan/asan_malloc_win.cc (revision 311697) @@ -1,251 +1,257 @@ //===-- asan_malloc_win.cc ------------------------------------------------===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // This file is a part of AddressSanitizer, an address sanity checker. // // Windows-specific malloc interception. //===----------------------------------------------------------------------===// #include "sanitizer_common/sanitizer_platform.h" #if SANITIZER_WINDOWS #define WIN32_LEAN_AND_MEAN #include #include "asan_allocator.h" #include "asan_interceptors.h" #include "asan_internal.h" #include "asan_stack.h" #include "interception/interception.h" #include using namespace __asan; // NOLINT // MT: Simply defining functions with the same signature in *.obj // files overrides the standard functions in the CRT. // MD: Memory allocation functions are defined in the CRT .dll, // so we have to intercept them before they are called for the first time. #if ASAN_DYNAMIC # define ALLOCATION_FUNCTION_ATTRIBUTE #else # define ALLOCATION_FUNCTION_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE #endif extern "C" { ALLOCATION_FUNCTION_ATTRIBUTE void free(void *ptr) { GET_STACK_TRACE_FREE; return asan_free(ptr, &stack, FROM_MALLOC); } ALLOCATION_FUNCTION_ATTRIBUTE void _free_dbg(void *ptr, int) { free(ptr); } ALLOCATION_FUNCTION_ATTRIBUTE void _free_base(void *ptr) { free(ptr); } ALLOCATION_FUNCTION_ATTRIBUTE void cfree(void *ptr) { CHECK(!"cfree() should not be used on Windows"); } ALLOCATION_FUNCTION_ATTRIBUTE void *malloc(size_t size) { GET_STACK_TRACE_MALLOC; return asan_malloc(size, &stack); } ALLOCATION_FUNCTION_ATTRIBUTE void *_malloc_base(size_t size) { return malloc(size); } ALLOCATION_FUNCTION_ATTRIBUTE void *_malloc_dbg(size_t size, int, const char *, int) { return malloc(size); } ALLOCATION_FUNCTION_ATTRIBUTE void *calloc(size_t nmemb, size_t size) { GET_STACK_TRACE_MALLOC; return asan_calloc(nmemb, size, &stack); } ALLOCATION_FUNCTION_ATTRIBUTE void *_calloc_base(size_t nmemb, size_t size) { return calloc(nmemb, size); } ALLOCATION_FUNCTION_ATTRIBUTE void *_calloc_dbg(size_t nmemb, size_t size, int, const char *, int) { return calloc(nmemb, size); } ALLOCATION_FUNCTION_ATTRIBUTE void *_calloc_impl(size_t nmemb, size_t size, int *errno_tmp) { return calloc(nmemb, size); } ALLOCATION_FUNCTION_ATTRIBUTE void *realloc(void *ptr, size_t size) { GET_STACK_TRACE_MALLOC; return asan_realloc(ptr, size, &stack); } ALLOCATION_FUNCTION_ATTRIBUTE void *_realloc_dbg(void *ptr, size_t size, int) { CHECK(!"_realloc_dbg should not exist!"); return 0; } ALLOCATION_FUNCTION_ATTRIBUTE void *_realloc_base(void *ptr, size_t size) { return realloc(ptr, size); } ALLOCATION_FUNCTION_ATTRIBUTE void *_recalloc(void *p, size_t n, size_t elem_size) { if (!p) return calloc(n, elem_size); const size_t size = n * elem_size; if (elem_size != 0 && size / elem_size != n) return 0; return realloc(p, size); } ALLOCATION_FUNCTION_ATTRIBUTE +void *_recalloc_base(void *p, size_t n, size_t elem_size) { + return _recalloc(p, n, elem_size); +} + +ALLOCATION_FUNCTION_ATTRIBUTE size_t _msize(const void *ptr) { GET_CURRENT_PC_BP_SP; (void)sp; return asan_malloc_usable_size(ptr, pc, bp); } ALLOCATION_FUNCTION_ATTRIBUTE void *_expand(void *memblock, size_t size) { // _expand is used in realloc-like functions to resize the buffer if possible. // We don't want memory to stand still while resizing buffers, so return 0. return 0; } ALLOCATION_FUNCTION_ATTRIBUTE void *_expand_dbg(void *memblock, size_t size) { return _expand(memblock, size); } // TODO(timurrrr): Might want to add support for _aligned_* allocation // functions to detect a bit more bugs. Those functions seem to wrap malloc(). int _CrtDbgReport(int, const char*, int, const char*, const char*, ...) { ShowStatsAndAbort(); } int _CrtDbgReportW(int reportType, const wchar_t*, int, const wchar_t*, const wchar_t*, ...) { ShowStatsAndAbort(); } int _CrtSetReportMode(int, int) { return 0; } } // extern "C" INTERCEPTOR_WINAPI(LPVOID, HeapAlloc, HANDLE hHeap, DWORD dwFlags, SIZE_T dwBytes) { GET_STACK_TRACE_MALLOC; void *p = asan_malloc(dwBytes, &stack); // Reading MSDN suggests that the *entire* usable allocation is zeroed out. // Otherwise it is difficult to HeapReAlloc with HEAP_ZERO_MEMORY. // https://blogs.msdn.microsoft.com/oldnewthing/20120316-00/?p=8083 if (dwFlags == HEAP_ZERO_MEMORY) internal_memset(p, 0, asan_mz_size(p)); else CHECK(dwFlags == 0 && "unsupported heap flags"); return p; } INTERCEPTOR_WINAPI(BOOL, HeapFree, HANDLE hHeap, DWORD dwFlags, LPVOID lpMem) { CHECK(dwFlags == 0 && "unsupported heap flags"); GET_STACK_TRACE_FREE; asan_free(lpMem, &stack, FROM_MALLOC); return true; } INTERCEPTOR_WINAPI(LPVOID, HeapReAlloc, HANDLE hHeap, DWORD dwFlags, LPVOID lpMem, SIZE_T dwBytes) { GET_STACK_TRACE_MALLOC; // Realloc should never reallocate in place. if (dwFlags & HEAP_REALLOC_IN_PLACE_ONLY) return nullptr; CHECK(dwFlags == 0 && "unsupported heap flags"); return asan_realloc(lpMem, dwBytes, &stack); } INTERCEPTOR_WINAPI(SIZE_T, HeapSize, HANDLE hHeap, DWORD dwFlags, LPCVOID lpMem) { CHECK(dwFlags == 0 && "unsupported heap flags"); GET_CURRENT_PC_BP_SP; (void)sp; return asan_malloc_usable_size(lpMem, pc, bp); } namespace __asan { static void TryToOverrideFunction(const char *fname, uptr new_func) { // Failure here is not fatal. The CRT may not be present, and different CRT // versions use different symbols. if (!__interception::OverrideFunction(fname, new_func)) VPrintf(2, "Failed to override function %s\n", fname); } void ReplaceSystemMalloc() { #if defined(ASAN_DYNAMIC) TryToOverrideFunction("free", (uptr)free); TryToOverrideFunction("_free_base", (uptr)free); TryToOverrideFunction("malloc", (uptr)malloc); TryToOverrideFunction("_malloc_base", (uptr)malloc); TryToOverrideFunction("_malloc_crt", (uptr)malloc); TryToOverrideFunction("calloc", (uptr)calloc); TryToOverrideFunction("_calloc_base", (uptr)calloc); TryToOverrideFunction("_calloc_crt", (uptr)calloc); TryToOverrideFunction("realloc", (uptr)realloc); TryToOverrideFunction("_realloc_base", (uptr)realloc); TryToOverrideFunction("_realloc_crt", (uptr)realloc); TryToOverrideFunction("_recalloc", (uptr)_recalloc); + TryToOverrideFunction("_recalloc_base", (uptr)_recalloc); TryToOverrideFunction("_recalloc_crt", (uptr)_recalloc); TryToOverrideFunction("_msize", (uptr)_msize); TryToOverrideFunction("_expand", (uptr)_expand); TryToOverrideFunction("_expand_base", (uptr)_expand); // Recent versions of ucrtbase.dll appear to be built with PGO and LTCG, which // enable cross-module inlining. This means our _malloc_base hook won't catch // all CRT allocations. This code here patches the import table of // ucrtbase.dll so that all attempts to use the lower-level win32 heap // allocation API will be directed to ASan's heap. We don't currently // intercept all calls to HeapAlloc. If we did, we would have to check on // HeapFree whether the pointer came from ASan of from the system. #define INTERCEPT_UCRT_FUNCTION(func) \ if (!INTERCEPT_FUNCTION_DLLIMPORT("ucrtbase.dll", \ "api-ms-win-core-heap-l1-1-0.dll", func)) \ VPrintf(2, "Failed to intercept ucrtbase.dll import %s\n", #func); INTERCEPT_UCRT_FUNCTION(HeapAlloc); INTERCEPT_UCRT_FUNCTION(HeapFree); INTERCEPT_UCRT_FUNCTION(HeapReAlloc); INTERCEPT_UCRT_FUNCTION(HeapSize); #undef INTERCEPT_UCRT_FUNCTION #endif } } // namespace __asan #endif // _WIN32 Index: projects/clang400-import/contrib/compiler-rt/lib/asan/asan_mapping.h =================================================================== --- projects/clang400-import/contrib/compiler-rt/lib/asan/asan_mapping.h (revision 311696) +++ projects/clang400-import/contrib/compiler-rt/lib/asan/asan_mapping.h (revision 311697) @@ -1,336 +1,337 @@ //===-- asan_mapping.h ------------------------------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // This file is a part of AddressSanitizer, an address sanity checker. // // Defines ASan memory mapping. //===----------------------------------------------------------------------===// #ifndef ASAN_MAPPING_H #define ASAN_MAPPING_H #include "asan_internal.h" // The full explanation of the memory mapping could be found here: // https://github.com/google/sanitizers/wiki/AddressSanitizerAlgorithm // // Typical shadow mapping on Linux/x86_64 with SHADOW_OFFSET == 0x00007fff8000: // || `[0x10007fff8000, 0x7fffffffffff]` || HighMem || // || `[0x02008fff7000, 0x10007fff7fff]` || HighShadow || // || `[0x00008fff7000, 0x02008fff6fff]` || ShadowGap || // || `[0x00007fff8000, 0x00008fff6fff]` || LowShadow || // || `[0x000000000000, 0x00007fff7fff]` || LowMem || // // When SHADOW_OFFSET is zero (-pie): // || `[0x100000000000, 0x7fffffffffff]` || HighMem || // || `[0x020000000000, 0x0fffffffffff]` || HighShadow || // || `[0x000000040000, 0x01ffffffffff]` || ShadowGap || // // Special case when something is already mapped between // 0x003000000000 and 0x005000000000 (e.g. when prelink is installed): // || `[0x10007fff8000, 0x7fffffffffff]` || HighMem || // || `[0x02008fff7000, 0x10007fff7fff]` || HighShadow || // || `[0x005000000000, 0x02008fff6fff]` || ShadowGap3 || // || `[0x003000000000, 0x004fffffffff]` || MidMem || // || `[0x000a7fff8000, 0x002fffffffff]` || ShadowGap2 || // || `[0x00067fff8000, 0x000a7fff7fff]` || MidShadow || // || `[0x00008fff7000, 0x00067fff7fff]` || ShadowGap || // || `[0x00007fff8000, 0x00008fff6fff]` || LowShadow || // || `[0x000000000000, 0x00007fff7fff]` || LowMem || // // Default Linux/i386 mapping on x86_64 machine: // || `[0x40000000, 0xffffffff]` || HighMem || // || `[0x28000000, 0x3fffffff]` || HighShadow || // || `[0x24000000, 0x27ffffff]` || ShadowGap || // || `[0x20000000, 0x23ffffff]` || LowShadow || // || `[0x00000000, 0x1fffffff]` || LowMem || // // Default Linux/i386 mapping on i386 machine // (addresses starting with 0xc0000000 are reserved // for kernel and thus not sanitized): // || `[0x38000000, 0xbfffffff]` || HighMem || // || `[0x27000000, 0x37ffffff]` || HighShadow || // || `[0x24000000, 0x26ffffff]` || ShadowGap || // || `[0x20000000, 0x23ffffff]` || LowShadow || // || `[0x00000000, 0x1fffffff]` || LowMem || // // Default Linux/MIPS32 mapping: // || `[0x2aaa0000, 0xffffffff]` || HighMem || // || `[0x0fff4000, 0x2aa9ffff]` || HighShadow || // || `[0x0bff4000, 0x0fff3fff]` || ShadowGap || // || `[0x0aaa0000, 0x0bff3fff]` || LowShadow || // || `[0x00000000, 0x0aa9ffff]` || LowMem || // // Default Linux/MIPS64 mapping: // || `[0x4000000000, 0xffffffffff]` || HighMem || // || `[0x2800000000, 0x3fffffffff]` || HighShadow || // || `[0x2400000000, 0x27ffffffff]` || ShadowGap || // || `[0x2000000000, 0x23ffffffff]` || LowShadow || // || `[0x0000000000, 0x1fffffffff]` || LowMem || // // Default Linux/AArch64 (39-bit VMA) mapping: // || `[0x2000000000, 0x7fffffffff]` || highmem || // || `[0x1400000000, 0x1fffffffff]` || highshadow || // || `[0x1200000000, 0x13ffffffff]` || shadowgap || // || `[0x1000000000, 0x11ffffffff]` || lowshadow || // || `[0x0000000000, 0x0fffffffff]` || lowmem || // // Default Linux/AArch64 (42-bit VMA) mapping: // || `[0x10000000000, 0x3ffffffffff]` || highmem || // || `[0x0a000000000, 0x0ffffffffff]` || highshadow || // || `[0x09000000000, 0x09fffffffff]` || shadowgap || // || `[0x08000000000, 0x08fffffffff]` || lowshadow || // || `[0x00000000000, 0x07fffffffff]` || lowmem || // // Default Linux/S390 mapping: // || `[0x30000000, 0x7fffffff]` || HighMem || // || `[0x26000000, 0x2fffffff]` || HighShadow || // || `[0x24000000, 0x25ffffff]` || ShadowGap || // || `[0x20000000, 0x23ffffff]` || LowShadow || // || `[0x00000000, 0x1fffffff]` || LowMem || // // Default Linux/SystemZ mapping: // || `[0x14000000000000, 0x1fffffffffffff]` || HighMem || // || `[0x12800000000000, 0x13ffffffffffff]` || HighShadow || // || `[0x12000000000000, 0x127fffffffffff]` || ShadowGap || // || `[0x10000000000000, 0x11ffffffffffff]` || LowShadow || // || `[0x00000000000000, 0x0fffffffffffff]` || LowMem || // // Shadow mapping on FreeBSD/x86-64 with SHADOW_OFFSET == 0x400000000000: // || `[0x500000000000, 0x7fffffffffff]` || HighMem || // || `[0x4a0000000000, 0x4fffffffffff]` || HighShadow || // || `[0x480000000000, 0x49ffffffffff]` || ShadowGap || // || `[0x400000000000, 0x47ffffffffff]` || LowShadow || // || `[0x000000000000, 0x3fffffffffff]` || LowMem || // // Shadow mapping on FreeBSD/i386 with SHADOW_OFFSET == 0x40000000: // || `[0x60000000, 0xffffffff]` || HighMem || // || `[0x4c000000, 0x5fffffff]` || HighShadow || // || `[0x48000000, 0x4bffffff]` || ShadowGap || // || `[0x40000000, 0x47ffffff]` || LowShadow || // || `[0x00000000, 0x3fffffff]` || LowMem || // // Default Windows/i386 mapping: // (the exact location of HighShadow/HighMem may vary depending // on WoW64, /LARGEADDRESSAWARE, etc). // || `[0x50000000, 0xffffffff]` || HighMem || // || `[0x3a000000, 0x4fffffff]` || HighShadow || // || `[0x36000000, 0x39ffffff]` || ShadowGap || // || `[0x30000000, 0x35ffffff]` || LowShadow || // || `[0x00000000, 0x2fffffff]` || LowMem || static const u64 kDefaultShadowScale = 3; +static const u64 kDefaultShadowSentinel = ~(uptr)0; static const u64 kDefaultShadowOffset32 = 1ULL << 29; // 0x20000000 static const u64 kDefaultShadowOffset64 = 1ULL << 44; static const u64 kDefaultShort64bitShadowOffset = 0x7FFF8000; // < 2G. static const u64 kIosShadowOffset32 = 1ULL << 30; // 0x40000000 static const u64 kIosShadowOffset64 = 0x120200000; static const u64 kIosSimShadowOffset32 = 1ULL << 30; static const u64 kIosSimShadowOffset64 = kDefaultShadowOffset64; static const u64 kAArch64_ShadowOffset64 = 1ULL << 36; static const u64 kMIPS32_ShadowOffset32 = 0x0aaa0000; static const u64 kMIPS64_ShadowOffset64 = 1ULL << 37; static const u64 kPPC64_ShadowOffset64 = 1ULL << 41; static const u64 kSystemZ_ShadowOffset64 = 1ULL << 52; static const u64 kFreeBSD_ShadowOffset32 = 1ULL << 30; // 0x40000000 static const u64 kFreeBSD_ShadowOffset64 = 1ULL << 46; // 0x400000000000 static const u64 kWindowsShadowOffset32 = 3ULL << 28; // 0x30000000 -static const u64 kWindowsShadowOffset64 = 1ULL << 45; // 32TB #define SHADOW_SCALE kDefaultShadowScale #if SANITIZER_WORDSIZE == 32 # if SANITIZER_ANDROID # define SHADOW_OFFSET (0) # elif defined(__mips__) # define SHADOW_OFFSET kMIPS32_ShadowOffset32 # elif SANITIZER_FREEBSD # define SHADOW_OFFSET kFreeBSD_ShadowOffset32 # elif SANITIZER_WINDOWS # define SHADOW_OFFSET kWindowsShadowOffset32 # elif SANITIZER_IOS # if SANITIZER_IOSSIM # define SHADOW_OFFSET kIosSimShadowOffset32 # else # define SHADOW_OFFSET kIosShadowOffset32 # endif # else # define SHADOW_OFFSET kDefaultShadowOffset32 # endif #else # if SANITIZER_IOS # if SANITIZER_IOSSIM # define SHADOW_OFFSET kIosSimShadowOffset64 # else -# define SHADOW_OFFSET kIosShadowOffset64 +# define SHADOW_OFFSET __asan_shadow_memory_dynamic_address # endif # elif defined(__aarch64__) # define SHADOW_OFFSET kAArch64_ShadowOffset64 # elif defined(__powerpc64__) # define SHADOW_OFFSET kPPC64_ShadowOffset64 # elif defined(__s390x__) # define SHADOW_OFFSET kSystemZ_ShadowOffset64 # elif SANITIZER_FREEBSD # define SHADOW_OFFSET kFreeBSD_ShadowOffset64 # elif SANITIZER_MAC # define SHADOW_OFFSET kDefaultShadowOffset64 # elif defined(__mips64) # define SHADOW_OFFSET kMIPS64_ShadowOffset64 # elif SANITIZER_WINDOWS64 -# define SHADOW_OFFSET kWindowsShadowOffset64 +# define SHADOW_OFFSET __asan_shadow_memory_dynamic_address # else # define SHADOW_OFFSET kDefaultShort64bitShadowOffset # endif #endif #define SHADOW_GRANULARITY (1ULL << SHADOW_SCALE) #define MEM_TO_SHADOW(mem) (((mem) >> SHADOW_SCALE) + (SHADOW_OFFSET)) #define SHADOW_TO_MEM(shadow) (((shadow) - SHADOW_OFFSET) << SHADOW_SCALE) #define kLowMemBeg 0 #define kLowMemEnd (SHADOW_OFFSET ? SHADOW_OFFSET - 1 : 0) #define kLowShadowBeg SHADOW_OFFSET #define kLowShadowEnd MEM_TO_SHADOW(kLowMemEnd) #define kHighMemBeg (MEM_TO_SHADOW(kHighMemEnd) + 1) #define kHighShadowBeg MEM_TO_SHADOW(kHighMemBeg) #define kHighShadowEnd MEM_TO_SHADOW(kHighMemEnd) # define kMidShadowBeg MEM_TO_SHADOW(kMidMemBeg) # define kMidShadowEnd MEM_TO_SHADOW(kMidMemEnd) // With the zero shadow base we can not actually map pages starting from 0. // This constant is somewhat arbitrary. #define kZeroBaseShadowStart 0 #define kZeroBaseMaxShadowStart (1 << 18) #define kShadowGapBeg (kLowShadowEnd ? kLowShadowEnd + 1 \ : kZeroBaseShadowStart) #define kShadowGapEnd ((kMidMemBeg ? kMidShadowBeg : kHighShadowBeg) - 1) #define kShadowGap2Beg (kMidMemBeg ? kMidShadowEnd + 1 : 0) #define kShadowGap2End (kMidMemBeg ? kMidMemBeg - 1 : 0) #define kShadowGap3Beg (kMidMemBeg ? kMidMemEnd + 1 : 0) #define kShadowGap3End (kMidMemBeg ? kHighShadowBeg - 1 : 0) #define DO_ASAN_MAPPING_PROFILE 0 // Set to 1 to profile the functions below. #if DO_ASAN_MAPPING_PROFILE # define PROFILE_ASAN_MAPPING() AsanMappingProfile[__LINE__]++; #else # define PROFILE_ASAN_MAPPING() #endif // If 1, all shadow boundaries are constants. // Don't set to 1 other than for testing. #define ASAN_FIXED_MAPPING 0 namespace __asan { extern uptr AsanMappingProfile[]; #if ASAN_FIXED_MAPPING // Fixed mapping for 64-bit Linux. Mostly used for performance comparison // with non-fixed mapping. As of r175253 (Feb 2013) the performance // difference between fixed and non-fixed mapping is below the noise level. static uptr kHighMemEnd = 0x7fffffffffffULL; static uptr kMidMemBeg = 0x3000000000ULL; static uptr kMidMemEnd = 0x4fffffffffULL; #else extern uptr kHighMemEnd, kMidMemBeg, kMidMemEnd; // Initialized in __asan_init. #endif static inline bool AddrIsInLowMem(uptr a) { PROFILE_ASAN_MAPPING(); return a < kLowMemEnd; } static inline bool AddrIsInLowShadow(uptr a) { PROFILE_ASAN_MAPPING(); return a >= kLowShadowBeg && a <= kLowShadowEnd; } static inline bool AddrIsInHighMem(uptr a) { PROFILE_ASAN_MAPPING(); return a >= kHighMemBeg && a <= kHighMemEnd; } static inline bool AddrIsInMidMem(uptr a) { PROFILE_ASAN_MAPPING(); return kMidMemBeg && a >= kMidMemBeg && a <= kMidMemEnd; } +static inline bool AddrIsInShadowGap(uptr a) { + PROFILE_ASAN_MAPPING(); + if (kMidMemBeg) { + if (a <= kShadowGapEnd) + return SHADOW_OFFSET == 0 || a >= kShadowGapBeg; + return (a >= kShadowGap2Beg && a <= kShadowGap2End) || + (a >= kShadowGap3Beg && a <= kShadowGap3End); + } + // In zero-based shadow mode we treat addresses near zero as addresses + // in shadow gap as well. + if (SHADOW_OFFSET == 0) + return a <= kShadowGapEnd; + return a >= kShadowGapBeg && a <= kShadowGapEnd; +} + static inline bool AddrIsInMem(uptr a) { PROFILE_ASAN_MAPPING(); - return AddrIsInLowMem(a) || AddrIsInMidMem(a) || AddrIsInHighMem(a); + return AddrIsInLowMem(a) || AddrIsInMidMem(a) || AddrIsInHighMem(a) || + (flags()->protect_shadow_gap == 0 && AddrIsInShadowGap(a)); } static inline uptr MemToShadow(uptr p) { PROFILE_ASAN_MAPPING(); CHECK(AddrIsInMem(p)); return MEM_TO_SHADOW(p); } static inline bool AddrIsInHighShadow(uptr a) { PROFILE_ASAN_MAPPING(); return a >= kHighShadowBeg && a <= kHighMemEnd; } static inline bool AddrIsInMidShadow(uptr a) { PROFILE_ASAN_MAPPING(); return kMidMemBeg && a >= kMidShadowBeg && a <= kMidMemEnd; } static inline bool AddrIsInShadow(uptr a) { PROFILE_ASAN_MAPPING(); return AddrIsInLowShadow(a) || AddrIsInMidShadow(a) || AddrIsInHighShadow(a); -} - -static inline bool AddrIsInShadowGap(uptr a) { - PROFILE_ASAN_MAPPING(); - if (kMidMemBeg) { - if (a <= kShadowGapEnd) - return SHADOW_OFFSET == 0 || a >= kShadowGapBeg; - return (a >= kShadowGap2Beg && a <= kShadowGap2End) || - (a >= kShadowGap3Beg && a <= kShadowGap3End); - } - // In zero-based shadow mode we treat addresses near zero as addresses - // in shadow gap as well. - if (SHADOW_OFFSET == 0) - return a <= kShadowGapEnd; - return a >= kShadowGapBeg && a <= kShadowGapEnd; } static inline bool AddrIsAlignedByGranularity(uptr a) { PROFILE_ASAN_MAPPING(); return (a & (SHADOW_GRANULARITY - 1)) == 0; } static inline bool AddressIsPoisoned(uptr a) { PROFILE_ASAN_MAPPING(); const uptr kAccessSize = 1; u8 *shadow_address = (u8*)MEM_TO_SHADOW(a); s8 shadow_value = *shadow_address; if (shadow_value) { u8 last_accessed_byte = (a & (SHADOW_GRANULARITY - 1)) + kAccessSize - 1; return (last_accessed_byte >= shadow_value); } return false; } // Must be after all calls to PROFILE_ASAN_MAPPING(). static const uptr kAsanMappingProfileSize = __LINE__; } // namespace __asan #endif // ASAN_MAPPING_H Index: projects/clang400-import/contrib/compiler-rt/lib/asan/asan_memory_profile.cc =================================================================== --- projects/clang400-import/contrib/compiler-rt/lib/asan/asan_memory_profile.cc (revision 311696) +++ projects/clang400-import/contrib/compiler-rt/lib/asan/asan_memory_profile.cc (revision 311697) @@ -1,100 +1,118 @@ //===-- asan_memory_profile.cc.cc -----------------------------------------===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // This file is a part of AddressSanitizer, an address sanity checker. // // This file implements __sanitizer_print_memory_profile. //===----------------------------------------------------------------------===// #include "sanitizer_common/sanitizer_common.h" #include "sanitizer_common/sanitizer_stackdepot.h" #include "sanitizer_common/sanitizer_stacktrace.h" #include "sanitizer_common/sanitizer_stoptheworld.h" #include "lsan/lsan_common.h" #include "asan/asan_allocator.h" #if CAN_SANITIZE_LEAKS namespace __asan { struct AllocationSite { u32 id; uptr total_size; uptr count; }; class HeapProfile { public: HeapProfile() : allocations_(1024) {} - void Insert(u32 id, uptr size) { - total_allocated_ += size; - total_count_++; - // Linear lookup will be good enough for most cases (although not all). - for (uptr i = 0; i < allocations_.size(); i++) { - if (allocations_[i].id == id) { - allocations_[i].total_size += size; - allocations_[i].count++; - return; - } + + void ProcessChunk(const AsanChunkView& cv) { + if (cv.IsAllocated()) { + total_allocated_user_size_ += cv.UsedSize(); + total_allocated_count_++; + u32 id = cv.GetAllocStackId(); + if (id) + Insert(id, cv.UsedSize()); + } else if (cv.IsQuarantined()) { + total_quarantined_user_size_ += cv.UsedSize(); + total_quarantined_count_++; + } else { + total_other_count_++; } - allocations_.push_back({id, size, 1}); } void Print(uptr top_percent) { InternalSort(&allocations_, allocations_.size(), [](const AllocationSite &a, const AllocationSite &b) { return a.total_size > b.total_size; }); - CHECK(total_allocated_); + CHECK(total_allocated_user_size_); uptr total_shown = 0; - Printf("Live Heap Allocations: %zd bytes from %zd allocations; " - "showing top %zd%%\n", total_allocated_, total_count_, top_percent); + Printf("Live Heap Allocations: %zd bytes in %zd chunks; quarantined: " + "%zd bytes in %zd chunks; %zd other chunks; total chunks: %zd; " + "showing top %zd%%\n", + total_allocated_user_size_, total_allocated_count_, + total_quarantined_user_size_, total_quarantined_count_, + total_other_count_, total_allocated_count_ + + total_quarantined_count_ + total_other_count_, top_percent); for (uptr i = 0; i < allocations_.size(); i++) { auto &a = allocations_[i]; Printf("%zd byte(s) (%zd%%) in %zd allocation(s)\n", a.total_size, - a.total_size * 100 / total_allocated_, a.count); + a.total_size * 100 / total_allocated_user_size_, a.count); StackDepotGet(a.id).Print(); total_shown += a.total_size; - if (total_shown * 100 / total_allocated_ > top_percent) + if (total_shown * 100 / total_allocated_user_size_ > top_percent) break; } } private: - uptr total_allocated_ = 0; - uptr total_count_ = 0; + uptr total_allocated_user_size_ = 0; + uptr total_allocated_count_ = 0; + uptr total_quarantined_user_size_ = 0; + uptr total_quarantined_count_ = 0; + uptr total_other_count_ = 0; InternalMmapVector allocations_; + + void Insert(u32 id, uptr size) { + // Linear lookup will be good enough for most cases (although not all). + for (uptr i = 0; i < allocations_.size(); i++) { + if (allocations_[i].id == id) { + allocations_[i].total_size += size; + allocations_[i].count++; + return; + } + } + allocations_.push_back({id, size, 1}); + } }; static void ChunkCallback(uptr chunk, void *arg) { - HeapProfile *hp = reinterpret_cast(arg); - AsanChunkView cv = FindHeapChunkByAddress(chunk); - if (!cv.IsAllocated()) return; - u32 id = cv.GetAllocStackId(); - if (!id) return; - hp->Insert(id, cv.UsedSize()); + reinterpret_cast(arg)->ProcessChunk( + FindHeapChunkByAllocBeg(chunk)); } static void MemoryProfileCB(const SuspendedThreadsList &suspended_threads_list, void *argument) { HeapProfile hp; __lsan::ForEachChunk(ChunkCallback, &hp); hp.Print(reinterpret_cast(argument)); } } // namespace __asan extern "C" { SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_print_memory_profile(uptr top_percent) { __sanitizer::StopTheWorld(__asan::MemoryProfileCB, (void*)top_percent); } } // extern "C" #endif // CAN_SANITIZE_LEAKS Index: projects/clang400-import/contrib/compiler-rt/lib/asan/asan_new_delete.cc =================================================================== --- projects/clang400-import/contrib/compiler-rt/lib/asan/asan_new_delete.cc (revision 311696) +++ projects/clang400-import/contrib/compiler-rt/lib/asan/asan_new_delete.cc (revision 311697) @@ -1,148 +1,190 @@ //===-- asan_interceptors.cc ----------------------------------------------===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // This file is a part of AddressSanitizer, an address sanity checker. // // Interceptors for operators new and delete. //===----------------------------------------------------------------------===// #include "asan_allocator.h" #include "asan_internal.h" #include "asan_stack.h" #include "interception/interception.h" #include // C++ operators can't have dllexport attributes on Windows. We export them // anyway by passing extra -export flags to the linker, which is exactly that // dllexport would normally do. We need to export them in order to make the // VS2015 dynamic CRT (MD) work. #if SANITIZER_WINDOWS # define CXX_OPERATOR_ATTRIBUTE # ifdef _WIN64 # pragma comment(linker, "/export:??2@YAPEAX_K@Z") // operator new # pragma comment(linker, "/export:??3@YAXPEAX@Z") // operator delete # pragma comment(linker, "/export:??3@YAXPEAX_K@Z") // sized operator delete # pragma comment(linker, "/export:??_U@YAPEAX_K@Z") // operator new[] # pragma comment(linker, "/export:??_V@YAXPEAX@Z") // operator delete[] # else # pragma comment(linker, "/export:??2@YAPAXI@Z") // operator new # pragma comment(linker, "/export:??3@YAXPAX@Z") // operator delete # pragma comment(linker, "/export:??3@YAXPAXI@Z") // sized operator delete # pragma comment(linker, "/export:??_U@YAPAXI@Z") // operator new[] # pragma comment(linker, "/export:??_V@YAXPAX@Z") // operator delete[] # endif #else # define CXX_OPERATOR_ATTRIBUTE INTERCEPTOR_ATTRIBUTE #endif using namespace __asan; // NOLINT +// FreeBSD prior v9.2 have wrong definition of 'size_t'. +// http://svnweb.freebsd.org/base?view=revision&revision=232261 +#if SANITIZER_FREEBSD && SANITIZER_WORDSIZE == 32 +#include +#if __FreeBSD_version <= 902001 // v9.2 +#define size_t unsigned +#endif // __FreeBSD_version +#endif // SANITIZER_FREEBSD && SANITIZER_WORDSIZE == 32 + // This code has issues on OSX. // See https://github.com/google/sanitizers/issues/131. -// Fake std::nothrow_t to avoid including . +// Fake std::nothrow_t and std::align_val_t to avoid including . namespace std { struct nothrow_t {}; +enum class align_val_t: size_t {}; } // namespace std #define OPERATOR_NEW_BODY(type) \ GET_STACK_TRACE_MALLOC;\ return asan_memalign(0, size, &stack, type); +#define OPERATOR_NEW_BODY_ALIGN(type) \ + GET_STACK_TRACE_MALLOC;\ + return asan_memalign((uptr)align, size, &stack, type); // On OS X it's not enough to just provide our own 'operator new' and // 'operator delete' implementations, because they're going to be in the // runtime dylib, and the main executable will depend on both the runtime // dylib and libstdc++, each of those'll have its implementation of new and // delete. // To make sure that C++ allocation/deallocation operators are overridden on // OS X we need to intercept them using their mangled names. #if !SANITIZER_MAC -// FreeBSD prior v9.2 have wrong definition of 'size_t'. -// http://svnweb.freebsd.org/base?view=revision&revision=232261 -#if SANITIZER_FREEBSD && SANITIZER_WORDSIZE == 32 -#include -#if __FreeBSD_version <= 902001 // v9.2 -#define size_t unsigned -#endif // __FreeBSD_version -#endif // SANITIZER_FREEBSD && SANITIZER_WORDSIZE == 32 - CXX_OPERATOR_ATTRIBUTE void *operator new(size_t size) { OPERATOR_NEW_BODY(FROM_NEW); } CXX_OPERATOR_ATTRIBUTE void *operator new[](size_t size) { OPERATOR_NEW_BODY(FROM_NEW_BR); } CXX_OPERATOR_ATTRIBUTE void *operator new(size_t size, std::nothrow_t const&) { OPERATOR_NEW_BODY(FROM_NEW); } CXX_OPERATOR_ATTRIBUTE void *operator new[](size_t size, std::nothrow_t const&) { OPERATOR_NEW_BODY(FROM_NEW_BR); } +CXX_OPERATOR_ATTRIBUTE +void *operator new(size_t size, std::align_val_t align) +{ OPERATOR_NEW_BODY_ALIGN(FROM_NEW); } +CXX_OPERATOR_ATTRIBUTE +void *operator new[](size_t size, std::align_val_t align) +{ OPERATOR_NEW_BODY_ALIGN(FROM_NEW_BR); } +CXX_OPERATOR_ATTRIBUTE +void *operator new(size_t size, std::align_val_t align, std::nothrow_t const&) +{ OPERATOR_NEW_BODY_ALIGN(FROM_NEW); } +CXX_OPERATOR_ATTRIBUTE +void *operator new[](size_t size, std::align_val_t align, std::nothrow_t const&) +{ OPERATOR_NEW_BODY_ALIGN(FROM_NEW_BR); } #else // SANITIZER_MAC INTERCEPTOR(void *, _Znwm, size_t size) { OPERATOR_NEW_BODY(FROM_NEW); } INTERCEPTOR(void *, _Znam, size_t size) { OPERATOR_NEW_BODY(FROM_NEW_BR); } INTERCEPTOR(void *, _ZnwmRKSt9nothrow_t, size_t size, std::nothrow_t const&) { OPERATOR_NEW_BODY(FROM_NEW); } INTERCEPTOR(void *, _ZnamRKSt9nothrow_t, size_t size, std::nothrow_t const&) { OPERATOR_NEW_BODY(FROM_NEW_BR); } #endif #define OPERATOR_DELETE_BODY(type) \ GET_STACK_TRACE_FREE;\ asan_free(ptr, &stack, type); #if !SANITIZER_MAC CXX_OPERATOR_ATTRIBUTE void operator delete(void *ptr) NOEXCEPT { OPERATOR_DELETE_BODY(FROM_NEW); } CXX_OPERATOR_ATTRIBUTE void operator delete[](void *ptr) NOEXCEPT { OPERATOR_DELETE_BODY(FROM_NEW_BR); } CXX_OPERATOR_ATTRIBUTE void operator delete(void *ptr, std::nothrow_t const&) { OPERATOR_DELETE_BODY(FROM_NEW); } CXX_OPERATOR_ATTRIBUTE void operator delete[](void *ptr, std::nothrow_t const&) { OPERATOR_DELETE_BODY(FROM_NEW_BR); } CXX_OPERATOR_ATTRIBUTE void operator delete(void *ptr, size_t size) NOEXCEPT { GET_STACK_TRACE_FREE; asan_sized_free(ptr, size, &stack, FROM_NEW); } CXX_OPERATOR_ATTRIBUTE void operator delete[](void *ptr, size_t size) NOEXCEPT { + GET_STACK_TRACE_FREE; + asan_sized_free(ptr, size, &stack, FROM_NEW_BR); +} +CXX_OPERATOR_ATTRIBUTE +void operator delete(void *ptr, std::align_val_t) NOEXCEPT { + OPERATOR_DELETE_BODY(FROM_NEW); +} +CXX_OPERATOR_ATTRIBUTE +void operator delete[](void *ptr, std::align_val_t) NOEXCEPT { + OPERATOR_DELETE_BODY(FROM_NEW_BR); +} +CXX_OPERATOR_ATTRIBUTE +void operator delete(void *ptr, std::align_val_t, std::nothrow_t const&) { + OPERATOR_DELETE_BODY(FROM_NEW); +} +CXX_OPERATOR_ATTRIBUTE +void operator delete[](void *ptr, std::align_val_t, std::nothrow_t const&) { + OPERATOR_DELETE_BODY(FROM_NEW_BR); +} +CXX_OPERATOR_ATTRIBUTE +void operator delete(void *ptr, size_t size, std::align_val_t) NOEXCEPT { + GET_STACK_TRACE_FREE; + asan_sized_free(ptr, size, &stack, FROM_NEW); +} +CXX_OPERATOR_ATTRIBUTE +void operator delete[](void *ptr, size_t size, std::align_val_t) NOEXCEPT { GET_STACK_TRACE_FREE; asan_sized_free(ptr, size, &stack, FROM_NEW_BR); } #else // SANITIZER_MAC INTERCEPTOR(void, _ZdlPv, void *ptr) { OPERATOR_DELETE_BODY(FROM_NEW); } INTERCEPTOR(void, _ZdaPv, void *ptr) { OPERATOR_DELETE_BODY(FROM_NEW_BR); } INTERCEPTOR(void, _ZdlPvRKSt9nothrow_t, void *ptr, std::nothrow_t const&) { OPERATOR_DELETE_BODY(FROM_NEW); } INTERCEPTOR(void, _ZdaPvRKSt9nothrow_t, void *ptr, std::nothrow_t const&) { OPERATOR_DELETE_BODY(FROM_NEW_BR); } #endif Index: projects/clang400-import/contrib/compiler-rt/lib/asan/asan_poisoning.cc =================================================================== --- projects/clang400-import/contrib/compiler-rt/lib/asan/asan_poisoning.cc (revision 311696) +++ projects/clang400-import/contrib/compiler-rt/lib/asan/asan_poisoning.cc (revision 311697) @@ -1,434 +1,455 @@ //===-- asan_poisoning.cc -------------------------------------------------===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // This file is a part of AddressSanitizer, an address sanity checker. // // Shadow memory poisoning by ASan RTL and by user application. //===----------------------------------------------------------------------===// #include "asan_poisoning.h" #include "asan_report.h" #include "asan_stack.h" #include "sanitizer_common/sanitizer_atomic.h" #include "sanitizer_common/sanitizer_libc.h" #include "sanitizer_common/sanitizer_flags.h" namespace __asan { static atomic_uint8_t can_poison_memory; void SetCanPoisonMemory(bool value) { atomic_store(&can_poison_memory, value, memory_order_release); } bool CanPoisonMemory() { return atomic_load(&can_poison_memory, memory_order_acquire); } void PoisonShadow(uptr addr, uptr size, u8 value) { if (!CanPoisonMemory()) return; CHECK(AddrIsAlignedByGranularity(addr)); CHECK(AddrIsInMem(addr)); CHECK(AddrIsAlignedByGranularity(addr + size)); CHECK(AddrIsInMem(addr + size - SHADOW_GRANULARITY)); CHECK(REAL(memset)); FastPoisonShadow(addr, size, value); } void PoisonShadowPartialRightRedzone(uptr addr, uptr size, uptr redzone_size, u8 value) { if (!CanPoisonMemory()) return; CHECK(AddrIsAlignedByGranularity(addr)); CHECK(AddrIsInMem(addr)); FastPoisonShadowPartialRightRedzone(addr, size, redzone_size, value); } struct ShadowSegmentEndpoint { u8 *chunk; s8 offset; // in [0, SHADOW_GRANULARITY) s8 value; // = *chunk; explicit ShadowSegmentEndpoint(uptr address) { chunk = (u8*)MemToShadow(address); offset = address & (SHADOW_GRANULARITY - 1); value = *chunk; } }; void FlushUnneededASanShadowMemory(uptr p, uptr size) { - // Since asan's mapping is compacting, the shadow chunk may be - // not page-aligned, so we only flush the page-aligned portion. - uptr page_size = GetPageSizeCached(); - uptr shadow_beg = RoundUpTo(MemToShadow(p), page_size); - uptr shadow_end = RoundDownTo(MemToShadow(p + size), page_size); - FlushUnneededShadowMemory(shadow_beg, shadow_end - shadow_beg); + // Since asan's mapping is compacting, the shadow chunk may be + // not page-aligned, so we only flush the page-aligned portion. + ReleaseMemoryPagesToOS(MemToShadow(p), MemToShadow(p + size)); } void AsanPoisonOrUnpoisonIntraObjectRedzone(uptr ptr, uptr size, bool poison) { uptr end = ptr + size; if (Verbosity()) { Printf("__asan_%spoison_intra_object_redzone [%p,%p) %zd\n", poison ? "" : "un", ptr, end, size); if (Verbosity() >= 2) PRINT_CURRENT_STACK(); } CHECK(size); CHECK_LE(size, 4096); CHECK(IsAligned(end, SHADOW_GRANULARITY)); if (!IsAligned(ptr, SHADOW_GRANULARITY)) { *(u8 *)MemToShadow(ptr) = poison ? static_cast(ptr % SHADOW_GRANULARITY) : 0; ptr |= SHADOW_GRANULARITY - 1; ptr++; } for (; ptr < end; ptr += SHADOW_GRANULARITY) *(u8*)MemToShadow(ptr) = poison ? kAsanIntraObjectRedzone : 0; } } // namespace __asan // ---------------------- Interface ---------------- {{{1 using namespace __asan; // NOLINT // Current implementation of __asan_(un)poison_memory_region doesn't check // that user program (un)poisons the memory it owns. It poisons memory // conservatively, and unpoisons progressively to make sure asan shadow // mapping invariant is preserved (see detailed mapping description here: // https://github.com/google/sanitizers/wiki/AddressSanitizerAlgorithm). // // * if user asks to poison region [left, right), the program poisons // at least [left, AlignDown(right)). // * if user asks to unpoison region [left, right), the program unpoisons // at most [AlignDown(left), right). void __asan_poison_memory_region(void const volatile *addr, uptr size) { if (!flags()->allow_user_poisoning || size == 0) return; uptr beg_addr = (uptr)addr; uptr end_addr = beg_addr + size; VPrintf(3, "Trying to poison memory region [%p, %p)\n", (void *)beg_addr, (void *)end_addr); ShadowSegmentEndpoint beg(beg_addr); ShadowSegmentEndpoint end(end_addr); if (beg.chunk == end.chunk) { - CHECK(beg.offset < end.offset); + CHECK_LT(beg.offset, end.offset); s8 value = beg.value; - CHECK(value == end.value); + CHECK_EQ(value, end.value); // We can only poison memory if the byte in end.offset is unaddressable. // No need to re-poison memory if it is poisoned already. if (value > 0 && value <= end.offset) { if (beg.offset > 0) { *beg.chunk = Min(value, beg.offset); } else { *beg.chunk = kAsanUserPoisonedMemoryMagic; } } return; } - CHECK(beg.chunk < end.chunk); + CHECK_LT(beg.chunk, end.chunk); if (beg.offset > 0) { // Mark bytes from beg.offset as unaddressable. if (beg.value == 0) { *beg.chunk = beg.offset; } else { *beg.chunk = Min(beg.value, beg.offset); } beg.chunk++; } REAL(memset)(beg.chunk, kAsanUserPoisonedMemoryMagic, end.chunk - beg.chunk); // Poison if byte in end.offset is unaddressable. if (end.value > 0 && end.value <= end.offset) { *end.chunk = kAsanUserPoisonedMemoryMagic; } } void __asan_unpoison_memory_region(void const volatile *addr, uptr size) { if (!flags()->allow_user_poisoning || size == 0) return; uptr beg_addr = (uptr)addr; uptr end_addr = beg_addr + size; VPrintf(3, "Trying to unpoison memory region [%p, %p)\n", (void *)beg_addr, (void *)end_addr); ShadowSegmentEndpoint beg(beg_addr); ShadowSegmentEndpoint end(end_addr); if (beg.chunk == end.chunk) { - CHECK(beg.offset < end.offset); + CHECK_LT(beg.offset, end.offset); s8 value = beg.value; - CHECK(value == end.value); + CHECK_EQ(value, end.value); // We unpoison memory bytes up to enbytes up to end.offset if it is not // unpoisoned already. if (value != 0) { *beg.chunk = Max(value, end.offset); } return; } - CHECK(beg.chunk < end.chunk); + CHECK_LT(beg.chunk, end.chunk); if (beg.offset > 0) { *beg.chunk = 0; beg.chunk++; } REAL(memset)(beg.chunk, 0, end.chunk - beg.chunk); if (end.offset > 0 && end.value != 0) { *end.chunk = Max(end.value, end.offset); } } int __asan_address_is_poisoned(void const volatile *addr) { return __asan::AddressIsPoisoned((uptr)addr); } uptr __asan_region_is_poisoned(uptr beg, uptr size) { if (!size) return 0; uptr end = beg + size; if (!AddrIsInMem(beg)) return beg; if (!AddrIsInMem(end)) return end; CHECK_LT(beg, end); uptr aligned_b = RoundUpTo(beg, SHADOW_GRANULARITY); uptr aligned_e = RoundDownTo(end, SHADOW_GRANULARITY); uptr shadow_beg = MemToShadow(aligned_b); uptr shadow_end = MemToShadow(aligned_e); // First check the first and the last application bytes, // then check the SHADOW_GRANULARITY-aligned region by calling // mem_is_zero on the corresponding shadow. if (!__asan::AddressIsPoisoned(beg) && !__asan::AddressIsPoisoned(end - 1) && (shadow_end <= shadow_beg || __sanitizer::mem_is_zero((const char *)shadow_beg, shadow_end - shadow_beg))) return 0; // The fast check failed, so we have a poisoned byte somewhere. // Find it slowly. for (; beg < end; beg++) if (__asan::AddressIsPoisoned(beg)) return beg; UNREACHABLE("mem_is_zero returned false, but poisoned byte was not found"); return 0; } #define CHECK_SMALL_REGION(p, size, isWrite) \ do { \ uptr __p = reinterpret_cast(p); \ uptr __size = size; \ if (UNLIKELY(__asan::AddressIsPoisoned(__p) || \ __asan::AddressIsPoisoned(__p + __size - 1))) { \ GET_CURRENT_PC_BP_SP; \ uptr __bad = __asan_region_is_poisoned(__p, __size); \ __asan_report_error(pc, bp, sp, __bad, isWrite, __size, 0);\ } \ } while (false); \ extern "C" SANITIZER_INTERFACE_ATTRIBUTE u16 __sanitizer_unaligned_load16(const uu16 *p) { CHECK_SMALL_REGION(p, sizeof(*p), false); return *p; } extern "C" SANITIZER_INTERFACE_ATTRIBUTE u32 __sanitizer_unaligned_load32(const uu32 *p) { CHECK_SMALL_REGION(p, sizeof(*p), false); return *p; } extern "C" SANITIZER_INTERFACE_ATTRIBUTE u64 __sanitizer_unaligned_load64(const uu64 *p) { CHECK_SMALL_REGION(p, sizeof(*p), false); return *p; } extern "C" SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_unaligned_store16(uu16 *p, u16 x) { CHECK_SMALL_REGION(p, sizeof(*p), true); *p = x; } extern "C" SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_unaligned_store32(uu32 *p, u32 x) { CHECK_SMALL_REGION(p, sizeof(*p), true); *p = x; } extern "C" SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_unaligned_store64(uu64 *p, u64 x) { CHECK_SMALL_REGION(p, sizeof(*p), true); *p = x; } extern "C" SANITIZER_INTERFACE_ATTRIBUTE void __asan_poison_cxx_array_cookie(uptr p) { if (SANITIZER_WORDSIZE != 64) return; if (!flags()->poison_array_cookie) return; uptr s = MEM_TO_SHADOW(p); *reinterpret_cast(s) = kAsanArrayCookieMagic; } extern "C" SANITIZER_INTERFACE_ATTRIBUTE uptr __asan_load_cxx_array_cookie(uptr *p) { if (SANITIZER_WORDSIZE != 64) return *p; if (!flags()->poison_array_cookie) return *p; uptr s = MEM_TO_SHADOW(reinterpret_cast(p)); u8 sval = *reinterpret_cast(s); if (sval == kAsanArrayCookieMagic) return *p; // If sval is not kAsanArrayCookieMagic it can only be freed memory, // which means that we are going to get double-free. So, return 0 to avoid // infinite loop of destructors. We don't want to report a double-free here // though, so print a warning just in case. // CHECK_EQ(sval, kAsanHeapFreeMagic); if (sval == kAsanHeapFreeMagic) { Report("AddressSanitizer: loaded array cookie from free-d memory; " "expect a double-free report\n"); return 0; } // The cookie may remain unpoisoned if e.g. it comes from a custom // operator new defined inside a class. return *p; } // This is a simplified version of __asan_(un)poison_memory_region, which // assumes that left border of region to be poisoned is properly aligned. static void PoisonAlignedStackMemory(uptr addr, uptr size, bool do_poison) { if (size == 0) return; uptr aligned_size = size & ~(SHADOW_GRANULARITY - 1); PoisonShadow(addr, aligned_size, do_poison ? kAsanStackUseAfterScopeMagic : 0); if (size == aligned_size) return; s8 end_offset = (s8)(size - aligned_size); s8* shadow_end = (s8*)MemToShadow(addr + aligned_size); s8 end_value = *shadow_end; if (do_poison) { // If possible, mark all the bytes mapping to last shadow byte as // unaddressable. if (end_value > 0 && end_value <= end_offset) *shadow_end = (s8)kAsanStackUseAfterScopeMagic; } else { // If necessary, mark few first bytes mapping to last shadow byte // as addressable if (end_value != 0) *shadow_end = Max(end_value, end_offset); } } +void __asan_set_shadow_00(uptr addr, uptr size) { + REAL(memset)((void *)addr, 0, size); +} + +void __asan_set_shadow_f1(uptr addr, uptr size) { + REAL(memset)((void *)addr, 0xf1, size); +} + +void __asan_set_shadow_f2(uptr addr, uptr size) { + REAL(memset)((void *)addr, 0xf2, size); +} + +void __asan_set_shadow_f3(uptr addr, uptr size) { + REAL(memset)((void *)addr, 0xf3, size); +} + +void __asan_set_shadow_f5(uptr addr, uptr size) { + REAL(memset)((void *)addr, 0xf5, size); +} + +void __asan_set_shadow_f8(uptr addr, uptr size) { + REAL(memset)((void *)addr, 0xf8, size); +} + void __asan_poison_stack_memory(uptr addr, uptr size) { VReport(1, "poisoning: %p %zx\n", (void *)addr, size); PoisonAlignedStackMemory(addr, size, true); } void __asan_unpoison_stack_memory(uptr addr, uptr size) { VReport(1, "unpoisoning: %p %zx\n", (void *)addr, size); PoisonAlignedStackMemory(addr, size, false); } void __sanitizer_annotate_contiguous_container(const void *beg_p, const void *end_p, const void *old_mid_p, const void *new_mid_p) { if (!flags()->detect_container_overflow) return; VPrintf(2, "contiguous_container: %p %p %p %p\n", beg_p, end_p, old_mid_p, new_mid_p); uptr beg = reinterpret_cast(beg_p); uptr end = reinterpret_cast(end_p); uptr old_mid = reinterpret_cast(old_mid_p); uptr new_mid = reinterpret_cast(new_mid_p); uptr granularity = SHADOW_GRANULARITY; if (!(beg <= old_mid && beg <= new_mid && old_mid <= end && new_mid <= end && IsAligned(beg, granularity))) { GET_STACK_TRACE_FATAL_HERE; ReportBadParamsToAnnotateContiguousContainer(beg, end, old_mid, new_mid, &stack); } CHECK_LE(end - beg, FIRST_32_SECOND_64(1UL << 30, 1ULL << 34)); // Sanity check. uptr a = RoundDownTo(Min(old_mid, new_mid), granularity); uptr c = RoundUpTo(Max(old_mid, new_mid), granularity); uptr d1 = RoundDownTo(old_mid, granularity); // uptr d2 = RoundUpTo(old_mid, granularity); // Currently we should be in this state: // [a, d1) is good, [d2, c) is bad, [d1, d2) is partially good. // Make a quick sanity check that we are indeed in this state. // // FIXME: Two of these three checks are disabled until we fix // https://github.com/google/sanitizers/issues/258. // if (d1 != d2) // CHECK_EQ(*(u8*)MemToShadow(d1), old_mid - d1); if (a + granularity <= d1) CHECK_EQ(*(u8*)MemToShadow(a), 0); // if (d2 + granularity <= c && c <= end) // CHECK_EQ(*(u8 *)MemToShadow(c - granularity), // kAsanContiguousContainerOOBMagic); uptr b1 = RoundDownTo(new_mid, granularity); uptr b2 = RoundUpTo(new_mid, granularity); // New state: // [a, b1) is good, [b2, c) is bad, [b1, b2) is partially good. PoisonShadow(a, b1 - a, 0); PoisonShadow(b2, c - b2, kAsanContiguousContainerOOBMagic); if (b1 != b2) { CHECK_EQ(b2 - b1, granularity); *(u8*)MemToShadow(b1) = static_cast(new_mid - b1); } } const void *__sanitizer_contiguous_container_find_bad_address( const void *beg_p, const void *mid_p, const void *end_p) { if (!flags()->detect_container_overflow) return nullptr; uptr beg = reinterpret_cast(beg_p); uptr end = reinterpret_cast(end_p); uptr mid = reinterpret_cast(mid_p); CHECK_LE(beg, mid); CHECK_LE(mid, end); // Check some bytes starting from beg, some bytes around mid, and some bytes // ending with end. uptr kMaxRangeToCheck = 32; uptr r1_beg = beg; - uptr r1_end = Min(end + kMaxRangeToCheck, mid); + uptr r1_end = Min(beg + kMaxRangeToCheck, mid); uptr r2_beg = Max(beg, mid - kMaxRangeToCheck); uptr r2_end = Min(end, mid + kMaxRangeToCheck); uptr r3_beg = Max(end - kMaxRangeToCheck, mid); uptr r3_end = end; for (uptr i = r1_beg; i < r1_end; i++) if (AddressIsPoisoned(i)) return reinterpret_cast(i); for (uptr i = r2_beg; i < mid; i++) if (AddressIsPoisoned(i)) return reinterpret_cast(i); for (uptr i = mid; i < r2_end; i++) if (!AddressIsPoisoned(i)) return reinterpret_cast(i); for (uptr i = r3_beg; i < r3_end; i++) if (!AddressIsPoisoned(i)) return reinterpret_cast(i); return nullptr; } int __sanitizer_verify_contiguous_container(const void *beg_p, const void *mid_p, const void *end_p) { return __sanitizer_contiguous_container_find_bad_address(beg_p, mid_p, end_p) == nullptr; } extern "C" SANITIZER_INTERFACE_ATTRIBUTE void __asan_poison_intra_object_redzone(uptr ptr, uptr size) { AsanPoisonOrUnpoisonIntraObjectRedzone(ptr, size, true); } extern "C" SANITIZER_INTERFACE_ATTRIBUTE void __asan_unpoison_intra_object_redzone(uptr ptr, uptr size) { AsanPoisonOrUnpoisonIntraObjectRedzone(ptr, size, false); } // --- Implementation of LSan-specific functions --- {{{1 namespace __lsan { bool WordIsPoisoned(uptr addr) { return (__asan_region_is_poisoned(addr, sizeof(uptr)) != 0); } } Index: projects/clang400-import/contrib/compiler-rt/lib/asan/asan_poisoning.h =================================================================== --- projects/clang400-import/contrib/compiler-rt/lib/asan/asan_poisoning.h (revision 311696) +++ projects/clang400-import/contrib/compiler-rt/lib/asan/asan_poisoning.h (revision 311697) @@ -1,93 +1,93 @@ //===-- asan_poisoning.h ----------------------------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // This file is a part of AddressSanitizer, an address sanity checker. // // Shadow memory poisoning by ASan RTL and by user application. //===----------------------------------------------------------------------===// #include "asan_interceptors.h" #include "asan_internal.h" #include "asan_mapping.h" #include "sanitizer_common/sanitizer_flags.h" namespace __asan { // Enable/disable memory poisoning. void SetCanPoisonMemory(bool value); bool CanPoisonMemory(); // Poisons the shadow memory for "size" bytes starting from "addr". void PoisonShadow(uptr addr, uptr size, u8 value); // Poisons the shadow memory for "redzone_size" bytes starting from // "addr + size". void PoisonShadowPartialRightRedzone(uptr addr, uptr size, uptr redzone_size, u8 value); // Fast versions of PoisonShadow and PoisonShadowPartialRightRedzone that // assume that memory addresses are properly aligned. Use in // performance-critical code with care. ALWAYS_INLINE void FastPoisonShadow(uptr aligned_beg, uptr aligned_size, u8 value) { DCHECK(CanPoisonMemory()); uptr shadow_beg = MEM_TO_SHADOW(aligned_beg); uptr shadow_end = MEM_TO_SHADOW( aligned_beg + aligned_size - SHADOW_GRANULARITY) + 1; // FIXME: Page states are different on Windows, so using the same interface // for mapping shadow and zeroing out pages doesn't "just work", so we should // probably provide higher-level interface for these operations. // For now, just memset on Windows. if (value || SANITIZER_WINDOWS == 1 || shadow_end - shadow_beg < common_flags()->clear_shadow_mmap_threshold) { REAL(memset)((void*)shadow_beg, value, shadow_end - shadow_beg); } else { uptr page_size = GetPageSizeCached(); uptr page_beg = RoundUpTo(shadow_beg, page_size); uptr page_end = RoundDownTo(shadow_end, page_size); if (page_beg >= page_end) { REAL(memset)((void *)shadow_beg, 0, shadow_end - shadow_beg); } else { if (page_beg != shadow_beg) { REAL(memset)((void *)shadow_beg, 0, page_beg - shadow_beg); } if (page_end != shadow_end) { REAL(memset)((void *)page_end, 0, shadow_end - page_end); } ReserveShadowMemoryRange(page_beg, page_end - 1, nullptr); } } } ALWAYS_INLINE void FastPoisonShadowPartialRightRedzone( uptr aligned_addr, uptr size, uptr redzone_size, u8 value) { DCHECK(CanPoisonMemory()); bool poison_partial = flags()->poison_partial; u8 *shadow = (u8*)MEM_TO_SHADOW(aligned_addr); for (uptr i = 0; i < redzone_size; i += SHADOW_GRANULARITY, shadow++) { if (i + SHADOW_GRANULARITY <= size) { *shadow = 0; // fully addressable } else if (i >= size) { *shadow = (SHADOW_GRANULARITY == 128) ? 0xff : value; // unaddressable } else { // first size-i bytes are addressable *shadow = poison_partial ? static_cast(size - i) : 0; } } } -// Calls __sanitizer::FlushUnneededShadowMemory() on -// [MemToShadow(p), MemToShadow(p+size)] with proper rounding. +// Calls __sanitizer::ReleaseMemoryPagesToOS() on +// [MemToShadow(p), MemToShadow(p+size)]. void FlushUnneededASanShadowMemory(uptr p, uptr size); } // namespace __asan Index: projects/clang400-import/contrib/compiler-rt/lib/asan/asan_posix.cc =================================================================== --- projects/clang400-import/contrib/compiler-rt/lib/asan/asan_posix.cc (revision 311696) +++ projects/clang400-import/contrib/compiler-rt/lib/asan/asan_posix.cc (revision 311697) @@ -1,126 +1,135 @@ //===-- asan_posix.cc -----------------------------------------------------===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // This file is a part of AddressSanitizer, an address sanity checker. // // Posix-specific details. //===----------------------------------------------------------------------===// #include "sanitizer_common/sanitizer_platform.h" #if SANITIZER_POSIX #include "asan_internal.h" #include "asan_interceptors.h" #include "asan_mapping.h" #include "asan_report.h" #include "asan_stack.h" #include "sanitizer_common/sanitizer_libc.h" #include "sanitizer_common/sanitizer_posix.h" #include "sanitizer_common/sanitizer_procmaps.h" #include #include #include #include #include #include namespace __asan { +const char *DescribeSignalOrException(int signo) { + switch (signo) { + case SIGFPE: + return "FPE"; + case SIGILL: + return "ILL"; + case SIGABRT: + return "ABRT"; + default: + return "SEGV"; + } +} + void AsanOnDeadlySignal(int signo, void *siginfo, void *context) { ScopedDeadlySignal signal_scope(GetCurrentThread()); int code = (int)((siginfo_t*)siginfo)->si_code; // Write the first message using fd=2, just in case. // It may actually fail to write in case stderr is closed. internal_write(2, "ASAN:DEADLYSIGNAL\n", 18); SignalContext sig = SignalContext::Create(siginfo, context); // 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 = sig.addr >= (sig.sp & ~0xFFF) && sig.addr < sig.sp + 0xFFFF; #else bool IsStackAccess = sig.addr + 512 > sig.sp && sig.addr < sig.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, becase the fault address will be more than just "slightly" // below sp. if (!IsStackAccess && IsAccessibleMemoryRange(sig.pc, 4)) { u32 inst = *(unsigned *)sig.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. if (IsStackAccess && (code == si_SEGV_MAPERR || code == si_SEGV_ACCERR)) ReportStackOverflow(sig); - else if (signo == SIGFPE) - ReportDeadlySignal("FPE", sig); - else if (signo == SIGILL) - ReportDeadlySignal("ILL", sig); else - ReportDeadlySignal("SEGV", sig); + ReportDeadlySignal(signo, sig); } // ---------------------- TSD ---------------- {{{1 static pthread_key_t tsd_key; static bool tsd_key_inited = false; void AsanTSDInit(void (*destructor)(void *tsd)) { CHECK(!tsd_key_inited); tsd_key_inited = true; CHECK_EQ(0, pthread_key_create(&tsd_key, destructor)); } void *AsanTSDGet() { CHECK(tsd_key_inited); return pthread_getspecific(tsd_key); } void AsanTSDSet(void *tsd) { CHECK(tsd_key_inited); pthread_setspecific(tsd_key, tsd); } void PlatformTSDDtor(void *tsd) { AsanThreadContext *context = (AsanThreadContext*)tsd; if (context->destructor_iterations > 1) { context->destructor_iterations--; CHECK_EQ(0, pthread_setspecific(tsd_key, tsd)); return; } AsanThread::TSDDtor(tsd); } } // namespace __asan #endif // SANITIZER_POSIX Index: projects/clang400-import/contrib/compiler-rt/lib/asan/asan_report.cc =================================================================== --- projects/clang400-import/contrib/compiler-rt/lib/asan/asan_report.cc (revision 311696) +++ projects/clang400-import/contrib/compiler-rt/lib/asan/asan_report.cc (revision 311697) @@ -1,1273 +1,494 @@ //===-- asan_report.cc ----------------------------------------------------===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // This file is a part of AddressSanitizer, an address sanity checker. // // This file contains error reporting code. //===----------------------------------------------------------------------===// +#include "asan_errors.h" #include "asan_flags.h" +#include "asan_descriptions.h" #include "asan_internal.h" #include "asan_mapping.h" #include "asan_report.h" #include "asan_scariness_score.h" #include "asan_stack.h" #include "asan_thread.h" #include "sanitizer_common/sanitizer_common.h" #include "sanitizer_common/sanitizer_flags.h" #include "sanitizer_common/sanitizer_report_decorator.h" #include "sanitizer_common/sanitizer_stackdepot.h" #include "sanitizer_common/sanitizer_symbolizer.h" namespace __asan { // -------------------- User-specified callbacks ----------------- {{{1 static void (*error_report_callback)(const char*); static char *error_message_buffer = nullptr; static uptr error_message_buffer_pos = 0; static BlockingMutex error_message_buf_mutex(LINKER_INITIALIZED); static const unsigned kAsanBuggyPcPoolSize = 25; static __sanitizer::atomic_uintptr_t AsanBuggyPcPool[kAsanBuggyPcPoolSize]; -struct ReportData { - uptr pc; - uptr sp; - uptr bp; - uptr addr; - bool is_write; - uptr access_size; - const char *description; -}; - -static bool report_happened = false; -static ReportData report_data = {}; - void AppendToErrorMessageBuffer(const char *buffer) { BlockingMutexLock l(&error_message_buf_mutex); if (!error_message_buffer) { error_message_buffer = (char*)MmapOrDieQuietly(kErrorMessageBufferSize, __func__); error_message_buffer_pos = 0; } uptr length = internal_strlen(buffer); RAW_CHECK(kErrorMessageBufferSize >= error_message_buffer_pos); uptr remaining = kErrorMessageBufferSize - error_message_buffer_pos; internal_strncpy(error_message_buffer + error_message_buffer_pos, buffer, remaining); error_message_buffer[kErrorMessageBufferSize - 1] = '\0'; // FIXME: reallocate the buffer instead of truncating the message. error_message_buffer_pos += Min(remaining, length); } -// ---------------------- Decorator ------------------------------ {{{1 -class Decorator: public __sanitizer::SanitizerCommonDecorator { - public: - Decorator() : SanitizerCommonDecorator() { } - const char *Access() { return Blue(); } - const char *EndAccess() { return Default(); } - const char *Location() { return Green(); } - const char *EndLocation() { return Default(); } - const char *Allocation() { return Magenta(); } - const char *EndAllocation() { return Default(); } - - const char *ShadowByte(u8 byte) { - switch (byte) { - case kAsanHeapLeftRedzoneMagic: - case kAsanHeapRightRedzoneMagic: - case kAsanArrayCookieMagic: - return Red(); - case kAsanHeapFreeMagic: - return Magenta(); - case kAsanStackLeftRedzoneMagic: - case kAsanStackMidRedzoneMagic: - case kAsanStackRightRedzoneMagic: - case kAsanStackPartialRedzoneMagic: - return Red(); - case kAsanStackAfterReturnMagic: - return Magenta(); - case kAsanInitializationOrderMagic: - return Cyan(); - case kAsanUserPoisonedMemoryMagic: - case kAsanContiguousContainerOOBMagic: - case kAsanAllocaLeftMagic: - case kAsanAllocaRightMagic: - return Blue(); - case kAsanStackUseAfterScopeMagic: - return Magenta(); - case kAsanGlobalRedzoneMagic: - return Red(); - case kAsanInternalHeapMagic: - return Yellow(); - case kAsanIntraObjectRedzone: - return Yellow(); - default: - return Default(); - } - } - const char *EndShadowByte() { return Default(); } - const char *MemoryByte() { return Magenta(); } - const char *EndMemoryByte() { return Default(); } -}; - // ---------------------- Helper functions ----------------------- {{{1 -static void PrintMemoryByte(InternalScopedString *str, const char *before, - u8 byte, bool in_shadow, const char *after = "\n") { +void PrintMemoryByte(InternalScopedString *str, const char *before, u8 byte, + bool in_shadow, const char *after) { Decorator d; str->append("%s%s%x%x%s%s", before, in_shadow ? d.ShadowByte(byte) : d.MemoryByte(), byte >> 4, byte & 15, in_shadow ? d.EndShadowByte() : d.EndMemoryByte(), after); } -static void PrintShadowByte(InternalScopedString *str, const char *before, - u8 byte, const char *after = "\n") { - PrintMemoryByte(str, before, byte, /*in_shadow*/true, after); -} - -static void PrintShadowBytes(InternalScopedString *str, const char *before, - u8 *bytes, u8 *guilty, uptr n) { - Decorator d; - if (before) str->append("%s%p:", before, bytes); - for (uptr i = 0; i < n; i++) { - u8 *p = bytes + i; - const char *before = - p == guilty ? "[" : (p - 1 == guilty && i != 0) ? "" : " "; - const char *after = p == guilty ? "]" : ""; - PrintShadowByte(str, before, *p, after); - } - str->append("\n"); -} - -static void PrintLegend(InternalScopedString *str) { - str->append( - "Shadow byte legend (one shadow byte represents %d " - "application bytes):\n", - (int)SHADOW_GRANULARITY); - PrintShadowByte(str, " Addressable: ", 0); - str->append(" Partially addressable: "); - for (u8 i = 1; i < SHADOW_GRANULARITY; i++) PrintShadowByte(str, "", i, " "); - str->append("\n"); - PrintShadowByte(str, " Heap left redzone: ", - kAsanHeapLeftRedzoneMagic); - PrintShadowByte(str, " Heap right redzone: ", - kAsanHeapRightRedzoneMagic); - PrintShadowByte(str, " Freed heap region: ", kAsanHeapFreeMagic); - PrintShadowByte(str, " Stack left redzone: ", - kAsanStackLeftRedzoneMagic); - PrintShadowByte(str, " Stack mid redzone: ", - kAsanStackMidRedzoneMagic); - PrintShadowByte(str, " Stack right redzone: ", - kAsanStackRightRedzoneMagic); - PrintShadowByte(str, " Stack partial redzone: ", - kAsanStackPartialRedzoneMagic); - PrintShadowByte(str, " Stack after return: ", - kAsanStackAfterReturnMagic); - PrintShadowByte(str, " Stack use after scope: ", - kAsanStackUseAfterScopeMagic); - PrintShadowByte(str, " Global redzone: ", kAsanGlobalRedzoneMagic); - PrintShadowByte(str, " Global init order: ", - kAsanInitializationOrderMagic); - PrintShadowByte(str, " Poisoned by user: ", - kAsanUserPoisonedMemoryMagic); - PrintShadowByte(str, " Container overflow: ", - kAsanContiguousContainerOOBMagic); - PrintShadowByte(str, " Array cookie: ", - kAsanArrayCookieMagic); - PrintShadowByte(str, " Intra object redzone: ", - kAsanIntraObjectRedzone); - PrintShadowByte(str, " ASan internal: ", kAsanInternalHeapMagic); - PrintShadowByte(str, " Left alloca redzone: ", kAsanAllocaLeftMagic); - PrintShadowByte(str, " Right alloca redzone: ", kAsanAllocaRightMagic); -} - -void MaybeDumpInstructionBytes(uptr pc) { - if (!flags()->dump_instruction_bytes || (pc < GetPageSizeCached())) - return; - InternalScopedString str(1024); - str.append("First 16 instruction bytes at pc: "); - if (IsAccessibleMemoryRange(pc, 16)) { - for (int i = 0; i < 16; ++i) { - PrintMemoryByte(&str, "", ((u8 *)pc)[i], /*in_shadow*/false, " "); - } - str.append("\n"); - } else { - str.append("unaccessible\n"); - } - Report("%s", str.data()); -} - -static void PrintShadowMemoryForAddress(uptr addr) { - if (!AddrIsInMem(addr)) return; - uptr shadow_addr = MemToShadow(addr); - const uptr n_bytes_per_row = 16; - uptr aligned_shadow = shadow_addr & ~(n_bytes_per_row - 1); - InternalScopedString str(4096 * 8); - str.append("Shadow bytes around the buggy address:\n"); - for (int i = -5; i <= 5; i++) { - const char *prefix = (i == 0) ? "=>" : " "; - PrintShadowBytes(&str, prefix, (u8 *)(aligned_shadow + i * n_bytes_per_row), - (u8 *)shadow_addr, n_bytes_per_row); - } - if (flags()->print_legend) PrintLegend(&str); - Printf("%s", str.data()); -} - static void PrintZoneForPointer(uptr ptr, uptr zone_ptr, const char *zone_name) { if (zone_ptr) { if (zone_name) { Printf("malloc_zone_from_ptr(%p) = %p, which is %s\n", ptr, zone_ptr, zone_name); } else { Printf("malloc_zone_from_ptr(%p) = %p, which doesn't have a name\n", ptr, zone_ptr); } } else { Printf("malloc_zone_from_ptr(%p) = 0\n", ptr); } } -static void DescribeThread(AsanThread *t) { - if (t) - DescribeThread(t->context()); -} - // ---------------------- Address Descriptions ------------------- {{{1 -static bool IsASCII(unsigned char c) { - return /*0x00 <= c &&*/ c <= 0x7F; -} - -static const char *MaybeDemangleGlobalName(const char *name) { - // We can spoil names of globals with C linkage, so use an heuristic - // approach to check if the name should be demangled. - bool should_demangle = false; - if (name[0] == '_' && name[1] == 'Z') - should_demangle = true; - else if (SANITIZER_WINDOWS && name[0] == '\01' && name[1] == '?') - should_demangle = true; - - return should_demangle ? Symbolizer::GetOrInit()->Demangle(name) : name; -} - -// Check if the global is a zero-terminated ASCII string. If so, print it. -static void PrintGlobalNameIfASCII(InternalScopedString *str, - const __asan_global &g) { - for (uptr p = g.beg; p < g.beg + g.size - 1; p++) { - unsigned char c = *(unsigned char*)p; - if (c == '\0' || !IsASCII(c)) return; - } - if (*(char*)(g.beg + g.size - 1) != '\0') return; - str->append(" '%s' is ascii string '%s'\n", MaybeDemangleGlobalName(g.name), - (char *)g.beg); -} - -static const char *GlobalFilename(const __asan_global &g) { - const char *res = g.module_name; - // Prefer the filename from source location, if is available. - if (g.location) - res = g.location->filename; - CHECK(res); - return res; -} - -static void PrintGlobalLocation(InternalScopedString *str, - const __asan_global &g) { - str->append("%s", GlobalFilename(g)); - if (!g.location) - return; - if (g.location->line_no) - str->append(":%d", g.location->line_no); - if (g.location->column_no) - str->append(":%d", g.location->column_no); -} - -static void DescribeAddressRelativeToGlobal(uptr addr, uptr size, - const __asan_global &g) { - InternalScopedString str(4096); - Decorator d; - str.append("%s", d.Location()); - if (addr < g.beg) { - str.append("%p is located %zd bytes to the left", (void *)addr, - g.beg - addr); - } else if (addr + size > g.beg + g.size) { - if (addr < g.beg + g.size) - addr = g.beg + g.size; - str.append("%p is located %zd bytes to the right", (void *)addr, - addr - (g.beg + g.size)); - } else { - // Can it happen? - str.append("%p is located %zd bytes inside", (void *)addr, addr - g.beg); - } - str.append(" of global variable '%s' defined in '", - MaybeDemangleGlobalName(g.name)); - PrintGlobalLocation(&str, g); - str.append("' (0x%zx) of size %zu\n", g.beg, g.size); - str.append("%s", d.EndLocation()); - PrintGlobalNameIfASCII(&str, g); - Printf("%s", str.data()); -} - -static bool DescribeAddressIfGlobal(uptr addr, uptr size, - const char *bug_type) { - // Assume address is close to at most four globals. - const int kMaxGlobalsInReport = 4; - __asan_global globals[kMaxGlobalsInReport]; - u32 reg_sites[kMaxGlobalsInReport]; - int globals_num = - GetGlobalsForAddress(addr, globals, reg_sites, ARRAY_SIZE(globals)); - if (globals_num == 0) - return false; - for (int i = 0; i < globals_num; i++) { - DescribeAddressRelativeToGlobal(addr, size, globals[i]); - if (0 == internal_strcmp(bug_type, "initialization-order-fiasco") && - reg_sites[i]) { - Printf(" registered at:\n"); - StackDepotGet(reg_sites[i]).Print(); - } - } - return true; -} - -bool DescribeAddressIfShadow(uptr addr, AddressDescription *descr, bool print) { - if (AddrIsInMem(addr)) - return false; - const char *area_type = nullptr; - if (AddrIsInShadowGap(addr)) area_type = "shadow gap"; - else if (AddrIsInHighShadow(addr)) area_type = "high shadow"; - else if (AddrIsInLowShadow(addr)) area_type = "low shadow"; - if (area_type != nullptr) { - if (print) { - Printf("Address %p is located in the %s area.\n", addr, area_type); - } else { - CHECK(descr); - descr->region_kind = area_type; - } - return true; - } - CHECK(0 && "Address is not in memory and not in shadow?"); - return false; -} - -// Return " (thread_name) " or an empty string if the name is empty. -const char *ThreadNameWithParenthesis(AsanThreadContext *t, char buff[], - uptr buff_len) { - const char *name = t->name; - if (name[0] == '\0') return ""; - buff[0] = 0; - internal_strncat(buff, " (", 3); - internal_strncat(buff, name, buff_len - 4); - internal_strncat(buff, ")", 2); - return buff; -} - -const char *ThreadNameWithParenthesis(u32 tid, char buff[], - uptr buff_len) { - if (tid == kInvalidTid) return ""; - asanThreadRegistry().CheckLocked(); - AsanThreadContext *t = GetThreadContextByTidLocked(tid); - return ThreadNameWithParenthesis(t, buff, buff_len); -} - -static void PrintAccessAndVarIntersection(const StackVarDescr &var, uptr addr, - uptr access_size, uptr prev_var_end, - uptr next_var_beg) { - uptr var_end = var.beg + var.size; - uptr addr_end = addr + access_size; - const char *pos_descr = nullptr; - // If the variable [var.beg, var_end) is the nearest variable to the - // current memory access, indicate it in the log. - if (addr >= var.beg) { - if (addr_end <= var_end) - pos_descr = "is inside"; // May happen if this is a use-after-return. - else if (addr < var_end) - pos_descr = "partially overflows"; - else if (addr_end <= next_var_beg && - next_var_beg - addr_end >= addr - var_end) - pos_descr = "overflows"; - } else { - if (addr_end > var.beg) - pos_descr = "partially underflows"; - else if (addr >= prev_var_end && - addr - prev_var_end >= var.beg - addr_end) - pos_descr = "underflows"; - } - InternalScopedString str(1024); - str.append(" [%zd, %zd)", var.beg, var_end); - // Render variable name. - str.append(" '"); - for (uptr i = 0; i < var.name_len; ++i) { - str.append("%c", var.name_pos[i]); - } - str.append("'"); - if (pos_descr) { - Decorator d; - // FIXME: we may want to also print the size of the access here, - // but in case of accesses generated by memset it may be confusing. - str.append("%s <== Memory access at offset %zd %s this variable%s\n", - d.Location(), addr, pos_descr, d.EndLocation()); - } else { - str.append("\n"); - } - Printf("%s", str.data()); -} - bool ParseFrameDescription(const char *frame_descr, InternalMmapVector *vars) { CHECK(frame_descr); char *p; // This string is created by the compiler and has the following form: // "n alloc_1 alloc_2 ... alloc_n" // where alloc_i looks like "offset size len ObjectName". uptr n_objects = (uptr)internal_simple_strtoll(frame_descr, &p, 10); if (n_objects == 0) return false; for (uptr i = 0; i < n_objects; i++) { uptr beg = (uptr)internal_simple_strtoll(p, &p, 10); uptr size = (uptr)internal_simple_strtoll(p, &p, 10); uptr len = (uptr)internal_simple_strtoll(p, &p, 10); if (beg == 0 || size == 0 || *p != ' ') { return false; } p++; StackVarDescr var = {beg, size, p, len}; vars->push_back(var); p += len; } return true; } -bool DescribeAddressIfStack(uptr addr, uptr access_size) { - AsanThread *t = FindThreadByStackAddress(addr); - if (!t) return false; - - Decorator d; - char tname[128]; - Printf("%s", d.Location()); - Printf("Address %p is located in stack of thread T%d%s", addr, t->tid(), - ThreadNameWithParenthesis(t->tid(), tname, sizeof(tname))); - - // Try to fetch precise stack frame for this access. - AsanThread::StackFrameAccess access; - if (!t->GetStackFrameAccessByAddr(addr, &access)) { - Printf("%s\n", d.EndLocation()); - return true; - } - Printf(" at offset %zu in frame%s\n", access.offset, d.EndLocation()); - - // Now we print the frame where the alloca has happened. - // We print this frame as a stack trace with one element. - // The symbolizer may print more than one frame if inlining was involved. - // The frame numbers may be different than those in the stack trace printed - // previously. That's unfortunate, but I have no better solution, - // especially given that the alloca may be from entirely different place - // (e.g. use-after-scope, or different thread's stack). -#if SANITIZER_PPC64V1 - // On PowerPC64 ELFv1, the address of a function actually points to a - // three-doubleword data structure with the first field containing - // the address of the function's code. - access.frame_pc = *reinterpret_cast(access.frame_pc); -#endif - access.frame_pc += 16; - Printf("%s", d.EndLocation()); - StackTrace alloca_stack(&access.frame_pc, 1); - alloca_stack.Print(); - - InternalMmapVector vars(16); - if (!ParseFrameDescription(access.frame_descr, &vars)) { - Printf("AddressSanitizer can't parse the stack frame " - "descriptor: |%s|\n", access.frame_descr); - // 'addr' is a stack address, so return true even if we can't parse frame - return true; - } - uptr n_objects = vars.size(); - // Report the number of stack objects. - Printf(" This frame has %zu object(s):\n", n_objects); - - // Report all objects in this frame. - for (uptr i = 0; i < n_objects; i++) { - uptr prev_var_end = i ? vars[i - 1].beg + vars[i - 1].size : 0; - uptr next_var_beg = i + 1 < n_objects ? vars[i + 1].beg : ~(0UL); - PrintAccessAndVarIntersection(vars[i], access.offset, access_size, - prev_var_end, next_var_beg); - } - Printf("HINT: this may be a false positive if your program uses " - "some custom stack unwind mechanism or swapcontext\n"); - if (SANITIZER_WINDOWS) - Printf(" (longjmp, SEH and C++ exceptions *are* supported)\n"); - else - Printf(" (longjmp and C++ exceptions *are* supported)\n"); - - DescribeThread(t); - return true; -} - -static void DescribeAccessToHeapChunk(AsanChunkView chunk, uptr addr, - uptr access_size) { - sptr offset; - Decorator d; - InternalScopedString str(4096); - str.append("%s", d.Location()); - if (chunk.AddrIsAtLeft(addr, access_size, &offset)) { - str.append("%p is located %zd bytes to the left of", (void *)addr, offset); - } else if (chunk.AddrIsAtRight(addr, access_size, &offset)) { - if (offset < 0) { - addr -= offset; - offset = 0; - } - str.append("%p is located %zd bytes to the right of", (void *)addr, offset); - } else if (chunk.AddrIsInside(addr, access_size, &offset)) { - str.append("%p is located %zd bytes inside of", (void*)addr, offset); - } else { - str.append("%p is located somewhere around (this is AddressSanitizer bug!)", - (void *)addr); - } - str.append(" %zu-byte region [%p,%p)\n", chunk.UsedSize(), - (void *)(chunk.Beg()), (void *)(chunk.End())); - str.append("%s", d.EndLocation()); - Printf("%s", str.data()); -} - -void DescribeHeapAddress(uptr addr, uptr access_size) { - AsanChunkView chunk = FindHeapChunkByAddress(addr); - if (!chunk.IsValid()) { - Printf("AddressSanitizer can not describe address in more detail " - "(wild memory access suspected).\n"); - return; - } - DescribeAccessToHeapChunk(chunk, addr, access_size); - CHECK(chunk.AllocTid() != kInvalidTid); - asanThreadRegistry().CheckLocked(); - AsanThreadContext *alloc_thread = - GetThreadContextByTidLocked(chunk.AllocTid()); - StackTrace alloc_stack = chunk.GetAllocStack(); - char tname[128]; - Decorator d; - AsanThreadContext *free_thread = nullptr; - if (chunk.FreeTid() != kInvalidTid) { - free_thread = GetThreadContextByTidLocked(chunk.FreeTid()); - Printf("%sfreed by thread T%d%s here:%s\n", d.Allocation(), - free_thread->tid, - ThreadNameWithParenthesis(free_thread, tname, sizeof(tname)), - d.EndAllocation()); - StackTrace free_stack = chunk.GetFreeStack(); - free_stack.Print(); - Printf("%spreviously allocated by thread T%d%s here:%s\n", - d.Allocation(), alloc_thread->tid, - ThreadNameWithParenthesis(alloc_thread, tname, sizeof(tname)), - d.EndAllocation()); - } else { - Printf("%sallocated by thread T%d%s here:%s\n", d.Allocation(), - alloc_thread->tid, - ThreadNameWithParenthesis(alloc_thread, tname, sizeof(tname)), - d.EndAllocation()); - } - alloc_stack.Print(); - DescribeThread(GetCurrentThread()); - if (free_thread) - DescribeThread(free_thread); - DescribeThread(alloc_thread); -} - -static void DescribeAddress(uptr addr, uptr access_size, const char *bug_type) { - // Check if this is shadow or shadow gap. - if (DescribeAddressIfShadow(addr)) - return; - CHECK(AddrIsInMem(addr)); - if (DescribeAddressIfGlobal(addr, access_size, bug_type)) - return; - if (DescribeAddressIfStack(addr, access_size)) - return; - // Assume it is a heap address. - DescribeHeapAddress(addr, access_size); -} - -// ------------------- Thread description -------------------- {{{1 - -void DescribeThread(AsanThreadContext *context) { - CHECK(context); - asanThreadRegistry().CheckLocked(); - // No need to announce the main thread. - if (context->tid == 0 || context->announced) { - return; - } - context->announced = true; - char tname[128]; - InternalScopedString str(1024); - str.append("Thread T%d%s", context->tid, - ThreadNameWithParenthesis(context->tid, tname, sizeof(tname))); - if (context->parent_tid == kInvalidTid) { - str.append(" created by unknown thread\n"); - Printf("%s", str.data()); - return; - } - str.append( - " created by T%d%s here:\n", context->parent_tid, - ThreadNameWithParenthesis(context->parent_tid, tname, sizeof(tname))); - Printf("%s", str.data()); - StackDepotGet(context->stack_id).Print(); - // Recursively described parent thread if needed. - if (flags()->print_full_thread_history) { - AsanThreadContext *parent_context = - GetThreadContextByTidLocked(context->parent_tid); - DescribeThread(parent_context); - } -} - // -------------------- Different kinds of reports ----------------- {{{1 // Use ScopedInErrorReport to run common actions just before and // immediately after printing error report. class ScopedInErrorReport { public: - explicit ScopedInErrorReport(ReportData *report = nullptr, - bool fatal = false) { + explicit ScopedInErrorReport(bool fatal = false) { halt_on_error_ = fatal || flags()->halt_on_error; if (lock_.TryLock()) { - StartReporting(report); + StartReporting(); return; } // ASan found two bugs in different threads simultaneously. u32 current_tid = GetCurrentTidOrInvalid(); if (reporting_thread_tid_ == current_tid || reporting_thread_tid_ == kInvalidTid) { // 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. const char msg[] = "AddressSanitizer: nested bug in the same thread, " "aborting.\n"; WriteToFile(kStderrFd, msg, sizeof(msg)); internal__exit(common_flags()->exitcode); } if (halt_on_error_) { // Do not print more than one report, otherwise they will mix up. // Error reporting functions shouldn't return at this situation, as // they are effectively no-returns. Report("AddressSanitizer: while reporting a bug found another one. " "Ignoring.\n"); // Sleep long enough to make sure that the thread which started // to print an error report will finish doing it. SleepForSeconds(Max(100, flags()->sleep_before_dying + 1)); // If we're still not dead for some reason, use raw _exit() instead of // Die() to bypass any additional checks. internal__exit(common_flags()->exitcode); } else { // The other thread will eventually finish reporting // so it's safe to wait lock_.Lock(); } - StartReporting(report); + StartReporting(); } ~ScopedInErrorReport() { + ASAN_ON_ERROR(); + if (current_error_.IsValid()) current_error_.Print(); + // Make sure the current thread is announced. DescribeThread(GetCurrentThread()); // We may want to grab this lock again when printing stats. asanThreadRegistry().Unlock(); // Print memory stats. if (flags()->print_stats) __asan_print_accumulated_stats(); if (common_flags()->print_cmdline) PrintCmdline(); // Copy the message buffer so that we could start logging without holding a // lock that gets aquired during printing. InternalScopedBuffer buffer_copy(kErrorMessageBufferSize); { BlockingMutexLock l(&error_message_buf_mutex); internal_memcpy(buffer_copy.data(), error_message_buffer, kErrorMessageBufferSize); } LogFullErrorReport(buffer_copy.data()); if (error_report_callback) { error_report_callback(buffer_copy.data()); } + + // In halt_on_error = false mode, reset the current error object (before + // unlocking). + if (!halt_on_error_) + internal_memset(¤t_error_, 0, sizeof(current_error_)); + CommonSanitizerReportMutex.Unlock(); reporting_thread_tid_ = kInvalidTid; lock_.Unlock(); if (halt_on_error_) { Report("ABORTING\n"); Die(); } } + void ReportError(const ErrorDescription &description) { + // Can only report one error per ScopedInErrorReport. + CHECK_EQ(current_error_.kind, kErrorKindInvalid); + current_error_ = description; + } + + static ErrorDescription &CurrentError() { + return current_error_; + } + private: - void StartReporting(ReportData *report) { - if (report) report_data = *report; - report_happened = true; - ASAN_ON_ERROR(); + void StartReporting() { // Make sure the registry and sanitizer report mutexes are locked while // we're printing an error report. // We can lock them only here to avoid self-deadlock in case of // recursive reports. asanThreadRegistry().Lock(); CommonSanitizerReportMutex.Lock(); reporting_thread_tid_ = GetCurrentTidOrInvalid(); Printf("====================================================" "=============\n"); } static StaticSpinMutex lock_; static u32 reporting_thread_tid_; + // Error currently being reported. This enables the destructor to interact + // with the debugger and point it to an error description. + static ErrorDescription current_error_; bool halt_on_error_; }; StaticSpinMutex ScopedInErrorReport::lock_; u32 ScopedInErrorReport::reporting_thread_tid_ = kInvalidTid; +ErrorDescription ScopedInErrorReport::current_error_; void ReportStackOverflow(const SignalContext &sig) { - ScopedInErrorReport in_report(/*report*/ nullptr, /*fatal*/ true); - Decorator d; - Printf("%s", d.Warning()); - Report( - "ERROR: AddressSanitizer: stack-overflow on address %p" - " (pc %p bp %p sp %p T%d)\n", - (void *)sig.addr, (void *)sig.pc, (void *)sig.bp, (void *)sig.sp, - GetCurrentTidOrInvalid()); - Printf("%s", d.EndWarning()); - ScarinessScore::PrintSimple(10, "stack-overflow"); - GET_STACK_TRACE_SIGNAL(sig); - stack.Print(); - ReportErrorSummary("stack-overflow", &stack); + ScopedInErrorReport in_report(/*fatal*/ true); + ErrorStackOverflow error(GetCurrentTidOrInvalid(), sig); + in_report.ReportError(error); } -void ReportDeadlySignal(const char *description, const SignalContext &sig) { - ScopedInErrorReport in_report(/*report*/ nullptr, /*fatal*/ true); - Decorator d; - Printf("%s", d.Warning()); - Report( - "ERROR: AddressSanitizer: %s on unknown address %p" - " (pc %p bp %p sp %p T%d)\n", - description, (void *)sig.addr, (void *)sig.pc, (void *)sig.bp, - (void *)sig.sp, GetCurrentTidOrInvalid()); - Printf("%s", d.EndWarning()); - ScarinessScore SS; - 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.addr < GetPageSizeCached()) { - Report("Hint: address points to the zero page.\n"); - SS.Scare(10, "null-deref"); - } else if (sig.addr == sig.pc) { - SS.Scare(60, "wild-jump"); - } else if (sig.write_flag == SignalContext::WRITE) { - SS.Scare(30, "wild-addr-write"); - } else if (sig.write_flag == SignalContext::READ) { - SS.Scare(20, "wild-addr-read"); - } else { - SS.Scare(25, "wild-addr"); - } - } else { - SS.Scare(10, "signal"); - } - SS.Print(); - GET_STACK_TRACE_SIGNAL(sig); - stack.Print(); - MaybeDumpInstructionBytes(sig.pc); - Printf("AddressSanitizer can not provide additional info.\n"); - ReportErrorSummary(description, &stack); +void ReportDeadlySignal(int signo, const SignalContext &sig) { + ScopedInErrorReport in_report(/*fatal*/ true); + ErrorDeadlySignal error(GetCurrentTidOrInvalid(), sig, signo); + in_report.ReportError(error); } void ReportDoubleFree(uptr addr, BufferedStackTrace *free_stack) { ScopedInErrorReport in_report; - Decorator d; - Printf("%s", d.Warning()); - char tname[128]; - u32 curr_tid = GetCurrentTidOrInvalid(); - Report("ERROR: AddressSanitizer: attempting double-free on %p in " - "thread T%d%s:\n", - addr, curr_tid, - ThreadNameWithParenthesis(curr_tid, tname, sizeof(tname))); - Printf("%s", d.EndWarning()); - CHECK_GT(free_stack->size, 0); - ScarinessScore::PrintSimple(42, "double-free"); - GET_STACK_TRACE_FATAL(free_stack->trace[0], free_stack->top_frame_bp); - stack.Print(); - DescribeHeapAddress(addr, 1); - ReportErrorSummary("double-free", &stack); + ErrorDoubleFree error(GetCurrentTidOrInvalid(), free_stack, addr); + in_report.ReportError(error); } -void ReportNewDeleteSizeMismatch(uptr addr, uptr alloc_size, uptr delete_size, +void ReportNewDeleteSizeMismatch(uptr addr, uptr delete_size, BufferedStackTrace *free_stack) { ScopedInErrorReport in_report; - Decorator d; - Printf("%s", d.Warning()); - char tname[128]; - u32 curr_tid = GetCurrentTidOrInvalid(); - Report("ERROR: AddressSanitizer: new-delete-type-mismatch on %p in " - "thread T%d%s:\n", - addr, curr_tid, - ThreadNameWithParenthesis(curr_tid, tname, sizeof(tname))); - Printf("%s object passed to delete has wrong type:\n", d.EndWarning()); - Printf(" size of the allocated type: %zd bytes;\n" - " size of the deallocated type: %zd bytes.\n", - alloc_size, delete_size); - CHECK_GT(free_stack->size, 0); - ScarinessScore::PrintSimple(10, "new-delete-type-mismatch"); - GET_STACK_TRACE_FATAL(free_stack->trace[0], free_stack->top_frame_bp); - stack.Print(); - DescribeHeapAddress(addr, 1); - ReportErrorSummary("new-delete-type-mismatch", &stack); - Report("HINT: if you don't care about these errors you may set " - "ASAN_OPTIONS=new_delete_type_mismatch=0\n"); + ErrorNewDeleteSizeMismatch error(GetCurrentTidOrInvalid(), free_stack, addr, + delete_size); + in_report.ReportError(error); } void ReportFreeNotMalloced(uptr addr, BufferedStackTrace *free_stack) { ScopedInErrorReport in_report; - Decorator d; - Printf("%s", d.Warning()); - char tname[128]; - u32 curr_tid = GetCurrentTidOrInvalid(); - Report("ERROR: AddressSanitizer: attempting free on address " - "which was not malloc()-ed: %p in thread T%d%s\n", addr, - curr_tid, ThreadNameWithParenthesis(curr_tid, tname, sizeof(tname))); - Printf("%s", d.EndWarning()); - CHECK_GT(free_stack->size, 0); - ScarinessScore::PrintSimple(40, "bad-free"); - GET_STACK_TRACE_FATAL(free_stack->trace[0], free_stack->top_frame_bp); - stack.Print(); - DescribeHeapAddress(addr, 1); - ReportErrorSummary("bad-free", &stack); + ErrorFreeNotMalloced error(GetCurrentTidOrInvalid(), free_stack, addr); + in_report.ReportError(error); } void ReportAllocTypeMismatch(uptr addr, BufferedStackTrace *free_stack, AllocType alloc_type, AllocType dealloc_type) { - static const char *alloc_names[] = - {"INVALID", "malloc", "operator new", "operator new []"}; - static const char *dealloc_names[] = - {"INVALID", "free", "operator delete", "operator delete []"}; - CHECK_NE(alloc_type, dealloc_type); ScopedInErrorReport in_report; - Decorator d; - Printf("%s", d.Warning()); - Report("ERROR: AddressSanitizer: alloc-dealloc-mismatch (%s vs %s) on %p\n", - alloc_names[alloc_type], dealloc_names[dealloc_type], addr); - Printf("%s", d.EndWarning()); - CHECK_GT(free_stack->size, 0); - ScarinessScore::PrintSimple(10, "alloc-dealloc-mismatch"); - GET_STACK_TRACE_FATAL(free_stack->trace[0], free_stack->top_frame_bp); - stack.Print(); - DescribeHeapAddress(addr, 1); - ReportErrorSummary("alloc-dealloc-mismatch", &stack); - Report("HINT: if you don't care about these errors you may set " - "ASAN_OPTIONS=alloc_dealloc_mismatch=0\n"); + ErrorAllocTypeMismatch error(GetCurrentTidOrInvalid(), free_stack, addr, + alloc_type, dealloc_type); + in_report.ReportError(error); } void ReportMallocUsableSizeNotOwned(uptr addr, BufferedStackTrace *stack) { ScopedInErrorReport in_report; - Decorator d; - Printf("%s", d.Warning()); - Report("ERROR: AddressSanitizer: attempting to call " - "malloc_usable_size() for pointer which is " - "not owned: %p\n", addr); - Printf("%s", d.EndWarning()); - stack->Print(); - DescribeHeapAddress(addr, 1); - ReportErrorSummary("bad-malloc_usable_size", stack); + ErrorMallocUsableSizeNotOwned error(GetCurrentTidOrInvalid(), stack, addr); + in_report.ReportError(error); } void ReportSanitizerGetAllocatedSizeNotOwned(uptr addr, BufferedStackTrace *stack) { ScopedInErrorReport in_report; - Decorator d; - Printf("%s", d.Warning()); - Report("ERROR: AddressSanitizer: attempting to call " - "__sanitizer_get_allocated_size() for pointer which is " - "not owned: %p\n", addr); - Printf("%s", d.EndWarning()); - stack->Print(); - DescribeHeapAddress(addr, 1); - ReportErrorSummary("bad-__sanitizer_get_allocated_size", stack); + ErrorSanitizerGetAllocatedSizeNotOwned error(GetCurrentTidOrInvalid(), stack, + addr); + in_report.ReportError(error); } void ReportStringFunctionMemoryRangesOverlap(const char *function, const char *offset1, uptr length1, const char *offset2, uptr length2, BufferedStackTrace *stack) { ScopedInErrorReport in_report; - Decorator d; - char bug_type[100]; - internal_snprintf(bug_type, sizeof(bug_type), "%s-param-overlap", function); - Printf("%s", d.Warning()); - Report("ERROR: AddressSanitizer: %s: " - "memory ranges [%p,%p) and [%p, %p) overlap\n", \ - bug_type, offset1, offset1 + length1, offset2, offset2 + length2); - Printf("%s", d.EndWarning()); - ScarinessScore::PrintSimple(10, bug_type); - stack->Print(); - DescribeAddress((uptr)offset1, length1, bug_type); - DescribeAddress((uptr)offset2, length2, bug_type); - ReportErrorSummary(bug_type, stack); + ErrorStringFunctionMemoryRangesOverlap error( + GetCurrentTidOrInvalid(), stack, (uptr)offset1, length1, (uptr)offset2, + length2, function); + in_report.ReportError(error); } void ReportStringFunctionSizeOverflow(uptr offset, uptr size, BufferedStackTrace *stack) { ScopedInErrorReport in_report; - Decorator d; - const char *bug_type = "negative-size-param"; - Printf("%s", d.Warning()); - Report("ERROR: AddressSanitizer: %s: (size=%zd)\n", bug_type, size); - Printf("%s", d.EndWarning()); - ScarinessScore::PrintSimple(10, bug_type); - stack->Print(); - DescribeAddress(offset, size, bug_type); - ReportErrorSummary(bug_type, stack); + ErrorStringFunctionSizeOverflow error(GetCurrentTidOrInvalid(), stack, offset, + size); + in_report.ReportError(error); } void ReportBadParamsToAnnotateContiguousContainer(uptr beg, uptr end, uptr old_mid, uptr new_mid, BufferedStackTrace *stack) { ScopedInErrorReport in_report; - Report("ERROR: AddressSanitizer: bad parameters to " - "__sanitizer_annotate_contiguous_container:\n" - " beg : %p\n" - " end : %p\n" - " old_mid : %p\n" - " new_mid : %p\n", - beg, end, old_mid, new_mid); - uptr granularity = SHADOW_GRANULARITY; - if (!IsAligned(beg, granularity)) - Report("ERROR: beg is not aligned by %d\n", granularity); - stack->Print(); - ReportErrorSummary("bad-__sanitizer_annotate_contiguous_container", stack); + ErrorBadParamsToAnnotateContiguousContainer error( + GetCurrentTidOrInvalid(), stack, beg, end, old_mid, new_mid); + in_report.ReportError(error); } void ReportODRViolation(const __asan_global *g1, u32 stack_id1, const __asan_global *g2, u32 stack_id2) { ScopedInErrorReport in_report; - Decorator d; - Printf("%s", d.Warning()); - Report("ERROR: AddressSanitizer: odr-violation (%p):\n", g1->beg); - Printf("%s", d.EndWarning()); - InternalScopedString g1_loc(256), g2_loc(256); - PrintGlobalLocation(&g1_loc, *g1); - PrintGlobalLocation(&g2_loc, *g2); - Printf(" [1] size=%zd '%s' %s\n", g1->size, - MaybeDemangleGlobalName(g1->name), g1_loc.data()); - Printf(" [2] size=%zd '%s' %s\n", g2->size, - MaybeDemangleGlobalName(g2->name), g2_loc.data()); - if (stack_id1 && stack_id2) { - Printf("These globals were registered at these points:\n"); - Printf(" [1]:\n"); - StackDepotGet(stack_id1).Print(); - Printf(" [2]:\n"); - StackDepotGet(stack_id2).Print(); - } - Report("HINT: if you don't care about these errors you may set " - "ASAN_OPTIONS=detect_odr_violation=0\n"); - InternalScopedString error_msg(256); - error_msg.append("odr-violation: global '%s' at %s", - MaybeDemangleGlobalName(g1->name), g1_loc.data()); - ReportErrorSummary(error_msg.data()); + ErrorODRViolation error(GetCurrentTidOrInvalid(), g1, stack_id1, g2, + stack_id2); + in_report.ReportError(error); } // ----------------------- CheckForInvalidPointerPair ----------- {{{1 -static NOINLINE void -ReportInvalidPointerPair(uptr pc, uptr bp, uptr sp, uptr a1, uptr a2) { +static NOINLINE void ReportInvalidPointerPair(uptr pc, uptr bp, uptr sp, + uptr a1, uptr a2) { ScopedInErrorReport in_report; - const char *bug_type = "invalid-pointer-pair"; - Decorator d; - Printf("%s", d.Warning()); - Report("ERROR: AddressSanitizer: invalid-pointer-pair: %p %p\n", a1, a2); - Printf("%s", d.EndWarning()); - GET_STACK_TRACE_FATAL(pc, bp); - stack.Print(); - DescribeAddress(a1, 1, bug_type); - DescribeAddress(a2, 1, bug_type); - ReportErrorSummary(bug_type, &stack); + ErrorInvalidPointerPair error(GetCurrentTidOrInvalid(), pc, bp, sp, a1, a2); + in_report.ReportError(error); } static INLINE void CheckForInvalidPointerPair(void *p1, void *p2) { if (!flags()->detect_invalid_pointer_pairs) return; uptr a1 = reinterpret_cast(p1); uptr a2 = reinterpret_cast(p2); AsanChunkView chunk1 = FindHeapChunkByAddress(a1); AsanChunkView chunk2 = FindHeapChunkByAddress(a2); bool valid1 = chunk1.IsAllocated(); bool valid2 = chunk2.IsAllocated(); if (!valid1 || !valid2 || !chunk1.Eq(chunk2)) { GET_CALLER_PC_BP_SP; return ReportInvalidPointerPair(pc, bp, sp, a1, a2); } } // ----------------------- Mac-specific reports ----------------- {{{1 void ReportMacMzReallocUnknown(uptr addr, uptr zone_ptr, const char *zone_name, BufferedStackTrace *stack) { ScopedInErrorReport in_report; Printf("mz_realloc(%p) -- attempting to realloc unallocated memory.\n" "This is an unrecoverable problem, exiting now.\n", addr); PrintZoneForPointer(addr, zone_ptr, zone_name); stack->Print(); - DescribeHeapAddress(addr, 1); + DescribeAddressIfHeap(addr); } // -------------- SuppressErrorReport -------------- {{{1 // Avoid error reports duplicating for ASan recover mode. static bool SuppressErrorReport(uptr pc) { if (!common_flags()->suppress_equal_pcs) return false; for (unsigned i = 0; i < kAsanBuggyPcPoolSize; i++) { uptr cmp = atomic_load_relaxed(&AsanBuggyPcPool[i]); if (cmp == 0 && atomic_compare_exchange_strong(&AsanBuggyPcPool[i], &cmp, pc, memory_order_relaxed)) return false; if (cmp == pc) return true; } Die(); } -static void PrintContainerOverflowHint() { - Printf("HINT: if you don't care about these errors you may set " - "ASAN_OPTIONS=detect_container_overflow=0.\n" - "If you suspect a false positive see also: " - "https://github.com/google/sanitizers/wiki/" - "AddressSanitizerContainerOverflow.\n"); -} - -static bool AdjacentShadowValuesAreFullyPoisoned(u8 *s) { - return s[-1] > 127 && s[1] > 127; -} - void ReportGenericError(uptr pc, uptr bp, uptr sp, uptr addr, bool is_write, uptr access_size, u32 exp, bool fatal) { if (!fatal && SuppressErrorReport(pc)) return; ENABLE_FRAME_POINTER; - ScarinessScore SS; - if (access_size) { - if (access_size <= 9) { - char desr[] = "?-byte"; - desr[0] = '0' + access_size; - SS.Scare(access_size + access_size / 2, desr); - } else if (access_size >= 10) { - SS.Scare(15, "multi-byte"); - } - is_write ? SS.Scare(20, "write") : SS.Scare(1, "read"); - } - // Optimization experiments. // The experiments can be used to evaluate potential optimizations that remove // instrumentation (assess false negatives). Instead of completely removing // some instrumentation, compiler can emit special calls into runtime // (e.g. __asan_report_exp_load1 instead of __asan_report_load1) and pass // mask of experiments (exp). // The reaction to a non-zero value of exp is to be defined. (void)exp; - // Determine the error type. - const char *bug_descr = "unknown-crash"; - u8 shadow_val = 0; - if (AddrIsInMem(addr)) { - u8 *shadow_addr = (u8*)MemToShadow(addr); - // If we are accessing 16 bytes, look at the second shadow byte. - if (*shadow_addr == 0 && access_size > SHADOW_GRANULARITY) - shadow_addr++; - // If we are in the partial right redzone, look at the next shadow byte. - if (*shadow_addr > 0 && *shadow_addr < 128) - shadow_addr++; - bool far_from_bounds = false; - shadow_val = *shadow_addr; - int bug_type_score = 0; - // For use-after-frees reads are almost as bad as writes. - int read_after_free_bonus = 0; - switch (shadow_val) { - case kAsanHeapLeftRedzoneMagic: - case kAsanHeapRightRedzoneMagic: - case kAsanArrayCookieMagic: - bug_descr = "heap-buffer-overflow"; - bug_type_score = 10; - far_from_bounds = AdjacentShadowValuesAreFullyPoisoned(shadow_addr); - break; - case kAsanHeapFreeMagic: - bug_descr = "heap-use-after-free"; - bug_type_score = 20; - if (!is_write) read_after_free_bonus = 18; - break; - case kAsanStackLeftRedzoneMagic: - bug_descr = "stack-buffer-underflow"; - bug_type_score = 25; - far_from_bounds = AdjacentShadowValuesAreFullyPoisoned(shadow_addr); - break; - case kAsanInitializationOrderMagic: - bug_descr = "initialization-order-fiasco"; - bug_type_score = 1; - break; - case kAsanStackMidRedzoneMagic: - case kAsanStackRightRedzoneMagic: - case kAsanStackPartialRedzoneMagic: - bug_descr = "stack-buffer-overflow"; - bug_type_score = 25; - far_from_bounds = AdjacentShadowValuesAreFullyPoisoned(shadow_addr); - break; - case kAsanStackAfterReturnMagic: - bug_descr = "stack-use-after-return"; - bug_type_score = 30; - if (!is_write) read_after_free_bonus = 18; - break; - case kAsanUserPoisonedMemoryMagic: - bug_descr = "use-after-poison"; - bug_type_score = 20; - break; - case kAsanContiguousContainerOOBMagic: - bug_descr = "container-overflow"; - bug_type_score = 10; - break; - case kAsanStackUseAfterScopeMagic: - bug_descr = "stack-use-after-scope"; - bug_type_score = 10; - break; - case kAsanGlobalRedzoneMagic: - bug_descr = "global-buffer-overflow"; - bug_type_score = 10; - far_from_bounds = AdjacentShadowValuesAreFullyPoisoned(shadow_addr); - break; - case kAsanIntraObjectRedzone: - bug_descr = "intra-object-overflow"; - bug_type_score = 10; - break; - case kAsanAllocaLeftMagic: - case kAsanAllocaRightMagic: - bug_descr = "dynamic-stack-buffer-overflow"; - bug_type_score = 25; - far_from_bounds = AdjacentShadowValuesAreFullyPoisoned(shadow_addr); - break; - } - SS.Scare(bug_type_score + read_after_free_bonus, bug_descr); - if (far_from_bounds) - SS.Scare(10, "far-from-bounds"); - } - - ReportData report = { pc, sp, bp, addr, (bool)is_write, access_size, - bug_descr }; - ScopedInErrorReport in_report(&report, fatal); - - Decorator d; - Printf("%s", d.Warning()); - Report("ERROR: AddressSanitizer: %s on address " - "%p at pc %p bp %p sp %p\n", - bug_descr, (void*)addr, pc, bp, sp); - Printf("%s", d.EndWarning()); - - u32 curr_tid = GetCurrentTidOrInvalid(); - char tname[128]; - Printf("%s%s of size %zu at %p thread T%d%s%s\n", - d.Access(), - access_size ? (is_write ? "WRITE" : "READ") : "ACCESS", - access_size, (void*)addr, curr_tid, - ThreadNameWithParenthesis(curr_tid, tname, sizeof(tname)), - d.EndAccess()); - - SS.Print(); - GET_STACK_TRACE_FATAL(pc, bp); - stack.Print(); - - DescribeAddress(addr, access_size, bug_descr); - if (shadow_val == kAsanContiguousContainerOOBMagic) - PrintContainerOverflowHint(); - ReportErrorSummary(bug_descr, &stack); - PrintShadowMemoryForAddress(addr); + ScopedInErrorReport in_report(fatal); + ErrorGeneric error(GetCurrentTidOrInvalid(), pc, bp, sp, addr, is_write, + access_size); + in_report.ReportError(error); } } // namespace __asan // --------------------------- Interface --------------------- {{{1 using namespace __asan; // NOLINT void __asan_report_error(uptr pc, uptr bp, uptr sp, uptr addr, int is_write, uptr access_size, u32 exp) { ENABLE_FRAME_POINTER; bool fatal = flags()->halt_on_error; ReportGenericError(pc, bp, sp, addr, is_write, access_size, exp, fatal); } void NOINLINE __asan_set_error_report_callback(void (*callback)(const char*)) { BlockingMutexLock l(&error_message_buf_mutex); error_report_callback = callback; } void __asan_describe_address(uptr addr) { // Thread registry must be locked while we're describing an address. asanThreadRegistry().Lock(); - DescribeAddress(addr, 1, ""); + PrintAddressDescription(addr, 1, ""); asanThreadRegistry().Unlock(); } int __asan_report_present() { - return report_happened ? 1 : 0; + return ScopedInErrorReport::CurrentError().kind != kErrorKindInvalid; } uptr __asan_get_report_pc() { - return report_data.pc; + if (ScopedInErrorReport::CurrentError().kind == kErrorKindGeneric) + return ScopedInErrorReport::CurrentError().Generic.pc; + return 0; } uptr __asan_get_report_bp() { - return report_data.bp; + if (ScopedInErrorReport::CurrentError().kind == kErrorKindGeneric) + return ScopedInErrorReport::CurrentError().Generic.bp; + return 0; } uptr __asan_get_report_sp() { - return report_data.sp; + if (ScopedInErrorReport::CurrentError().kind == kErrorKindGeneric) + return ScopedInErrorReport::CurrentError().Generic.sp; + return 0; } uptr __asan_get_report_address() { - return report_data.addr; + ErrorDescription &err = ScopedInErrorReport::CurrentError(); + if (err.kind == kErrorKindGeneric) + return err.Generic.addr_description.Address(); + else if (err.kind == kErrorKindDoubleFree) + return err.DoubleFree.addr_description.addr; + return 0; } int __asan_get_report_access_type() { - return report_data.is_write ? 1 : 0; + if (ScopedInErrorReport::CurrentError().kind == kErrorKindGeneric) + return ScopedInErrorReport::CurrentError().Generic.is_write; + return 0; } uptr __asan_get_report_access_size() { - return report_data.access_size; + if (ScopedInErrorReport::CurrentError().kind == kErrorKindGeneric) + return ScopedInErrorReport::CurrentError().Generic.access_size; + return 0; } const char *__asan_get_report_description() { - return report_data.description; + if (ScopedInErrorReport::CurrentError().kind == kErrorKindGeneric) + return ScopedInErrorReport::CurrentError().Generic.bug_descr; + return ScopedInErrorReport::CurrentError().Base.scariness.GetDescription(); } extern "C" { SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_ptr_sub(void *a, void *b) { CheckForInvalidPointerPair(a, b); } SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_ptr_cmp(void *a, void *b) { CheckForInvalidPointerPair(a, b); } } // extern "C" #if !SANITIZER_SUPPORTS_WEAK_HOOKS // Provide default implementation of __asan_on_error that does nothing // and may be overriden by user. SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE NOINLINE void __asan_on_error() {} #endif Index: projects/clang400-import/contrib/compiler-rt/lib/asan/asan_report.h =================================================================== --- projects/clang400-import/contrib/compiler-rt/lib/asan/asan_report.h (revision 311696) +++ projects/clang400-import/contrib/compiler-rt/lib/asan/asan_report.h (revision 311697) @@ -1,87 +1,81 @@ //===-- asan_report.h -------------------------------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // This file is a part of AddressSanitizer, an address sanity checker. // // ASan-private header for error reporting functions. //===----------------------------------------------------------------------===// #include "asan_allocator.h" #include "asan_internal.h" #include "asan_thread.h" namespace __asan { struct StackVarDescr { uptr beg; uptr size; const char *name_pos; uptr name_len; }; -struct AddressDescription { - char *name; - uptr name_size; - uptr region_address; - uptr region_size; - const char *region_kind; -}; - // Returns the number of globals close to the provided address and copies // them to "globals" array. int GetGlobalsForAddress(uptr addr, __asan_global *globals, u32 *reg_sites, int max_globals); -bool GetInfoForAddressIfGlobal(uptr addr, AddressDescription *descr); + +const char *MaybeDemangleGlobalName(const char *name); +void PrintGlobalNameIfASCII(InternalScopedString *str, const __asan_global &g); +void PrintGlobalLocation(InternalScopedString *str, const __asan_global &g); + +void PrintMemoryByte(InternalScopedString *str, const char *before, u8 byte, + bool in_shadow, const char *after = "\n"); + // The following functions prints address description depending // on the memory type (shadow/heap/stack/global). -void DescribeHeapAddress(uptr addr, uptr access_size); -bool DescribeAddressIfShadow(uptr addr, AddressDescription *descr = nullptr, - bool print = true); bool ParseFrameDescription(const char *frame_descr, InternalMmapVector *vars); -bool DescribeAddressIfStack(uptr addr, uptr access_size); -void DescribeThread(AsanThreadContext *context); // Different kinds of error reports. void ReportGenericError(uptr pc, uptr bp, uptr sp, uptr addr, bool is_write, uptr access_size, u32 exp, bool fatal); void ReportStackOverflow(const SignalContext &sig); -void ReportDeadlySignal(const char *description, const SignalContext &sig); -void ReportNewDeleteSizeMismatch(uptr addr, uptr alloc_size, uptr delete_size, +void ReportDeadlySignal(int signo, const SignalContext &sig); +void ReportNewDeleteSizeMismatch(uptr addr, uptr delete_size, BufferedStackTrace *free_stack); void ReportDoubleFree(uptr addr, BufferedStackTrace *free_stack); void ReportFreeNotMalloced(uptr addr, BufferedStackTrace *free_stack); void ReportAllocTypeMismatch(uptr addr, BufferedStackTrace *free_stack, AllocType alloc_type, AllocType dealloc_type); void ReportMallocUsableSizeNotOwned(uptr addr, BufferedStackTrace *stack); void ReportSanitizerGetAllocatedSizeNotOwned(uptr addr, BufferedStackTrace *stack); void ReportStringFunctionMemoryRangesOverlap(const char *function, const char *offset1, uptr length1, const char *offset2, uptr length2, BufferedStackTrace *stack); void ReportStringFunctionSizeOverflow(uptr offset, uptr size, BufferedStackTrace *stack); void ReportBadParamsToAnnotateContiguousContainer(uptr beg, uptr end, uptr old_mid, uptr new_mid, BufferedStackTrace *stack); void ReportODRViolation(const __asan_global *g1, u32 stack_id1, const __asan_global *g2, u32 stack_id2); // Mac-specific errors and warnings. void ReportMacMzReallocUnknown(uptr addr, uptr zone_ptr, const char *zone_name, BufferedStackTrace *stack); void ReportMacCfReallocUnknown(uptr addr, uptr zone_ptr, const char *zone_name, BufferedStackTrace *stack); } // namespace __asan Index: projects/clang400-import/contrib/compiler-rt/lib/asan/asan_rtl.cc =================================================================== --- projects/clang400-import/contrib/compiler-rt/lib/asan/asan_rtl.cc (revision 311696) +++ projects/clang400-import/contrib/compiler-rt/lib/asan/asan_rtl.cc (revision 311697) @@ -1,648 +1,695 @@ //===-- asan_rtl.cc -------------------------------------------------------===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // This file is a part of AddressSanitizer, an address sanity checker. // // Main file of the ASan run-time library. //===----------------------------------------------------------------------===// #include "asan_activation.h" #include "asan_allocator.h" #include "asan_interceptors.h" #include "asan_interface_internal.h" #include "asan_internal.h" #include "asan_mapping.h" #include "asan_poisoning.h" #include "asan_report.h" #include "asan_stack.h" #include "asan_stats.h" #include "asan_suppressions.h" #include "asan_thread.h" #include "sanitizer_common/sanitizer_atomic.h" #include "sanitizer_common/sanitizer_flags.h" #include "sanitizer_common/sanitizer_libc.h" #include "sanitizer_common/sanitizer_symbolizer.h" #include "lsan/lsan_common.h" #include "ubsan/ubsan_init.h" #include "ubsan/ubsan_platform.h" +uptr __asan_shadow_memory_dynamic_address; // Global interface symbol. int __asan_option_detect_stack_use_after_return; // Global interface symbol. uptr *__asan_test_only_reported_buggy_pointer; // Used only for testing asan. namespace __asan { uptr AsanMappingProfile[kAsanMappingProfileSize]; static void AsanDie() { static atomic_uint32_t num_calls; if (atomic_fetch_add(&num_calls, 1, memory_order_relaxed) != 0) { // Don't die twice - run a busy loop. while (1) { } } if (flags()->sleep_before_dying) { Report("Sleeping for %d second(s)\n", flags()->sleep_before_dying); SleepForSeconds(flags()->sleep_before_dying); } if (flags()->unmap_shadow_on_exit) { if (kMidMemBeg) { UnmapOrDie((void*)kLowShadowBeg, kMidMemBeg - kLowShadowBeg); UnmapOrDie((void*)kMidMemEnd, kHighShadowEnd - kMidMemEnd); } else { UnmapOrDie((void*)kLowShadowBeg, kHighShadowEnd - kLowShadowBeg); } } } static void AsanCheckFailed(const char *file, int line, const char *cond, u64 v1, u64 v2) { Report("AddressSanitizer CHECK failed: %s:%d \"%s\" (0x%zx, 0x%zx)\n", file, line, cond, (uptr)v1, (uptr)v2); // FIXME: check for infinite recursion without a thread-local counter here. PRINT_CURRENT_STACK_CHECK(); Die(); } // -------------------------- Globals --------------------- {{{1 int asan_inited; bool asan_init_is_running; #if !ASAN_FIXED_MAPPING uptr kHighMemEnd, kMidMemBeg, kMidMemEnd; #endif // -------------------------- Misc ---------------- {{{1 void ShowStatsAndAbort() { __asan_print_accumulated_stats(); Die(); } // ---------------------- mmap -------------------- {{{1 // 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) { 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. void *res = MmapFixedNoReserve(beg, size, name); if (res != (void*)beg) { Report("ReserveShadowMemoryRange failed while trying to map 0x%zx bytes. " "Perhaps you're using ulimit -v\n", size); Abort(); } if (common_flags()->no_huge_pages_for_shadow) NoHugePagesInRegion(beg, size); if (common_flags()->use_madv_dontdump) DontDumpShadowMemory(beg, size); } // --------------- LowLevelAllocateCallbac ---------- {{{1 static void OnLowLevelAllocate(uptr ptr, uptr size) { PoisonShadow(ptr, size, kAsanInternalHeapMagic); } // -------------------------- Run-time entry ------------------- {{{1 // exported functions #define ASAN_REPORT_ERROR(type, is_write, size) \ extern "C" NOINLINE INTERFACE_ATTRIBUTE \ void __asan_report_ ## type ## size(uptr addr) { \ GET_CALLER_PC_BP_SP; \ ReportGenericError(pc, bp, sp, addr, is_write, size, 0, true); \ } \ extern "C" NOINLINE INTERFACE_ATTRIBUTE \ void __asan_report_exp_ ## type ## size(uptr addr, u32 exp) { \ GET_CALLER_PC_BP_SP; \ ReportGenericError(pc, bp, sp, addr, is_write, size, exp, true); \ } \ extern "C" NOINLINE INTERFACE_ATTRIBUTE \ void __asan_report_ ## type ## size ## _noabort(uptr addr) { \ GET_CALLER_PC_BP_SP; \ ReportGenericError(pc, bp, sp, addr, is_write, size, 0, false); \ } \ ASAN_REPORT_ERROR(load, false, 1) ASAN_REPORT_ERROR(load, false, 2) ASAN_REPORT_ERROR(load, false, 4) ASAN_REPORT_ERROR(load, false, 8) ASAN_REPORT_ERROR(load, false, 16) ASAN_REPORT_ERROR(store, true, 1) ASAN_REPORT_ERROR(store, true, 2) ASAN_REPORT_ERROR(store, true, 4) ASAN_REPORT_ERROR(store, true, 8) ASAN_REPORT_ERROR(store, true, 16) #define ASAN_REPORT_ERROR_N(type, is_write) \ extern "C" NOINLINE INTERFACE_ATTRIBUTE \ void __asan_report_ ## type ## _n(uptr addr, uptr size) { \ GET_CALLER_PC_BP_SP; \ ReportGenericError(pc, bp, sp, addr, is_write, size, 0, true); \ } \ extern "C" NOINLINE INTERFACE_ATTRIBUTE \ void __asan_report_exp_ ## type ## _n(uptr addr, uptr size, u32 exp) { \ GET_CALLER_PC_BP_SP; \ ReportGenericError(pc, bp, sp, addr, is_write, size, exp, true); \ } \ extern "C" NOINLINE INTERFACE_ATTRIBUTE \ void __asan_report_ ## type ## _n_noabort(uptr addr, uptr size) { \ GET_CALLER_PC_BP_SP; \ ReportGenericError(pc, bp, sp, addr, is_write, size, 0, false); \ } \ ASAN_REPORT_ERROR_N(load, false) ASAN_REPORT_ERROR_N(store, true) #define ASAN_MEMORY_ACCESS_CALLBACK_BODY(type, is_write, size, exp_arg, fatal) \ uptr sp = MEM_TO_SHADOW(addr); \ uptr s = size <= SHADOW_GRANULARITY ? *reinterpret_cast(sp) \ : *reinterpret_cast(sp); \ if (UNLIKELY(s)) { \ if (UNLIKELY(size >= SHADOW_GRANULARITY || \ ((s8)((addr & (SHADOW_GRANULARITY - 1)) + size - 1)) >= \ (s8)s)) { \ if (__asan_test_only_reported_buggy_pointer) { \ *__asan_test_only_reported_buggy_pointer = addr; \ } else { \ GET_CALLER_PC_BP_SP; \ ReportGenericError(pc, bp, sp, addr, is_write, size, exp_arg, \ fatal); \ } \ } \ } #define ASAN_MEMORY_ACCESS_CALLBACK(type, is_write, size) \ extern "C" NOINLINE INTERFACE_ATTRIBUTE \ void __asan_##type##size(uptr addr) { \ ASAN_MEMORY_ACCESS_CALLBACK_BODY(type, is_write, size, 0, true) \ } \ extern "C" NOINLINE INTERFACE_ATTRIBUTE \ void __asan_exp_##type##size(uptr addr, u32 exp) { \ ASAN_MEMORY_ACCESS_CALLBACK_BODY(type, is_write, size, exp, true) \ } \ extern "C" NOINLINE INTERFACE_ATTRIBUTE \ void __asan_##type##size ## _noabort(uptr addr) { \ ASAN_MEMORY_ACCESS_CALLBACK_BODY(type, is_write, size, 0, false) \ } \ ASAN_MEMORY_ACCESS_CALLBACK(load, false, 1) ASAN_MEMORY_ACCESS_CALLBACK(load, false, 2) ASAN_MEMORY_ACCESS_CALLBACK(load, false, 4) ASAN_MEMORY_ACCESS_CALLBACK(load, false, 8) ASAN_MEMORY_ACCESS_CALLBACK(load, false, 16) ASAN_MEMORY_ACCESS_CALLBACK(store, true, 1) ASAN_MEMORY_ACCESS_CALLBACK(store, true, 2) ASAN_MEMORY_ACCESS_CALLBACK(store, true, 4) ASAN_MEMORY_ACCESS_CALLBACK(store, true, 8) ASAN_MEMORY_ACCESS_CALLBACK(store, true, 16) extern "C" NOINLINE INTERFACE_ATTRIBUTE void __asan_loadN(uptr addr, uptr size) { if (__asan_region_is_poisoned(addr, size)) { GET_CALLER_PC_BP_SP; ReportGenericError(pc, bp, sp, addr, false, size, 0, true); } } extern "C" NOINLINE INTERFACE_ATTRIBUTE void __asan_exp_loadN(uptr addr, uptr size, u32 exp) { if (__asan_region_is_poisoned(addr, size)) { GET_CALLER_PC_BP_SP; ReportGenericError(pc, bp, sp, addr, false, size, exp, true); } } extern "C" NOINLINE INTERFACE_ATTRIBUTE void __asan_loadN_noabort(uptr addr, uptr size) { if (__asan_region_is_poisoned(addr, size)) { GET_CALLER_PC_BP_SP; ReportGenericError(pc, bp, sp, addr, false, size, 0, false); } } extern "C" NOINLINE INTERFACE_ATTRIBUTE void __asan_storeN(uptr addr, uptr size) { if (__asan_region_is_poisoned(addr, size)) { GET_CALLER_PC_BP_SP; ReportGenericError(pc, bp, sp, addr, true, size, 0, true); } } extern "C" NOINLINE INTERFACE_ATTRIBUTE void __asan_exp_storeN(uptr addr, uptr size, u32 exp) { if (__asan_region_is_poisoned(addr, size)) { GET_CALLER_PC_BP_SP; ReportGenericError(pc, bp, sp, addr, true, size, exp, true); } } extern "C" NOINLINE INTERFACE_ATTRIBUTE void __asan_storeN_noabort(uptr addr, uptr size) { if (__asan_region_is_poisoned(addr, size)) { GET_CALLER_PC_BP_SP; ReportGenericError(pc, bp, sp, addr, true, size, 0, false); } } // Force the linker to keep the symbols for various ASan interface functions. // We want to keep those in the executable in order to let the instrumented // dynamic libraries access the symbol even if it is not used by the executable // itself. This should help if the build system is removing dead code at link // time. static NOINLINE void force_interface_symbols() { volatile int fake_condition = 0; // prevent dead condition elimination. // __asan_report_* functions are noreturn, so we need a switch to prevent // the compiler from removing any of them. + // clang-format off switch (fake_condition) { case 1: __asan_report_load1(0); break; case 2: __asan_report_load2(0); break; case 3: __asan_report_load4(0); break; case 4: __asan_report_load8(0); break; case 5: __asan_report_load16(0); break; case 6: __asan_report_load_n(0, 0); break; case 7: __asan_report_store1(0); break; case 8: __asan_report_store2(0); break; case 9: __asan_report_store4(0); break; case 10: __asan_report_store8(0); break; case 11: __asan_report_store16(0); break; case 12: __asan_report_store_n(0, 0); break; case 13: __asan_report_exp_load1(0, 0); break; case 14: __asan_report_exp_load2(0, 0); break; case 15: __asan_report_exp_load4(0, 0); break; case 16: __asan_report_exp_load8(0, 0); break; case 17: __asan_report_exp_load16(0, 0); break; case 18: __asan_report_exp_load_n(0, 0, 0); break; case 19: __asan_report_exp_store1(0, 0); break; case 20: __asan_report_exp_store2(0, 0); break; case 21: __asan_report_exp_store4(0, 0); break; case 22: __asan_report_exp_store8(0, 0); break; case 23: __asan_report_exp_store16(0, 0); break; case 24: __asan_report_exp_store_n(0, 0, 0); break; case 25: __asan_register_globals(nullptr, 0); break; case 26: __asan_unregister_globals(nullptr, 0); break; case 27: __asan_set_death_callback(nullptr); break; case 28: __asan_set_error_report_callback(nullptr); break; case 29: __asan_handle_no_return(); break; case 30: __asan_address_is_poisoned(nullptr); break; case 31: __asan_poison_memory_region(nullptr, 0); break; case 32: __asan_unpoison_memory_region(nullptr, 0); break; case 34: __asan_before_dynamic_init(nullptr); break; case 35: __asan_after_dynamic_init(); break; case 36: __asan_poison_stack_memory(0, 0); break; case 37: __asan_unpoison_stack_memory(0, 0); break; case 38: __asan_region_is_poisoned(0, 0); break; case 39: __asan_describe_address(0); break; + case 40: __asan_set_shadow_00(0, 0); break; + case 41: __asan_set_shadow_f1(0, 0); break; + case 42: __asan_set_shadow_f2(0, 0); break; + case 43: __asan_set_shadow_f3(0, 0); break; + case 44: __asan_set_shadow_f5(0, 0); break; + case 45: __asan_set_shadow_f8(0, 0); break; } + // clang-format on } static void asan_atexit() { Printf("AddressSanitizer exit stats:\n"); __asan_print_accumulated_stats(); // Print AsanMappingProfile. for (uptr i = 0; i < kAsanMappingProfileSize; i++) { if (AsanMappingProfile[i] == 0) continue; Printf("asan_mapping.h:%zd -- %zd\n", i, AsanMappingProfile[i]); } } static void InitializeHighMemEnd() { #if !ASAN_FIXED_MAPPING kHighMemEnd = GetMaxVirtualAddress(); // Increase kHighMemEnd to make sure it's properly // aligned together with kHighMemBeg: kHighMemEnd |= SHADOW_GRANULARITY * GetMmapGranularity() - 1; #endif // !ASAN_FIXED_MAPPING CHECK_EQ((kHighMemBeg % GetMmapGranularity()), 0); } static void ProtectGap(uptr addr, uptr size) { - if (!flags()->protect_shadow_gap) + if (!flags()->protect_shadow_gap) { + // The shadow gap is unprotected, so there is a chance that someone + // is actually using this memory. Which means it needs a shadow... + uptr GapShadowBeg = RoundDownTo(MEM_TO_SHADOW(addr), GetPageSizeCached()); + uptr GapShadowEnd = + RoundUpTo(MEM_TO_SHADOW(addr + size), GetPageSizeCached()) - 1; + if (Verbosity()) + Printf("protect_shadow_gap=0:" + " not protecting shadow gap, allocating gap's shadow\n" + "|| `[%p, %p]` || ShadowGap's shadow ||\n", GapShadowBeg, + GapShadowEnd); + ReserveShadowMemoryRange(GapShadowBeg, GapShadowEnd, + "unprotected gap shadow"); 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 == kZeroBaseShadowStart) { uptr step = GetMmapGranularity(); while (size > step && addr < kZeroBaseMaxShadowStart) { addr += step; size -= step; void *res = MmapFixedNoAccess(addr, size, "shadow gap"); if (addr == (uptr)res) return; } } Report("ERROR: Failed to protect the shadow gap. " "ASan cannot proceed correctly. ABORTING.\n"); DumpProcessMap(); Die(); } static void PrintAddressSpaceLayout() { Printf("|| `[%p, %p]` || HighMem ||\n", (void*)kHighMemBeg, (void*)kHighMemEnd); Printf("|| `[%p, %p]` || HighShadow ||\n", (void*)kHighShadowBeg, (void*)kHighShadowEnd); if (kMidMemBeg) { Printf("|| `[%p, %p]` || ShadowGap3 ||\n", (void*)kShadowGap3Beg, (void*)kShadowGap3End); Printf("|| `[%p, %p]` || MidMem ||\n", (void*)kMidMemBeg, (void*)kMidMemEnd); Printf("|| `[%p, %p]` || ShadowGap2 ||\n", (void*)kShadowGap2Beg, (void*)kShadowGap2End); Printf("|| `[%p, %p]` || MidShadow ||\n", (void*)kMidShadowBeg, (void*)kMidShadowEnd); } Printf("|| `[%p, %p]` || ShadowGap ||\n", (void*)kShadowGapBeg, (void*)kShadowGapEnd); if (kLowShadowBeg) { Printf("|| `[%p, %p]` || LowShadow ||\n", (void*)kLowShadowBeg, (void*)kLowShadowEnd); Printf("|| `[%p, %p]` || LowMem ||\n", (void*)kLowMemBeg, (void*)kLowMemEnd); } Printf("MemToShadow(shadow): %p %p %p %p", (void*)MEM_TO_SHADOW(kLowShadowBeg), (void*)MEM_TO_SHADOW(kLowShadowEnd), (void*)MEM_TO_SHADOW(kHighShadowBeg), (void*)MEM_TO_SHADOW(kHighShadowEnd)); if (kMidMemBeg) { Printf(" %p %p", (void*)MEM_TO_SHADOW(kMidShadowBeg), (void*)MEM_TO_SHADOW(kMidShadowEnd)); } Printf("\n"); Printf("redzone=%zu\n", (uptr)flags()->redzone); Printf("max_redzone=%zu\n", (uptr)flags()->max_redzone); Printf("quarantine_size_mb=%zuM\n", (uptr)flags()->quarantine_size_mb); + Printf("thread_local_quarantine_size_kb=%zuK\n", + (uptr)flags()->thread_local_quarantine_size_kb); Printf("malloc_context_size=%zu\n", (uptr)common_flags()->malloc_context_size); Printf("SHADOW_SCALE: %d\n", (int)SHADOW_SCALE); Printf("SHADOW_GRANULARITY: %d\n", (int)SHADOW_GRANULARITY); Printf("SHADOW_OFFSET: 0x%zx\n", (uptr)SHADOW_OFFSET); CHECK(SHADOW_SCALE >= 3 && SHADOW_SCALE <= 7); if (kMidMemBeg) CHECK(kMidShadowBeg > kLowShadowEnd && kMidMemBeg > kMidShadowEnd && kHighShadowBeg > kMidMemEnd); } +static void InitializeShadowMemory() { + // Set the shadow memory address to uninitialized. + __asan_shadow_memory_dynamic_address = kDefaultShadowSentinel; + + uptr shadow_start = kLowShadowBeg; + // Detect if a dynamic shadow address must used and find a available location + // when necessary. When dynamic address is used, the macro |kLowShadowBeg| + // expands to |__asan_shadow_memory_dynamic_address| which is + // |kDefaultShadowSentinel|. + if (shadow_start == kDefaultShadowSentinel) { + __asan_shadow_memory_dynamic_address = 0; + CHECK_EQ(0, kLowShadowBeg); + + uptr granularity = GetMmapGranularity(); + uptr alignment = 8 * granularity; + uptr left_padding = granularity; + uptr space_size = kHighShadowEnd + left_padding; + + shadow_start = FindAvailableMemoryRange(space_size, alignment, granularity); + CHECK_NE((uptr)0, shadow_start); + CHECK(IsAligned(shadow_start, alignment)); + } + // Update the shadow memory address (potentially) used by instrumentation. + __asan_shadow_memory_dynamic_address = shadow_start; + + if (kLowShadowBeg) + shadow_start -= GetMmapGranularity(); + bool full_shadow_is_available = + MemoryRangeIsAvailable(shadow_start, kHighShadowEnd); + +#if SANITIZER_LINUX && defined(__x86_64__) && defined(_LP64) && \ + !ASAN_FIXED_MAPPING + if (!full_shadow_is_available) { + kMidMemBeg = kLowMemEnd < 0x3000000000ULL ? 0x3000000000ULL : 0; + kMidMemEnd = kLowMemEnd < 0x3000000000ULL ? 0x4fffffffffULL : 0; + } +#endif + + if (Verbosity()) PrintAddressSpaceLayout(); + + if (full_shadow_is_available) { + // mmap the low shadow plus at least one page at the left. + if (kLowShadowBeg) + ReserveShadowMemoryRange(shadow_start, kLowShadowEnd, "low shadow"); + // mmap the high shadow. + ReserveShadowMemoryRange(kHighShadowBeg, kHighShadowEnd, "high shadow"); + // protect the gap. + ProtectGap(kShadowGapBeg, kShadowGapEnd - kShadowGapBeg + 1); + CHECK_EQ(kShadowGapEnd, kHighShadowBeg - 1); + } else if (kMidMemBeg && + MemoryRangeIsAvailable(shadow_start, kMidMemBeg - 1) && + MemoryRangeIsAvailable(kMidMemEnd + 1, kHighShadowEnd)) { + CHECK(kLowShadowBeg != kLowShadowEnd); + // mmap the low shadow plus at least one page at the left. + ReserveShadowMemoryRange(shadow_start, kLowShadowEnd, "low shadow"); + // mmap the mid shadow. + ReserveShadowMemoryRange(kMidShadowBeg, kMidShadowEnd, "mid shadow"); + // mmap the high shadow. + ReserveShadowMemoryRange(kHighShadowBeg, kHighShadowEnd, "high shadow"); + // protect the gaps. + ProtectGap(kShadowGapBeg, kShadowGapEnd - kShadowGapBeg + 1); + ProtectGap(kShadowGap2Beg, kShadowGap2End - kShadowGap2Beg + 1); + ProtectGap(kShadowGap3Beg, kShadowGap3End - kShadowGap3Beg + 1); + } else { + Report("Shadow memory range interleaves with an existing memory mapping. " + "ASan cannot proceed correctly. ABORTING.\n"); + Report("ASan shadow was supposed to be located in the [%p-%p] range.\n", + shadow_start, kHighShadowEnd); + DumpProcessMap(); + Die(); + } +} + static void AsanInitInternal() { if (LIKELY(asan_inited)) return; SanitizerToolName = "AddressSanitizer"; CHECK(!asan_init_is_running && "ASan init calls itself!"); asan_init_is_running = true; CacheBinaryName(); // Initialize flags. This must be done early, because most of the // initialization steps look at flags(). InitializeFlags(); AsanCheckIncompatibleRT(); AsanCheckDynamicRTPrereqs(); AvoidCVE_2016_2143(); SetCanPoisonMemory(flags()->poison_heap); SetMallocContextSize(common_flags()->malloc_context_size); InitializePlatformExceptionHandlers(); InitializeHighMemEnd(); // Make sure we are not statically linked. AsanDoesNotSupportStaticLinkage(); // Install tool-specific callbacks in sanitizer_common. AddDieCallback(AsanDie); SetCheckFailedCallback(AsanCheckFailed); SetPrintfAndReportCallback(AppendToErrorMessageBuffer); __sanitizer_set_report_path(common_flags()->log_path); - // Enable UAR detection, if required. __asan_option_detect_stack_use_after_return = flags()->detect_stack_use_after_return; // Re-exec ourselves if we need to set additional env or command line args. MaybeReexec(); // Setup internal allocator callback. SetLowLevelAllocateCallback(OnLowLevelAllocate); InitializeAsanInterceptors(); // Enable system log ("adb logcat") on Android. // Doing this before interceptors are initialized crashes in: // AsanInitInternal -> android_log_write -> __interceptor_strcmp AndroidLogInit(); ReplaceSystemMalloc(); - uptr shadow_start = kLowShadowBeg; - if (kLowShadowBeg) - shadow_start -= GetMmapGranularity(); - bool full_shadow_is_available = - MemoryRangeIsAvailable(shadow_start, kHighShadowEnd); - -#if SANITIZER_LINUX && defined(__x86_64__) && defined(_LP64) && \ - !ASAN_FIXED_MAPPING - if (!full_shadow_is_available) { - kMidMemBeg = kLowMemEnd < 0x3000000000ULL ? 0x3000000000ULL : 0; - kMidMemEnd = kLowMemEnd < 0x3000000000ULL ? 0x4fffffffffULL : 0; - } -#elif SANITIZER_WINDOWS64 - // Disable the "mid mem" shadow layout. - if (!full_shadow_is_available) { - kMidMemBeg = 0; - kMidMemEnd = 0; - } -#endif - - if (Verbosity()) PrintAddressSpaceLayout(); - DisableCoreDumperIfNecessary(); - if (full_shadow_is_available) { - // mmap the low shadow plus at least one page at the left. - if (kLowShadowBeg) - ReserveShadowMemoryRange(shadow_start, kLowShadowEnd, "low shadow"); - // mmap the high shadow. - ReserveShadowMemoryRange(kHighShadowBeg, kHighShadowEnd, "high shadow"); - // protect the gap. - ProtectGap(kShadowGapBeg, kShadowGapEnd - kShadowGapBeg + 1); - CHECK_EQ(kShadowGapEnd, kHighShadowBeg - 1); - } else if (kMidMemBeg && - MemoryRangeIsAvailable(shadow_start, kMidMemBeg - 1) && - MemoryRangeIsAvailable(kMidMemEnd + 1, kHighShadowEnd)) { - CHECK(kLowShadowBeg != kLowShadowEnd); - // mmap the low shadow plus at least one page at the left. - ReserveShadowMemoryRange(shadow_start, kLowShadowEnd, "low shadow"); - // mmap the mid shadow. - ReserveShadowMemoryRange(kMidShadowBeg, kMidShadowEnd, "mid shadow"); - // mmap the high shadow. - ReserveShadowMemoryRange(kHighShadowBeg, kHighShadowEnd, "high shadow"); - // protect the gaps. - ProtectGap(kShadowGapBeg, kShadowGapEnd - kShadowGapBeg + 1); - ProtectGap(kShadowGap2Beg, kShadowGap2End - kShadowGap2Beg + 1); - ProtectGap(kShadowGap3Beg, kShadowGap3End - kShadowGap3Beg + 1); - } else { - Report("Shadow memory range interleaves with an existing memory mapping. " - "ASan cannot proceed correctly. ABORTING.\n"); - Report("ASan shadow was supposed to be located in the [%p-%p] range.\n", - shadow_start, kHighShadowEnd); - DumpProcessMap(); - Die(); - } + InitializeShadowMemory(); AsanTSDInit(PlatformTSDDtor); InstallDeadlySignalHandlers(AsanOnDeadlySignal); AllocatorOptions allocator_options; allocator_options.SetFrom(flags(), common_flags()); InitializeAllocator(allocator_options); MaybeStartBackgroudThread(); SetSoftRssLimitExceededCallback(AsanSoftRssLimitExceededCallback); // On Linux AsanThread::ThreadStart() calls malloc() that's why asan_inited // should be set to 1 prior to initializing the threads. asan_inited = 1; asan_init_is_running = false; if (flags()->atexit) Atexit(asan_atexit); InitializeCoverage(common_flags()->coverage, common_flags()->coverage_dir); // Now that ASan runtime is (mostly) initialized, deactivate it if // necessary, so that it can be re-activated when requested. if (flags()->start_deactivated) AsanDeactivate(); // interceptors InitTlsSize(); // Create main thread. AsanThread *main_thread = AsanThread::Create( /* start_routine */ nullptr, /* arg */ nullptr, /* parent_tid */ 0, /* stack */ nullptr, /* detached */ true); CHECK_EQ(0, main_thread->tid()); SetCurrentThread(main_thread); main_thread->ThreadStart(internal_getpid(), /* signal_thread_is_registered */ nullptr); force_interface_symbols(); // no-op. SanitizerInitializeUnwinder(); if (CAN_SANITIZE_LEAKS) { __lsan::InitCommonLsan(); if (common_flags()->detect_leaks && common_flags()->leak_check_at_exit) { Atexit(__lsan::DoLeakCheck); } } #if CAN_SANITIZE_UB __ubsan::InitAsPlugin(); #endif InitializeSuppressions(); if (CAN_SANITIZE_LEAKS) { // LateInitialize() calls dlsym, which can allocate an error string buffer // in the TLS. Let's ignore the allocation to avoid reporting a leak. __lsan::ScopedInterceptorDisabler disabler; Symbolizer::LateInitialize(); } else { Symbolizer::LateInitialize(); } VReport(1, "AddressSanitizer Init done\n"); } // Initialize as requested from some part of ASan runtime library (interceptors, // allocator, etc). void AsanInitFromRtl() { AsanInitInternal(); } #if ASAN_DYNAMIC // Initialize runtime in case it's LD_PRELOAD-ed into unsanitized executable // (and thus normal initializers from .preinit_array or modules haven't run). class AsanInitializer { public: // NOLINT AsanInitializer() { AsanInitFromRtl(); } }; static AsanInitializer asan_initializer; #endif // ASAN_DYNAMIC } // namespace __asan // ---------------------- Interface ---------------- {{{1 using namespace __asan; // NOLINT void NOINLINE __asan_handle_no_return() { + if (asan_init_is_running) + return; + int local_stack; AsanThread *curr_thread = GetCurrentThread(); uptr PageSize = GetPageSizeCached(); uptr top, bottom; if (curr_thread) { top = curr_thread->stack_top(); bottom = ((uptr)&local_stack - PageSize) & ~(PageSize - 1); } else { // If we haven't seen this thread, try asking the OS for stack bounds. uptr tls_addr, tls_size, stack_size; GetThreadStackAndTls(/*main=*/false, &bottom, &stack_size, &tls_addr, &tls_size); top = bottom + stack_size; } static const uptr kMaxExpectedCleanupSize = 64 << 20; // 64M if (top - bottom > kMaxExpectedCleanupSize) { static bool reported_warning = false; if (reported_warning) return; reported_warning = true; Report("WARNING: ASan is ignoring requested __asan_handle_no_return: " "stack top: %p; bottom %p; size: %p (%zd)\n" "False positive error reports may follow\n" "For details see " "https://github.com/google/sanitizers/issues/189\n", top, bottom, top - bottom, top - bottom); return; } PoisonShadow(bottom, top - bottom, 0); if (curr_thread && curr_thread->has_fake_stack()) curr_thread->fake_stack()->HandleNoReturn(); } void NOINLINE __asan_set_death_callback(void (*callback)(void)) { SetUserDieCallback(callback); } // Initialize as requested from instrumented application code. // We use this call as a trigger to wake up ASan from deactivated state. void __asan_init() { AsanActivate(); AsanInitInternal(); } void __asan_version_mismatch_check() { // Do nothing. } Index: projects/clang400-import/contrib/compiler-rt/lib/asan/asan_scariness_score.h =================================================================== --- projects/clang400-import/contrib/compiler-rt/lib/asan/asan_scariness_score.h (revision 311696) +++ projects/clang400-import/contrib/compiler-rt/lib/asan/asan_scariness_score.h (revision 311697) @@ -1,67 +1,74 @@ //===-- asan_scariness_score.h ----------------------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // This file is a part of AddressSanitizer, an address sanity checker. // // Compute the level of scariness of the error message. // Don't expect any deep science here, just a set of heuristics that suggest // that e.g. 1-byte-read-global-buffer-overflow is less scary than // 8-byte-write-stack-use-after-return. // // Every error report has one or more features, such as memory access size, // type (read or write), type of accessed memory (e.g. free-d heap, or a global // redzone), etc. Every such feature has an int score and a string description. // The overall score is the sum of all feature scores and the description // is a concatenation of feature descriptions. // Examples: // 17 (4-byte-read-heap-buffer-overflow) // 65 (multi-byte-write-stack-use-after-return) // 10 (null-deref) // //===----------------------------------------------------------------------===// #ifndef ASAN_SCARINESS_SCORE_H #define ASAN_SCARINESS_SCORE_H #include "asan_flags.h" #include "sanitizer_common/sanitizer_common.h" #include "sanitizer_common/sanitizer_libc.h" namespace __asan { -class ScarinessScore { - public: - ScarinessScore() { +struct ScarinessScoreBase { + void Clear() { descr[0] = 0; + score = 0; } void Scare(int add_to_score, const char *reason) { if (descr[0]) internal_strlcat(descr, "-", sizeof(descr)); internal_strlcat(descr, reason, sizeof(descr)); score += add_to_score; }; int GetScore() const { return score; } const char *GetDescription() const { return descr; } void Print() { if (score && flags()->print_scariness) Printf("SCARINESS: %d (%s)\n", score, descr); } static void PrintSimple(int score, const char *descr) { - ScarinessScore SS; - SS.Scare(score, descr); - SS.Print(); + ScarinessScoreBase SSB; + SSB.Clear(); + SSB.Scare(score, descr); + SSB.Print(); } private: - int score = 0; + int score; char descr[1024]; +}; + +struct ScarinessScore : ScarinessScoreBase { + ScarinessScore() { + Clear(); + } }; } // namespace __asan #endif // ASAN_SCARINESS_SCORE_H Index: projects/clang400-import/contrib/compiler-rt/lib/asan/asan_thread.cc =================================================================== --- projects/clang400-import/contrib/compiler-rt/lib/asan/asan_thread.cc (revision 311696) +++ projects/clang400-import/contrib/compiler-rt/lib/asan/asan_thread.cc (revision 311697) @@ -1,458 +1,468 @@ //===-- asan_thread.cc ----------------------------------------------------===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // This file is a part of AddressSanitizer, an address sanity checker. // // Thread-related code. //===----------------------------------------------------------------------===// #include "asan_allocator.h" #include "asan_interceptors.h" #include "asan_poisoning.h" #include "asan_stack.h" #include "asan_thread.h" #include "asan_mapping.h" #include "sanitizer_common/sanitizer_common.h" #include "sanitizer_common/sanitizer_placement_new.h" #include "sanitizer_common/sanitizer_stackdepot.h" #include "sanitizer_common/sanitizer_tls_get_addr.h" #include "lsan/lsan_common.h" namespace __asan { // AsanThreadContext implementation. struct CreateThreadContextArgs { AsanThread *thread; StackTrace *stack; }; void AsanThreadContext::OnCreated(void *arg) { CreateThreadContextArgs *args = static_cast(arg); if (args->stack) stack_id = StackDepotPut(*args->stack); thread = args->thread; thread->set_context(this); } void AsanThreadContext::OnFinished() { // Drop the link to the AsanThread object. thread = nullptr; } // MIPS requires aligned address static ALIGNED(16) char thread_registry_placeholder[sizeof(ThreadRegistry)]; static ThreadRegistry *asan_thread_registry; static BlockingMutex mu_for_thread_context(LINKER_INITIALIZED); static LowLevelAllocator allocator_for_thread_context; static ThreadContextBase *GetAsanThreadContext(u32 tid) { BlockingMutexLock lock(&mu_for_thread_context); return new(allocator_for_thread_context) AsanThreadContext(tid); } ThreadRegistry &asanThreadRegistry() { static bool initialized; // Don't worry about thread_safety - this should be called when there is // a single thread. if (!initialized) { // Never reuse ASan threads: we store pointer to AsanThreadContext // in TSD and can't reliably tell when no more TSD destructors will // be called. It would be wrong to reuse AsanThreadContext for another // thread before all TSD destructors will be called for it. asan_thread_registry = new(thread_registry_placeholder) ThreadRegistry( GetAsanThreadContext, kMaxNumberOfThreads, kMaxNumberOfThreads); initialized = true; } return *asan_thread_registry; } AsanThreadContext *GetThreadContextByTidLocked(u32 tid) { return static_cast( asanThreadRegistry().GetThreadLocked(tid)); } // AsanThread implementation. AsanThread *AsanThread::Create(thread_callback_t start_routine, void *arg, u32 parent_tid, StackTrace *stack, bool detached) { uptr PageSize = GetPageSizeCached(); uptr size = RoundUpTo(sizeof(AsanThread), PageSize); AsanThread *thread = (AsanThread*)MmapOrDie(size, __func__); thread->start_routine_ = start_routine; thread->arg_ = arg; CreateThreadContextArgs args = { thread, stack }; asanThreadRegistry().CreateThread(*reinterpret_cast(thread), detached, parent_tid, &args); return thread; } void AsanThread::TSDDtor(void *tsd) { AsanThreadContext *context = (AsanThreadContext*)tsd; VReport(1, "T%d TSDDtor\n", context->tid); if (context->thread) context->thread->Destroy(); } void AsanThread::Destroy() { int tid = this->tid(); VReport(1, "T%d exited\n", tid); malloc_storage().CommitBack(); if (common_flags()->use_sigaltstack) UnsetAlternateSignalStack(); asanThreadRegistry().FinishThread(tid); FlushToDeadThreadStats(&stats_); // We also clear the shadow on thread destruction because // some code may still be executing in later TSD destructors // and we don't want it to have any poisoned stack. ClearShadowForThreadStackAndTLS(); DeleteFakeStack(tid); uptr size = RoundUpTo(sizeof(AsanThread), GetPageSizeCached()); UnmapOrDie(this, size); DTLS_Destroy(); } void AsanThread::StartSwitchFiber(FakeStack **fake_stack_save, uptr bottom, uptr size) { if (atomic_load(&stack_switching_, memory_order_relaxed)) { Report("ERROR: starting fiber switch while in fiber switch\n"); Die(); } next_stack_bottom_ = bottom; next_stack_top_ = bottom + size; atomic_store(&stack_switching_, 1, memory_order_release); FakeStack *current_fake_stack = fake_stack_; if (fake_stack_save) *fake_stack_save = fake_stack_; fake_stack_ = nullptr; SetTLSFakeStack(nullptr); // if fake_stack_save is null, the fiber will die, delete the fakestack if (!fake_stack_save && current_fake_stack) current_fake_stack->Destroy(this->tid()); } -void AsanThread::FinishSwitchFiber(FakeStack *fake_stack_save) { +void AsanThread::FinishSwitchFiber(FakeStack *fake_stack_save, + uptr *bottom_old, + uptr *size_old) { if (!atomic_load(&stack_switching_, memory_order_relaxed)) { Report("ERROR: finishing a fiber switch that has not started\n"); Die(); } if (fake_stack_save) { SetTLSFakeStack(fake_stack_save); fake_stack_ = fake_stack_save; } + if (bottom_old) + *bottom_old = stack_bottom_; + if (size_old) + *size_old = stack_top_ - stack_bottom_; stack_bottom_ = next_stack_bottom_; stack_top_ = next_stack_top_; atomic_store(&stack_switching_, 0, memory_order_release); next_stack_top_ = 0; next_stack_bottom_ = 0; } inline AsanThread::StackBounds AsanThread::GetStackBounds() const { if (!atomic_load(&stack_switching_, memory_order_acquire)) return StackBounds{stack_bottom_, stack_top_}; // NOLINT char local; const uptr cur_stack = (uptr)&local; // Note: need to check next stack first, because FinishSwitchFiber // may be in process of overwriting stack_top_/bottom_. But in such case // we are already on the next stack. if (cur_stack >= next_stack_bottom_ && cur_stack < next_stack_top_) return StackBounds{next_stack_bottom_, next_stack_top_}; // NOLINT return StackBounds{stack_bottom_, stack_top_}; // NOLINT } uptr AsanThread::stack_top() { return GetStackBounds().top; } uptr AsanThread::stack_bottom() { return GetStackBounds().bottom; } uptr AsanThread::stack_size() { const auto bounds = GetStackBounds(); return bounds.top - bounds.bottom; } // We want to create the FakeStack lazyly on the first use, but not eralier // than the stack size is known and the procedure has to be async-signal safe. FakeStack *AsanThread::AsyncSignalSafeLazyInitFakeStack() { uptr stack_size = this->stack_size(); if (stack_size == 0) // stack_size is not yet available, don't use FakeStack. return nullptr; uptr old_val = 0; // fake_stack_ has 3 states: // 0 -- not initialized // 1 -- being initialized // ptr -- initialized // This CAS checks if the state was 0 and if so changes it to state 1, // if that was successful, it initializes the pointer. if (atomic_compare_exchange_strong( reinterpret_cast(&fake_stack_), &old_val, 1UL, memory_order_relaxed)) { uptr stack_size_log = Log2(RoundUpToPowerOfTwo(stack_size)); CHECK_LE(flags()->min_uar_stack_size_log, flags()->max_uar_stack_size_log); stack_size_log = Min(stack_size_log, static_cast(flags()->max_uar_stack_size_log)); stack_size_log = Max(stack_size_log, static_cast(flags()->min_uar_stack_size_log)); fake_stack_ = FakeStack::Create(stack_size_log); SetTLSFakeStack(fake_stack_); return fake_stack_; } return nullptr; } void AsanThread::Init() { next_stack_top_ = next_stack_bottom_ = 0; atomic_store(&stack_switching_, false, memory_order_release); fake_stack_ = nullptr; // Will be initialized lazily if needed. CHECK_EQ(this->stack_size(), 0U); SetThreadStackAndTls(); CHECK_GT(this->stack_size(), 0U); CHECK(AddrIsInMem(stack_bottom_)); CHECK(AddrIsInMem(stack_top_ - 1)); ClearShadowForThreadStackAndTLS(); int local = 0; VReport(1, "T%d: stack [%p,%p) size 0x%zx; local=%p\n", tid(), (void *)stack_bottom_, (void *)stack_top_, stack_top_ - stack_bottom_, &local); } thread_return_t AsanThread::ThreadStart( uptr os_id, atomic_uintptr_t *signal_thread_is_registered) { Init(); asanThreadRegistry().StartThread(tid(), os_id, nullptr); if (signal_thread_is_registered) atomic_store(signal_thread_is_registered, 1, memory_order_release); if (common_flags()->use_sigaltstack) SetAlternateSignalStack(); if (!start_routine_) { // start_routine_ == 0 if we're on the main thread or on one of the // OS X libdispatch worker threads. But nobody is supposed to call // ThreadStart() for the worker threads. CHECK_EQ(tid(), 0); return 0; } thread_return_t res = start_routine_(arg_); // On POSIX systems we defer this to the TSD destructor. LSan will consider // the thread's memory as non-live from the moment we call Destroy(), even // though that memory might contain pointers to heap objects which will be // cleaned up by a user-defined TSD destructor. Thus, calling Destroy() before // the TSD destructors have run might cause false positives in LSan. if (!SANITIZER_POSIX) this->Destroy(); return res; } void AsanThread::SetThreadStackAndTls() { uptr tls_size = 0; uptr stack_size = 0; GetThreadStackAndTls(tid() == 0, const_cast(&stack_bottom_), const_cast(&stack_size), &tls_begin_, &tls_size); stack_top_ = stack_bottom_ + stack_size; tls_end_ = tls_begin_ + tls_size; dtls_ = DTLS_Get(); int local; CHECK(AddrIsInStack((uptr)&local)); } void AsanThread::ClearShadowForThreadStackAndTLS() { PoisonShadow(stack_bottom_, stack_top_ - stack_bottom_, 0); if (tls_begin_ != tls_end_) PoisonShadow(tls_begin_, tls_end_ - tls_begin_, 0); } bool AsanThread::GetStackFrameAccessByAddr(uptr addr, StackFrameAccess *access) { uptr bottom = 0; if (AddrIsInStack(addr)) { bottom = stack_bottom(); } else if (has_fake_stack()) { bottom = fake_stack()->AddrIsInFakeStack(addr); CHECK(bottom); access->offset = addr - bottom; access->frame_pc = ((uptr*)bottom)[2]; access->frame_descr = (const char *)((uptr*)bottom)[1]; return true; } uptr aligned_addr = addr & ~(SANITIZER_WORDSIZE/8 - 1); // align addr. u8 *shadow_ptr = (u8*)MemToShadow(aligned_addr); u8 *shadow_bottom = (u8*)MemToShadow(bottom); while (shadow_ptr >= shadow_bottom && *shadow_ptr != kAsanStackLeftRedzoneMagic) { shadow_ptr--; } while (shadow_ptr >= shadow_bottom && *shadow_ptr == kAsanStackLeftRedzoneMagic) { shadow_ptr--; } if (shadow_ptr < shadow_bottom) { return false; } uptr* ptr = (uptr*)SHADOW_TO_MEM((uptr)(shadow_ptr + 1)); CHECK(ptr[0] == kCurrentStackFrameMagic); access->offset = addr - (uptr)ptr; access->frame_pc = ptr[2]; access->frame_descr = (const char*)ptr[1]; return true; } bool AsanThread::AddrIsInStack(uptr addr) { const auto bounds = GetStackBounds(); return addr >= bounds.bottom && addr < bounds.top; } static bool ThreadStackContainsAddress(ThreadContextBase *tctx_base, void *addr) { AsanThreadContext *tctx = static_cast(tctx_base); AsanThread *t = tctx->thread; if (!t) return false; if (t->AddrIsInStack((uptr)addr)) return true; if (t->has_fake_stack() && t->fake_stack()->AddrIsInFakeStack((uptr)addr)) return true; return false; } AsanThread *GetCurrentThread() { AsanThreadContext *context = reinterpret_cast(AsanTSDGet()); if (!context) { if (SANITIZER_ANDROID) { // On Android, libc constructor is called _after_ asan_init, and cleans up // TSD. Try to figure out if this is still the main thread by the stack // address. We are not entirely sure that we have correct main thread // limits, so only do this magic on Android, and only if the found thread // is the main thread. AsanThreadContext *tctx = GetThreadContextByTidLocked(0); - if (ThreadStackContainsAddress(tctx, &context)) { + if (tctx && ThreadStackContainsAddress(tctx, &context)) { SetCurrentThread(tctx->thread); return tctx->thread; } } return nullptr; } return context->thread; } void SetCurrentThread(AsanThread *t) { CHECK(t->context()); VReport(2, "SetCurrentThread: %p for thread %p\n", t->context(), (void *)GetThreadSelf()); // Make sure we do not reset the current AsanThread. CHECK_EQ(0, AsanTSDGet()); AsanTSDSet(t->context()); CHECK_EQ(t->context(), AsanTSDGet()); } u32 GetCurrentTidOrInvalid() { AsanThread *t = GetCurrentThread(); return t ? t->tid() : kInvalidTid; } AsanThread *FindThreadByStackAddress(uptr addr) { asanThreadRegistry().CheckLocked(); AsanThreadContext *tctx = static_cast( asanThreadRegistry().FindThreadContextLocked(ThreadStackContainsAddress, (void *)addr)); return tctx ? tctx->thread : nullptr; } void EnsureMainThreadIDIsCorrect() { AsanThreadContext *context = reinterpret_cast(AsanTSDGet()); if (context && (context->tid == 0)) context->os_id = GetTid(); } __asan::AsanThread *GetAsanThreadByOsIDLocked(uptr os_id) { __asan::AsanThreadContext *context = static_cast<__asan::AsanThreadContext *>( __asan::asanThreadRegistry().FindThreadContextByOsIDLocked(os_id)); if (!context) return nullptr; return context->thread; } } // namespace __asan // --- Implementation of LSan-specific functions --- {{{1 namespace __lsan { bool GetThreadRangesLocked(uptr os_id, uptr *stack_begin, uptr *stack_end, uptr *tls_begin, uptr *tls_end, uptr *cache_begin, uptr *cache_end, DTLS **dtls) { __asan::AsanThread *t = __asan::GetAsanThreadByOsIDLocked(os_id); if (!t) return false; *stack_begin = t->stack_bottom(); *stack_end = t->stack_top(); *tls_begin = t->tls_begin(); *tls_end = t->tls_end(); // ASan doesn't keep allocator caches in TLS, so these are unused. *cache_begin = 0; *cache_end = 0; *dtls = t->dtls(); return true; } void ForEachExtraStackRange(uptr os_id, RangeIteratorCallback callback, void *arg) { __asan::AsanThread *t = __asan::GetAsanThreadByOsIDLocked(os_id); if (t && t->has_fake_stack()) t->fake_stack()->ForEachFakeFrame(callback, arg); } void LockThreadRegistry() { __asan::asanThreadRegistry().Lock(); } void UnlockThreadRegistry() { __asan::asanThreadRegistry().Unlock(); } void EnsureMainThreadIDIsCorrect() { __asan::EnsureMainThreadIDIsCorrect(); } } // namespace __lsan // ---------------------- Interface ---------------- {{{1 using namespace __asan; // NOLINT extern "C" { SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_start_switch_fiber(void **fakestacksave, const void *bottom, uptr size) { AsanThread *t = GetCurrentThread(); if (!t) { VReport(1, "__asan_start_switch_fiber called from unknown thread\n"); return; } t->StartSwitchFiber((FakeStack**)fakestacksave, (uptr)bottom, size); } SANITIZER_INTERFACE_ATTRIBUTE -void __sanitizer_finish_switch_fiber(void* fakestack) { +void __sanitizer_finish_switch_fiber(void* fakestack, + const void **bottom_old, + uptr *size_old) { AsanThread *t = GetCurrentThread(); if (!t) { VReport(1, "__asan_finish_switch_fiber called from unknown thread\n"); return; } - t->FinishSwitchFiber((FakeStack*)fakestack); + t->FinishSwitchFiber((FakeStack*)fakestack, + (uptr*)bottom_old, + (uptr*)size_old); } } Index: projects/clang400-import/contrib/compiler-rt/lib/asan/asan_thread.h =================================================================== --- projects/clang400-import/contrib/compiler-rt/lib/asan/asan_thread.h (revision 311696) +++ projects/clang400-import/contrib/compiler-rt/lib/asan/asan_thread.h (revision 311697) @@ -1,205 +1,206 @@ //===-- asan_thread.h -------------------------------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // This file is a part of AddressSanitizer, an address sanity checker. // // ASan-private header for asan_thread.cc. //===----------------------------------------------------------------------===// #ifndef ASAN_THREAD_H #define ASAN_THREAD_H #include "asan_allocator.h" #include "asan_internal.h" #include "asan_fake_stack.h" #include "asan_stats.h" #include "sanitizer_common/sanitizer_common.h" #include "sanitizer_common/sanitizer_libc.h" #include "sanitizer_common/sanitizer_thread_registry.h" namespace __sanitizer { struct DTLS; } // namespace __sanitizer namespace __asan { const u32 kInvalidTid = 0xffffff; // Must fit into 24 bits. const u32 kMaxNumberOfThreads = (1 << 22); // 4M class AsanThread; // These objects are created for every thread and are never deleted, // so we can find them by tid even if the thread is long dead. class AsanThreadContext : public ThreadContextBase { public: explicit AsanThreadContext(int tid) : ThreadContextBase(tid), announced(false), destructor_iterations(GetPthreadDestructorIterations()), stack_id(0), thread(nullptr) {} bool announced; u8 destructor_iterations; u32 stack_id; AsanThread *thread; void OnCreated(void *arg) override; void OnFinished() override; }; // AsanThreadContext objects are never freed, so we need many of them. COMPILER_CHECK(sizeof(AsanThreadContext) <= 256); // AsanThread are stored in TSD and destroyed when the thread dies. class AsanThread { public: static AsanThread *Create(thread_callback_t start_routine, void *arg, u32 parent_tid, StackTrace *stack, bool detached); static void TSDDtor(void *tsd); void Destroy(); void Init(); // Should be called from the thread itself. thread_return_t ThreadStart(uptr os_id, atomic_uintptr_t *signal_thread_is_registered); uptr stack_top(); uptr stack_bottom(); uptr stack_size(); uptr tls_begin() { return tls_begin_; } uptr tls_end() { return tls_end_; } DTLS *dtls() { return dtls_; } u32 tid() { return context_->tid; } AsanThreadContext *context() { return context_; } void set_context(AsanThreadContext *context) { context_ = context; } struct StackFrameAccess { uptr offset; uptr frame_pc; const char *frame_descr; }; bool GetStackFrameAccessByAddr(uptr addr, StackFrameAccess *access); bool AddrIsInStack(uptr addr); void DeleteFakeStack(int tid) { if (!fake_stack_) return; FakeStack *t = fake_stack_; fake_stack_ = nullptr; SetTLSFakeStack(nullptr); t->Destroy(tid); } void StartSwitchFiber(FakeStack **fake_stack_save, uptr bottom, uptr size); - void FinishSwitchFiber(FakeStack *fake_stack_save); + void FinishSwitchFiber(FakeStack *fake_stack_save, uptr *bottom_old, + uptr *size_old); bool has_fake_stack() { return !atomic_load(&stack_switching_, memory_order_relaxed) && (reinterpret_cast(fake_stack_) > 1); } FakeStack *fake_stack() { if (!__asan_option_detect_stack_use_after_return) return nullptr; if (atomic_load(&stack_switching_, memory_order_relaxed)) return nullptr; if (!has_fake_stack()) return AsyncSignalSafeLazyInitFakeStack(); return fake_stack_; } // True is this thread is currently unwinding stack (i.e. collecting a stack // trace). Used to prevent deadlocks on platforms where libc unwinder calls // malloc internally. See PR17116 for more details. bool isUnwinding() const { return unwinding_; } void setUnwinding(bool b) { unwinding_ = b; } // True if we are in a deadly signal handler. bool isInDeadlySignal() const { return in_deadly_signal_; } void setInDeadlySignal(bool b) { in_deadly_signal_ = b; } AsanThreadLocalMallocStorage &malloc_storage() { return malloc_storage_; } AsanStats &stats() { return stats_; } private: // NOTE: There is no AsanThread constructor. It is allocated // via mmap() and *must* be valid in zero-initialized state. void SetThreadStackAndTls(); void ClearShadowForThreadStackAndTLS(); FakeStack *AsyncSignalSafeLazyInitFakeStack(); struct StackBounds { uptr bottom; uptr top; }; StackBounds GetStackBounds() const; AsanThreadContext *context_; thread_callback_t start_routine_; void *arg_; uptr stack_top_; uptr stack_bottom_; // these variables are used when the thread is about to switch stack uptr next_stack_top_; uptr next_stack_bottom_; // true if switching is in progress atomic_uint8_t stack_switching_; uptr tls_begin_; uptr tls_end_; DTLS *dtls_; FakeStack *fake_stack_; AsanThreadLocalMallocStorage malloc_storage_; AsanStats stats_; bool unwinding_; bool in_deadly_signal_; }; // ScopedUnwinding is a scope for stacktracing member of a context class ScopedUnwinding { public: explicit ScopedUnwinding(AsanThread *t) : thread(t) { t->setUnwinding(true); } ~ScopedUnwinding() { thread->setUnwinding(false); } private: AsanThread *thread; }; // ScopedDeadlySignal is a scope for handling deadly signals. class ScopedDeadlySignal { public: explicit ScopedDeadlySignal(AsanThread *t) : thread(t) { if (thread) thread->setInDeadlySignal(true); } ~ScopedDeadlySignal() { if (thread) thread->setInDeadlySignal(false); } private: AsanThread *thread; }; // Returns a single instance of registry. ThreadRegistry &asanThreadRegistry(); // Must be called under ThreadRegistryLock. AsanThreadContext *GetThreadContextByTidLocked(u32 tid); // Get the current thread. May return 0. AsanThread *GetCurrentThread(); void SetCurrentThread(AsanThread *t); u32 GetCurrentTidOrInvalid(); AsanThread *FindThreadByStackAddress(uptr addr); // Used to handle fork(). void EnsureMainThreadIDIsCorrect(); } // namespace __asan #endif // ASAN_THREAD_H Index: projects/clang400-import/contrib/compiler-rt/lib/asan/asan_win.cc =================================================================== --- projects/clang400-import/contrib/compiler-rt/lib/asan/asan_win.cc (revision 311696) +++ projects/clang400-import/contrib/compiler-rt/lib/asan/asan_win.cc (revision 311697) @@ -1,340 +1,376 @@ //===-- asan_win.cc -------------------------------------------------------===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // This file is a part of AddressSanitizer, an address sanity checker. // // Windows-specific details. //===----------------------------------------------------------------------===// #include "sanitizer_common/sanitizer_platform.h" #if SANITIZER_WINDOWS #define WIN32_LEAN_AND_MEAN #include #include +#include "asan_globals_win.h" #include "asan_interceptors.h" #include "asan_internal.h" #include "asan_report.h" #include "asan_stack.h" #include "asan_thread.h" #include "asan_mapping.h" #include "sanitizer_common/sanitizer_libc.h" #include "sanitizer_common/sanitizer_mutex.h" using namespace __asan; // NOLINT extern "C" { SANITIZER_INTERFACE_ATTRIBUTE int __asan_should_detect_stack_use_after_return() { __asan_init(); return __asan_option_detect_stack_use_after_return; } -// -------------------- A workaround for the abscence of weak symbols ----- {{{ +SANITIZER_INTERFACE_ATTRIBUTE +uptr __asan_get_shadow_memory_dynamic_address() { + __asan_init(); + return __asan_shadow_memory_dynamic_address; +} + +// -------------------- 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, which works nicely for allocator hooks and // __asan_default_options(). void __sanitizer_default_malloc_hook(void *ptr, uptr size) { } void __sanitizer_default_free_hook(void *ptr) { } const char* __asan_default_default_options() { return ""; } const char* __asan_default_default_suppressions() { return ""; } void __asan_default_on_error() {} // 64-bit msvc will not prepend an underscore for symbols. #ifdef _WIN64 #pragma comment(linker, "/alternatename:__sanitizer_malloc_hook=__sanitizer_default_malloc_hook") // NOLINT #pragma comment(linker, "/alternatename:__sanitizer_free_hook=__sanitizer_default_free_hook") // NOLINT #pragma comment(linker, "/alternatename:__asan_default_options=__asan_default_default_options") // NOLINT #pragma comment(linker, "/alternatename:__asan_default_suppressions=__asan_default_default_suppressions") // NOLINT #pragma comment(linker, "/alternatename:__asan_on_error=__asan_default_on_error") // NOLINT #else #pragma comment(linker, "/alternatename:___sanitizer_malloc_hook=___sanitizer_default_malloc_hook") // NOLINT #pragma comment(linker, "/alternatename:___sanitizer_free_hook=___sanitizer_default_free_hook") // NOLINT #pragma comment(linker, "/alternatename:___asan_default_options=___asan_default_default_options") // NOLINT #pragma comment(linker, "/alternatename:___asan_default_suppressions=___asan_default_default_suppressions") // NOLINT #pragma comment(linker, "/alternatename:___asan_on_error=___asan_default_on_error") // NOLINT #endif // }}} } // extern "C" -// ---------------------- Windows-specific inteceptors ---------------- {{{ +// ---------------------- Windows-specific interceptors ---------------- {{{ +INTERCEPTOR_WINAPI(void, RtlRaiseException, EXCEPTION_RECORD *ExceptionRecord) { + CHECK(REAL(RtlRaiseException)); + // This is a noreturn function, unless it's one of the exceptions raised to + // communicate with the debugger, such as the one from OutputDebugString. + if (ExceptionRecord->ExceptionCode != DBG_PRINTEXCEPTION_C) + __asan_handle_no_return(); + REAL(RtlRaiseException)(ExceptionRecord); +} + INTERCEPTOR_WINAPI(void, RaiseException, void *a, void *b, void *c, void *d) { CHECK(REAL(RaiseException)); __asan_handle_no_return(); REAL(RaiseException)(a, b, c, d); } - #ifdef _WIN64 INTERCEPTOR_WINAPI(int, __C_specific_handler, void *a, void *b, void *c, void *d) { // NOLINT CHECK(REAL(__C_specific_handler)); __asan_handle_no_return(); return REAL(__C_specific_handler)(a, b, c, d); } #else INTERCEPTOR(int, _except_handler3, void *a, void *b, void *c, void *d) { CHECK(REAL(_except_handler3)); __asan_handle_no_return(); return REAL(_except_handler3)(a, b, c, d); } #if ASAN_DYNAMIC // This handler is named differently in -MT and -MD CRTs. #define _except_handler4 _except_handler4_common #endif INTERCEPTOR(int, _except_handler4, void *a, void *b, void *c, void *d) { CHECK(REAL(_except_handler4)); __asan_handle_no_return(); return REAL(_except_handler4)(a, b, c, d); } #endif static thread_return_t THREAD_CALLING_CONV asan_thread_start(void *arg) { AsanThread *t = (AsanThread*)arg; SetCurrentThread(t); return t->ThreadStart(GetTid(), /* signal_thread_is_registered */ nullptr); } INTERCEPTOR_WINAPI(DWORD, CreateThread, void* security, uptr stack_size, DWORD (__stdcall *start_routine)(void*), void* arg, DWORD thr_flags, void* tid) { // Strict init-order checking is thread-hostile. if (flags()->strict_init_order) StopInitOrderChecking(); GET_STACK_TRACE_THREAD; // FIXME: The CreateThread interceptor is not the same as a pthread_create // one. This is a bandaid fix for PR22025. bool detached = false; // FIXME: how can we determine it on Windows? u32 current_tid = GetCurrentTidOrInvalid(); AsanThread *t = AsanThread::Create(start_routine, arg, current_tid, &stack, detached); return REAL(CreateThread)(security, stack_size, asan_thread_start, t, thr_flags, tid); } -namespace { -BlockingMutex mu_for_thread_tracking(LINKER_INITIALIZED); - -void EnsureWorkerThreadRegistered() { - // FIXME: GetCurrentThread relies on TSD, which might not play well with - // system thread pools. We might want to use something like reference - // counting to zero out GetCurrentThread() underlying storage when the last - // work item finishes? Or can we disable reclaiming of threads in the pool? - BlockingMutexLock l(&mu_for_thread_tracking); - if (__asan::GetCurrentThread()) - return; - - AsanThread *t = AsanThread::Create( - /* start_routine */ nullptr, /* arg */ nullptr, - /* parent_tid */ -1, /* stack */ nullptr, /* detached */ true); - t->Init(); - asanThreadRegistry().StartThread(t->tid(), 0, 0); - SetCurrentThread(t); -} -} // namespace - -INTERCEPTOR_WINAPI(DWORD, NtWaitForWorkViaWorkerFactory, DWORD a, DWORD b) { - // NtWaitForWorkViaWorkerFactory is called from system worker pool threads to - // query work scheduled by BindIoCompletionCallback, QueueUserWorkItem, etc. - // System worker pool threads are created at arbitraty point in time and - // without using CreateThread, so we wrap NtWaitForWorkViaWorkerFactory - // instead and don't register a specific parent_tid/stack. - EnsureWorkerThreadRegistered(); - return REAL(NtWaitForWorkViaWorkerFactory)(a, b); -} - // }}} namespace __asan { void InitializePlatformInterceptors() { ASAN_INTERCEPT_FUNC(CreateThread); - ASAN_INTERCEPT_FUNC(RaiseException); #ifdef _WIN64 ASAN_INTERCEPT_FUNC(__C_specific_handler); #else ASAN_INTERCEPT_FUNC(_except_handler3); ASAN_INTERCEPT_FUNC(_except_handler4); #endif - // NtWaitForWorkViaWorkerFactory is always linked dynamically. - CHECK(::__interception::OverrideFunction( - "NtWaitForWorkViaWorkerFactory", - (uptr)WRAP(NtWaitForWorkViaWorkerFactory), - (uptr *)&REAL(NtWaitForWorkViaWorkerFactory))); + // Try to intercept kernel32!RaiseException, and if that fails, intercept + // ntdll!RtlRaiseException instead. + if (!::__interception::OverrideFunction("RaiseException", + (uptr)WRAP(RaiseException), + (uptr *)&REAL(RaiseException))) { + CHECK(::__interception::OverrideFunction("RtlRaiseException", + (uptr)WRAP(RtlRaiseException), + (uptr *)&REAL(RtlRaiseException))); + } } void AsanApplyToGlobals(globals_op_fptr op, const void *needle) { UNIMPLEMENTED(); } // ---------------------- TSD ---------------- {{{ static bool tsd_key_inited = false; static __declspec(thread) void *fake_tsd = 0; void AsanTSDInit(void (*destructor)(void *tsd)) { // FIXME: we're ignoring the destructor for now. tsd_key_inited = true; } void *AsanTSDGet() { CHECK(tsd_key_inited); return fake_tsd; } void AsanTSDSet(void *tsd) { CHECK(tsd_key_inited); fake_tsd = tsd; } void PlatformTSDDtor(void *tsd) { AsanThread::TSDDtor(tsd); } // }}} // ---------------------- Various stuff ---------------- {{{ void *AsanDoesNotSupportStaticLinkage() { #if defined(_DEBUG) #error Please build the runtime with a non-debug CRT: /MD or /MT #endif return 0; } void AsanCheckDynamicRTPrereqs() {} void AsanCheckIncompatibleRT() {} void ReadContextStack(void *context, uptr *stack, uptr *ssize) { UNIMPLEMENTED(); } void AsanOnDeadlySignal(int, void *siginfo, void *context) { UNIMPLEMENTED(); } #if SANITIZER_WINDOWS64 // Exception handler for dealing with shadow memory. static LONG CALLBACK ShadowExceptionHandler(PEXCEPTION_POINTERS exception_pointers) { - static uptr page_size = GetPageSizeCached(); - static uptr alloc_granularity = GetMmapGranularity(); + uptr page_size = GetPageSizeCached(); // Only handle access violations. if (exception_pointers->ExceptionRecord->ExceptionCode != EXCEPTION_ACCESS_VIOLATION) { return EXCEPTION_CONTINUE_SEARCH; } // Only handle access violations that land within the shadow memory. uptr addr = (uptr)(exception_pointers->ExceptionRecord->ExceptionInformation[1]); // Check valid shadow range. if (!AddrIsInShadow(addr)) return EXCEPTION_CONTINUE_SEARCH; // This is an access violation while trying to read from the shadow. Commit // the relevant page and let execution continue. // Determine the address of the page that is being accessed. uptr page = RoundDownTo(addr, page_size); // Query the existing page. MEMORY_BASIC_INFORMATION mem_info = {}; if (::VirtualQuery((LPVOID)page, &mem_info, sizeof(mem_info)) == 0) return EXCEPTION_CONTINUE_SEARCH; // Commit the page. uptr result = (uptr)::VirtualAlloc((LPVOID)page, page_size, MEM_COMMIT, PAGE_READWRITE); if (result != page) return EXCEPTION_CONTINUE_SEARCH; // The page mapping succeeded, so continue execution as usual. return EXCEPTION_CONTINUE_EXECUTION; } #endif void InitializePlatformExceptionHandlers() { #if SANITIZER_WINDOWS64 // On Win64, we map memory on demand with access violation handler. // Install our exception handler. CHECK(AddVectoredExceptionHandler(TRUE, &ShadowExceptionHandler)); #endif } static LPTOP_LEVEL_EXCEPTION_FILTER default_seh_handler; -static long WINAPI SEHHandler(EXCEPTION_POINTERS *info) { - EXCEPTION_RECORD *exception_record = info->ExceptionRecord; - CONTEXT *context = info->ContextRecord; +// Check based on flags if we should report this exception. +static bool ShouldReportDeadlyException(unsigned code) { + switch (code) { + case EXCEPTION_ACCESS_VIOLATION: + case EXCEPTION_IN_PAGE_ERROR: + return common_flags()->handle_segv; + case EXCEPTION_BREAKPOINT: + case EXCEPTION_ILLEGAL_INSTRUCTION: { + return common_flags()->handle_sigill; + } + } + return false; +} - if (exception_record->ExceptionCode == EXCEPTION_ACCESS_VIOLATION || - exception_record->ExceptionCode == EXCEPTION_IN_PAGE_ERROR) { - const char *description = - (exception_record->ExceptionCode == EXCEPTION_ACCESS_VIOLATION) - ? "access-violation" - : "in-page-error"; - SignalContext sig = SignalContext::Create(exception_record, context); - ReportDeadlySignal(description, sig); +// Return the textual name for this exception. +const char *DescribeSignalOrException(int signo) { + unsigned code = signo; + // 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_IN_PAGE_ERROR: + return "in-page-error"; + case EXCEPTION_BREAKPOINT: + return "breakpoint"; + case EXCEPTION_ILLEGAL_INSTRUCTION: + return "illegal-instruction"; } + return nullptr; +} +extern "C" SANITIZER_INTERFACE_ATTRIBUTE +long __asan_unhandled_exception_filter(EXCEPTION_POINTERS *info) { + EXCEPTION_RECORD *exception_record = info->ExceptionRecord; + CONTEXT *context = info->ContextRecord; + + // Continue the search if the signal wasn't deadly. + if (!ShouldReportDeadlyException(exception_record->ExceptionCode)) + return EXCEPTION_CONTINUE_SEARCH; // FIXME: Handle EXCEPTION_STACK_OVERFLOW here. + SignalContext sig = SignalContext::Create(exception_record, context); + ReportDeadlySignal(exception_record->ExceptionCode, sig); + UNREACHABLE("returned from reporting deadly signal"); +} + +static long WINAPI SEHHandler(EXCEPTION_POINTERS *info) { + __asan_unhandled_exception_filter(info); + + // Bubble out to the default exception filter. return default_seh_handler(info); } // We want to install our own exception handler (EH) to print helpful reports // on access violations and whatnot. Unfortunately, the CRT initializers assume // they are run before any user code and drop any previously-installed EHs on // the floor, so we can't install our handler inside __asan_init. // (See crt0dat.c in the CRT sources for the details) // // Things get even more complicated with the dynamic runtime, as it finishes its // initialization before the .exe module CRT begins to initialize. // // For the static runtime (-MT), it's enough to put a callback to // __asan_set_seh_filter in the last section for C initializers. // // For the dynamic runtime (-MD), we want link the same // asan_dynamic_runtime_thunk.lib to all the modules, thus __asan_set_seh_filter // will be called for each instrumented module. This ensures that at least one // __asan_set_seh_filter call happens after the .exe module CRT is initialized. extern "C" SANITIZER_INTERFACE_ATTRIBUTE int __asan_set_seh_filter() { // We should only store the previous handler if it's not our own handler in // order to avoid loops in the EH chain. auto prev_seh_handler = SetUnhandledExceptionFilter(SEHHandler); if (prev_seh_handler != &SEHHandler) default_seh_handler = prev_seh_handler; return 0; } #if !ASAN_DYNAMIC // The CRT runs initializers in this order: // - C initializers, from XIA to XIZ // - C++ initializers, from XCA to XCZ // Prior to 2015, the CRT set the unhandled exception filter at priority XIY, // near the end of C initialization. Starting in 2015, it was moved to the // beginning of C++ initialization. We set our priority to XCAB to run // immediately after the CRT runs. This way, our exception filter is called // first and we can delegate to their filter if appropriate. #pragma section(".CRT$XCAB", long, read) // NOLINT -__declspec(allocate(".CRT$XCAB")) - int (*__intercept_seh)() = __asan_set_seh_filter; +__declspec(allocate(".CRT$XCAB")) int (*__intercept_seh)() = + __asan_set_seh_filter; + +// Piggyback on the TLS initialization callback directory to initialize asan as +// early as possible. Initializers in .CRT$XL* are called directly by ntdll, +// which run before the CRT. Users also add code to .CRT$XLC, so it's important +// to run our initializers first. +static void NTAPI asan_thread_init(void *module, DWORD reason, void *reserved) { + if (reason == DLL_PROCESS_ATTACH) __asan_init(); +} + +#pragma section(".CRT$XLAB", long, read) // NOLINT +__declspec(allocate(".CRT$XLAB")) void (NTAPI *__asan_tls_init)(void *, + unsigned long, void *) = asan_thread_init; #endif + +ASAN_LINK_GLOBALS_WIN() + // }}} } // namespace __asan -#endif // _WIN32 +#endif // SANITIZER_WINDOWS Index: projects/clang400-import/contrib/compiler-rt/lib/asan/asan_win_dll_thunk.cc =================================================================== --- projects/clang400-import/contrib/compiler-rt/lib/asan/asan_win_dll_thunk.cc (revision 311696) +++ projects/clang400-import/contrib/compiler-rt/lib/asan/asan_win_dll_thunk.cc (revision 311697) @@ -1,447 +1,483 @@ //===-- asan_win_dll_thunk.cc ---------------------------------------------===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // This file is a part of AddressSanitizer, an address sanity checker. // // This file defines a family of thunks that should be statically linked into // the DLLs that have ASan instrumentation in order to delegate the calls to the // shared runtime that lives in the main binary. // See https://github.com/google/sanitizers/issues/209 for the details. //===----------------------------------------------------------------------===// -// Only compile this code when buidling asan_dll_thunk.lib +// Only compile this code when building asan_dll_thunk.lib // Using #ifdef rather than relying on Makefiles etc. // simplifies the build procedure. #ifdef ASAN_DLL_THUNK #include "asan_init_version.h" +#include "asan_globals_win.h" #include "interception/interception.h" #include "sanitizer_common/sanitizer_platform_interceptors.h" +#ifdef _M_IX86 +#define WINAPI __stdcall +#else +#define WINAPI +#endif + // ---------- Function interception helper functions and macros ----------- {{{1 extern "C" { -void *__stdcall GetModuleHandleA(const char *module_name); -void *__stdcall GetProcAddress(void *module, const char *proc_name); +void *WINAPI GetModuleHandleA(const char *module_name); +void *WINAPI GetProcAddress(void *module, const char *proc_name); void abort(); } +using namespace __sanitizer; + static uptr getRealProcAddressOrDie(const char *name) { uptr ret = __interception::InternalGetProcAddress((void *)GetModuleHandleA(0), name); if (!ret) abort(); return ret; } // We need to intercept some functions (e.g. ASan interface, memory allocator -- // let's call them "hooks") exported by the DLL thunk and forward the hooks to // the runtime in the main module. // However, we don't want to keep two lists of these hooks. // To avoid that, the list of hooks should be defined using the // INTERCEPT_WHEN_POSSIBLE macro. Then, all these hooks can be intercepted // at once by calling INTERCEPT_HOOKS(). // Use macro+template magic to automatically generate the list of hooks. // Each hook at line LINE defines a template class with a static // FunctionInterceptor::Execute() method intercepting the hook. // The default implementation of FunctionInterceptor is to call // the Execute() method corresponding to the previous line. template struct FunctionInterceptor { static void Execute() { FunctionInterceptor::Execute(); } }; // There shouldn't be any hooks with negative definition line number. template<> struct FunctionInterceptor<0> { static void Execute() {} }; #define INTERCEPT_WHEN_POSSIBLE(main_function, dll_function) \ template <> struct FunctionInterceptor<__LINE__> { \ static void Execute() { \ uptr wrapper = getRealProcAddressOrDie(main_function); \ if (!__interception::OverrideFunction((uptr)dll_function, wrapper, 0)) \ abort(); \ FunctionInterceptor<__LINE__ - 1>::Execute(); \ } \ }; // Special case of hooks -- ASan own interface functions. Those are only called // after __asan_init, thus an empty implementation is sufficient. #define INTERFACE_FUNCTION(name) \ extern "C" __declspec(noinline) void name() { \ volatile int prevent_icf = (__LINE__ << 8); (void)prevent_icf; \ __debugbreak(); \ } \ INTERCEPT_WHEN_POSSIBLE(#name, name) // INTERCEPT_HOOKS must be used after the last INTERCEPT_WHEN_POSSIBLE. #define INTERCEPT_HOOKS FunctionInterceptor<__LINE__>::Execute // 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 __asan_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_WHEN_POSSIBLE(WRAPPER_NAME(name), name) // Disable compiler warnings that show up if we declare our own version // of a compiler intrinsic (e.g. strlen). #pragma warning(disable: 4391) #pragma warning(disable: 4392) static void InterceptHooks(); // }}} // ---------- Function wrapping helpers ----------------------------------- {{{1 #define WRAP_V_V(name) \ extern "C" void name() { \ - typedef void (*fntype)(); \ + typedef decltype(name) *fntype; \ static fntype fn = (fntype)getRealProcAddressOrDie(#name); \ fn(); \ } \ INTERCEPT_WHEN_POSSIBLE(#name, name); #define WRAP_V_W(name) \ extern "C" void name(void *arg) { \ - typedef void (*fntype)(void *arg); \ + typedef decltype(name) *fntype; \ static fntype fn = (fntype)getRealProcAddressOrDie(#name); \ fn(arg); \ } \ INTERCEPT_WHEN_POSSIBLE(#name, name); #define WRAP_V_WW(name) \ extern "C" void name(void *arg1, void *arg2) { \ - typedef void (*fntype)(void *, void *); \ + typedef decltype(name) *fntype; \ static fntype fn = (fntype)getRealProcAddressOrDie(#name); \ fn(arg1, arg2); \ } \ INTERCEPT_WHEN_POSSIBLE(#name, name); #define WRAP_V_WWW(name) \ extern "C" void name(void *arg1, void *arg2, void *arg3) { \ - typedef void *(*fntype)(void *, void *, void *); \ + typedef decltype(name) *fntype; \ static fntype fn = (fntype)getRealProcAddressOrDie(#name); \ fn(arg1, arg2, arg3); \ } \ INTERCEPT_WHEN_POSSIBLE(#name, name); #define WRAP_W_V(name) \ extern "C" void *name() { \ - typedef void *(*fntype)(); \ + typedef decltype(name) *fntype; \ static fntype fn = (fntype)getRealProcAddressOrDie(#name); \ return fn(); \ } \ INTERCEPT_WHEN_POSSIBLE(#name, name); #define WRAP_W_W(name) \ extern "C" void *name(void *arg) { \ - typedef void *(*fntype)(void *arg); \ + typedef decltype(name) *fntype; \ static fntype fn = (fntype)getRealProcAddressOrDie(#name); \ return fn(arg); \ } \ INTERCEPT_WHEN_POSSIBLE(#name, name); #define WRAP_W_WW(name) \ extern "C" void *name(void *arg1, void *arg2) { \ - typedef void *(*fntype)(void *, void *); \ + typedef decltype(name) *fntype; \ static fntype fn = (fntype)getRealProcAddressOrDie(#name); \ return fn(arg1, arg2); \ } \ INTERCEPT_WHEN_POSSIBLE(#name, name); #define WRAP_W_WWW(name) \ extern "C" void *name(void *arg1, void *arg2, void *arg3) { \ - typedef void *(*fntype)(void *, void *, void *); \ + typedef decltype(name) *fntype; \ static fntype fn = (fntype)getRealProcAddressOrDie(#name); \ return fn(arg1, arg2, arg3); \ } \ INTERCEPT_WHEN_POSSIBLE(#name, name); #define WRAP_W_WWWW(name) \ extern "C" void *name(void *arg1, void *arg2, void *arg3, void *arg4) { \ - typedef void *(*fntype)(void *, void *, void *, void *); \ + typedef decltype(name) *fntype; \ static fntype fn = (fntype)getRealProcAddressOrDie(#name); \ return fn(arg1, arg2, arg3, arg4); \ } \ INTERCEPT_WHEN_POSSIBLE(#name, name); #define WRAP_W_WWWWW(name) \ extern "C" void *name(void *arg1, void *arg2, void *arg3, void *arg4, \ void *arg5) { \ - typedef void *(*fntype)(void *, void *, void *, void *, void *); \ + typedef decltype(name) *fntype; \ static fntype fn = (fntype)getRealProcAddressOrDie(#name); \ return fn(arg1, arg2, arg3, arg4, arg5); \ } \ INTERCEPT_WHEN_POSSIBLE(#name, name); #define WRAP_W_WWWWWW(name) \ extern "C" void *name(void *arg1, void *arg2, void *arg3, void *arg4, \ void *arg5, void *arg6) { \ - typedef void *(*fntype)(void *, void *, void *, void *, void *, void *); \ + typedef decltype(name) *fntype; \ static fntype fn = (fntype)getRealProcAddressOrDie(#name); \ return fn(arg1, arg2, arg3, arg4, arg5, arg6); \ } \ INTERCEPT_WHEN_POSSIBLE(#name, name); // }}} // ----------------- ASan own interface functions -------------------- // Don't use the INTERFACE_FUNCTION machinery for this function as we actually // want to call it in the __asan_init interceptor. WRAP_W_V(__asan_should_detect_stack_use_after_return) +WRAP_W_V(__asan_get_shadow_memory_dynamic_address) extern "C" { int __asan_option_detect_stack_use_after_return; + uptr __asan_shadow_memory_dynamic_address; // Manually wrap __asan_init as we need to initialize // __asan_option_detect_stack_use_after_return afterwards. void __asan_init() { typedef void (*fntype)(); static fntype fn = 0; // __asan_init is expected to be called by only one thread. if (fn) return; fn = (fntype)getRealProcAddressOrDie("__asan_init"); fn(); __asan_option_detect_stack_use_after_return = (__asan_should_detect_stack_use_after_return() != 0); - + __asan_shadow_memory_dynamic_address = + (uptr)__asan_get_shadow_memory_dynamic_address(); InterceptHooks(); } } extern "C" void __asan_version_mismatch_check() { // Do nothing. } INTERFACE_FUNCTION(__asan_handle_no_return) +INTERFACE_FUNCTION(__asan_unhandled_exception_filter) INTERFACE_FUNCTION(__asan_report_store1) INTERFACE_FUNCTION(__asan_report_store2) INTERFACE_FUNCTION(__asan_report_store4) INTERFACE_FUNCTION(__asan_report_store8) INTERFACE_FUNCTION(__asan_report_store16) INTERFACE_FUNCTION(__asan_report_store_n) INTERFACE_FUNCTION(__asan_report_load1) INTERFACE_FUNCTION(__asan_report_load2) INTERFACE_FUNCTION(__asan_report_load4) INTERFACE_FUNCTION(__asan_report_load8) INTERFACE_FUNCTION(__asan_report_load16) INTERFACE_FUNCTION(__asan_report_load_n) INTERFACE_FUNCTION(__asan_store1) INTERFACE_FUNCTION(__asan_store2) INTERFACE_FUNCTION(__asan_store4) INTERFACE_FUNCTION(__asan_store8) INTERFACE_FUNCTION(__asan_store16) INTERFACE_FUNCTION(__asan_storeN) INTERFACE_FUNCTION(__asan_load1) INTERFACE_FUNCTION(__asan_load2) INTERFACE_FUNCTION(__asan_load4) INTERFACE_FUNCTION(__asan_load8) INTERFACE_FUNCTION(__asan_load16) INTERFACE_FUNCTION(__asan_loadN) INTERFACE_FUNCTION(__asan_memcpy); INTERFACE_FUNCTION(__asan_memset); INTERFACE_FUNCTION(__asan_memmove); +INTERFACE_FUNCTION(__asan_set_shadow_00); +INTERFACE_FUNCTION(__asan_set_shadow_f1); +INTERFACE_FUNCTION(__asan_set_shadow_f2); +INTERFACE_FUNCTION(__asan_set_shadow_f3); +INTERFACE_FUNCTION(__asan_set_shadow_f5); +INTERFACE_FUNCTION(__asan_set_shadow_f8); + INTERFACE_FUNCTION(__asan_alloca_poison); INTERFACE_FUNCTION(__asan_allocas_unpoison); INTERFACE_FUNCTION(__asan_register_globals) INTERFACE_FUNCTION(__asan_unregister_globals) INTERFACE_FUNCTION(__asan_before_dynamic_init) INTERFACE_FUNCTION(__asan_after_dynamic_init) INTERFACE_FUNCTION(__asan_poison_stack_memory) INTERFACE_FUNCTION(__asan_unpoison_stack_memory) INTERFACE_FUNCTION(__asan_poison_memory_region) INTERFACE_FUNCTION(__asan_unpoison_memory_region) INTERFACE_FUNCTION(__asan_address_is_poisoned) INTERFACE_FUNCTION(__asan_region_is_poisoned) INTERFACE_FUNCTION(__asan_get_current_fake_stack) INTERFACE_FUNCTION(__asan_addr_is_in_fake_stack) INTERFACE_FUNCTION(__asan_stack_malloc_0) INTERFACE_FUNCTION(__asan_stack_malloc_1) INTERFACE_FUNCTION(__asan_stack_malloc_2) INTERFACE_FUNCTION(__asan_stack_malloc_3) INTERFACE_FUNCTION(__asan_stack_malloc_4) INTERFACE_FUNCTION(__asan_stack_malloc_5) INTERFACE_FUNCTION(__asan_stack_malloc_6) INTERFACE_FUNCTION(__asan_stack_malloc_7) INTERFACE_FUNCTION(__asan_stack_malloc_8) INTERFACE_FUNCTION(__asan_stack_malloc_9) INTERFACE_FUNCTION(__asan_stack_malloc_10) INTERFACE_FUNCTION(__asan_stack_free_0) INTERFACE_FUNCTION(__asan_stack_free_1) INTERFACE_FUNCTION(__asan_stack_free_2) INTERFACE_FUNCTION(__asan_stack_free_4) INTERFACE_FUNCTION(__asan_stack_free_5) INTERFACE_FUNCTION(__asan_stack_free_6) INTERFACE_FUNCTION(__asan_stack_free_7) INTERFACE_FUNCTION(__asan_stack_free_8) INTERFACE_FUNCTION(__asan_stack_free_9) INTERFACE_FUNCTION(__asan_stack_free_10) // FIXME: we might want to have a sanitizer_win_dll_thunk? INTERFACE_FUNCTION(__sanitizer_annotate_contiguous_container) INTERFACE_FUNCTION(__sanitizer_contiguous_container_find_bad_address) INTERFACE_FUNCTION(__sanitizer_cov) INTERFACE_FUNCTION(__sanitizer_cov_dump) +INTERFACE_FUNCTION(__sanitizer_dump_coverage) +INTERFACE_FUNCTION(__sanitizer_dump_trace_pc_guard_coverage) INTERFACE_FUNCTION(__sanitizer_cov_indir_call16) INTERFACE_FUNCTION(__sanitizer_cov_init) INTERFACE_FUNCTION(__sanitizer_cov_module_init) INTERFACE_FUNCTION(__sanitizer_cov_trace_basic_block) INTERFACE_FUNCTION(__sanitizer_cov_trace_func_enter) -INTERFACE_FUNCTION(__sanitizer_cov_trace_cmp) -INTERFACE_FUNCTION(__sanitizer_cov_trace_switch) +INTERFACE_FUNCTION(__sanitizer_cov_trace_pc_guard) +INTERFACE_FUNCTION(__sanitizer_cov_trace_pc_guard_init) INTERFACE_FUNCTION(__sanitizer_cov_with_check) INTERFACE_FUNCTION(__sanitizer_get_allocated_size) INTERFACE_FUNCTION(__sanitizer_get_coverage_guards) -INTERFACE_FUNCTION(__sanitizer_get_coverage_pc_buffer) 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_total_unique_caller_callee_pairs) INTERFACE_FUNCTION(__sanitizer_get_total_unique_coverage) INTERFACE_FUNCTION(__sanitizer_get_unmapped_bytes) INTERFACE_FUNCTION(__sanitizer_maybe_open_cov_file) INTERFACE_FUNCTION(__sanitizer_print_stack_trace) +INTERFACE_FUNCTION(__sanitizer_symbolize_pc) +INTERFACE_FUNCTION(__sanitizer_symbolize_global) INTERFACE_FUNCTION(__sanitizer_ptr_cmp) INTERFACE_FUNCTION(__sanitizer_ptr_sub) INTERFACE_FUNCTION(__sanitizer_report_error_summary) INTERFACE_FUNCTION(__sanitizer_reset_coverage) INTERFACE_FUNCTION(__sanitizer_get_number_of_counters) INTERFACE_FUNCTION(__sanitizer_update_counter_bitset_and_clear_counters) INTERFACE_FUNCTION(__sanitizer_sandbox_on_notify) INTERFACE_FUNCTION(__sanitizer_set_death_callback) INTERFACE_FUNCTION(__sanitizer_set_report_path) INTERFACE_FUNCTION(__sanitizer_set_report_fd) INTERFACE_FUNCTION(__sanitizer_unaligned_load16) INTERFACE_FUNCTION(__sanitizer_unaligned_load32) INTERFACE_FUNCTION(__sanitizer_unaligned_load64) INTERFACE_FUNCTION(__sanitizer_unaligned_store16) INTERFACE_FUNCTION(__sanitizer_unaligned_store32) INTERFACE_FUNCTION(__sanitizer_unaligned_store64) INTERFACE_FUNCTION(__sanitizer_verify_contiguous_container) INTERFACE_FUNCTION(__sanitizer_install_malloc_and_free_hooks) INTERFACE_FUNCTION(__sanitizer_start_switch_fiber) INTERFACE_FUNCTION(__sanitizer_finish_switch_fiber) +INTERFACE_FUNCTION(__sanitizer_get_module_and_offset_for_pc) // TODO(timurrrr): Add more interface functions on the as-needed basis. // ----------------- Memory allocation functions --------------------- WRAP_V_W(free) WRAP_V_W(_free_base) WRAP_V_WW(_free_dbg) WRAP_W_W(malloc) WRAP_W_W(_malloc_base) WRAP_W_WWWW(_malloc_dbg) WRAP_W_WW(calloc) WRAP_W_WW(_calloc_base) WRAP_W_WWWWW(_calloc_dbg) WRAP_W_WWW(_calloc_impl) WRAP_W_WW(realloc) WRAP_W_WW(_realloc_base) WRAP_W_WWW(_realloc_dbg) WRAP_W_WWW(_recalloc) +WRAP_W_WWW(_recalloc_base) WRAP_W_W(_msize) WRAP_W_W(_expand) WRAP_W_W(_expand_dbg) // TODO(timurrrr): Might want to add support for _aligned_* allocation // functions to detect a bit more bugs. Those functions seem to wrap malloc(). // TODO(timurrrr): Do we need to add _Crt* stuff here? (see asan_malloc_win.cc). INTERCEPT_LIBRARY_FUNCTION(atoi); INTERCEPT_LIBRARY_FUNCTION(atol); #ifdef _WIN64 INTERCEPT_LIBRARY_FUNCTION(__C_specific_handler); #else INTERCEPT_LIBRARY_FUNCTION(_except_handler3); // _except_handler4 checks -GS cookie which is different for each module, so we // can't use INTERCEPT_LIBRARY_FUNCTION(_except_handler4). INTERCEPTOR(int, _except_handler4, void *a, void *b, void *c, void *d) { __asan_handle_no_return(); return REAL(_except_handler4)(a, b, c, d); } #endif INTERCEPT_LIBRARY_FUNCTION(frexp); INTERCEPT_LIBRARY_FUNCTION(longjmp); #if SANITIZER_INTERCEPT_MEMCHR INTERCEPT_LIBRARY_FUNCTION(memchr); #endif INTERCEPT_LIBRARY_FUNCTION(memcmp); INTERCEPT_LIBRARY_FUNCTION(memcpy); INTERCEPT_LIBRARY_FUNCTION(memmove); INTERCEPT_LIBRARY_FUNCTION(memset); INTERCEPT_LIBRARY_FUNCTION(strcat); // NOLINT INTERCEPT_LIBRARY_FUNCTION(strchr); INTERCEPT_LIBRARY_FUNCTION(strcmp); INTERCEPT_LIBRARY_FUNCTION(strcpy); // NOLINT INTERCEPT_LIBRARY_FUNCTION(strcspn); INTERCEPT_LIBRARY_FUNCTION(strdup); INTERCEPT_LIBRARY_FUNCTION(strlen); INTERCEPT_LIBRARY_FUNCTION(strncat); INTERCEPT_LIBRARY_FUNCTION(strncmp); INTERCEPT_LIBRARY_FUNCTION(strncpy); INTERCEPT_LIBRARY_FUNCTION(strnlen); INTERCEPT_LIBRARY_FUNCTION(strpbrk); INTERCEPT_LIBRARY_FUNCTION(strrchr); INTERCEPT_LIBRARY_FUNCTION(strspn); INTERCEPT_LIBRARY_FUNCTION(strstr); INTERCEPT_LIBRARY_FUNCTION(strtol); INTERCEPT_LIBRARY_FUNCTION(wcslen); // Must be after all the interceptor declarations due to the way INTERCEPT_HOOKS // is defined. void InterceptHooks() { INTERCEPT_HOOKS(); #ifndef _WIN64 INTERCEPT_FUNCTION(_except_handler4); #endif } // We want to call __asan_init before C/C++ initializers/constructors are // executed, otherwise functions like memset might be invoked. // For some strange reason, merely linking in asan_preinit.cc doesn't work // as the callback is never called... Is link.exe doing something too smart? // In DLLs, the callbacks are expected to return 0, // otherwise CRT initialization fails. static int call_asan_init() { __asan_init(); return 0; } #pragma section(".CRT$XIB", long, read) // NOLINT __declspec(allocate(".CRT$XIB")) int (*__asan_preinit)() = call_asan_init; + +static void WINAPI asan_thread_init(void *mod, unsigned long reason, + void *reserved) { + if (reason == /*DLL_PROCESS_ATTACH=*/1) __asan_init(); +} + +#pragma section(".CRT$XLAB", long, read) // NOLINT +__declspec(allocate(".CRT$XLAB")) void (WINAPI *__asan_tls_init)(void *, + unsigned long, void *) = asan_thread_init; + +ASAN_LINK_GLOBALS_WIN() #endif // ASAN_DLL_THUNK Index: projects/clang400-import/contrib/compiler-rt/lib/asan/asan_win_dynamic_runtime_thunk.cc =================================================================== --- projects/clang400-import/contrib/compiler-rt/lib/asan/asan_win_dynamic_runtime_thunk.cc (revision 311696) +++ projects/clang400-import/contrib/compiler-rt/lib/asan/asan_win_dynamic_runtime_thunk.cc (revision 311697) @@ -1,100 +1,127 @@ -//===-- asan_win_uar_thunk.cc ---------------------------------------------===// +//===-- asan_win_dynamic_runtime_thunk.cc ---------------------------------===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // This file is a part of AddressSanitizer, an address sanity checker. // // This file defines things that need to be present in the application modules // to interact with the ASan DLL runtime correctly and can't be implemented // using the default "import library" generated when linking the DLL RTL. // // This includes: // - forwarding the detect_stack_use_after_return runtime option // - working around deficiencies of the MD runtime -// - installing a custom SEH handlerx +// - installing a custom SEH handler // //===----------------------------------------------------------------------===// -// Only compile this code when buidling asan_dynamic_runtime_thunk.lib +// Only compile this code when building asan_dynamic_runtime_thunk.lib // Using #ifdef rather than relying on Makefiles etc. // simplifies the build procedure. #ifdef ASAN_DYNAMIC_RUNTIME_THUNK +#include "asan_globals_win.h" #define WIN32_LEAN_AND_MEAN #include // First, declare CRT sections we'll be using in this file +#pragma section(".CRT$XIB", long, read) // NOLINT #pragma section(".CRT$XID", long, read) // NOLINT #pragma section(".CRT$XCAB", long, read) // NOLINT #pragma section(".CRT$XTW", long, read) // NOLINT #pragma section(".CRT$XTY", long, read) // NOLINT +#pragma section(".CRT$XLAB", long, read) // NOLINT //////////////////////////////////////////////////////////////////////////////// // Define a copy of __asan_option_detect_stack_use_after_return that should be // used when linking an MD runtime with a set of object files on Windows. // // The ASan MD runtime dllexports '__asan_option_detect_stack_use_after_return', // so normally we would just dllimport it. Unfortunately, the dllimport // attribute adds __imp_ prefix to the symbol name of a variable. // Since in general we don't know if a given TU is going to be used // with a MT or MD runtime and we don't want to use ugly __imp_ names on Windows -// just to work around this issue, let's clone the a variable that is -// constant after initialization anyways. +// just to work around this issue, let's clone the variable that is constant +// after initialization anyways. extern "C" { __declspec(dllimport) int __asan_should_detect_stack_use_after_return(); -int __asan_option_detect_stack_use_after_return = +int __asan_option_detect_stack_use_after_return; + +__declspec(dllimport) void* __asan_get_shadow_memory_dynamic_address(); +void* __asan_shadow_memory_dynamic_address; +} + +static int InitializeClonedVariables() { + __asan_option_detect_stack_use_after_return = __asan_should_detect_stack_use_after_return(); + __asan_shadow_memory_dynamic_address = + __asan_get_shadow_memory_dynamic_address(); + return 0; } +static void NTAPI asan_thread_init(void *mod, unsigned long reason, + void *reserved) { + if (reason == DLL_PROCESS_ATTACH) InitializeClonedVariables(); +} + +// Our cloned variables must be initialized before C/C++ constructors. If TLS +// is used, our .CRT$XLAB initializer will run first. If not, our .CRT$XIB +// initializer is needed as a backup. +__declspec(allocate(".CRT$XIB")) int (*__asan_initialize_cloned_variables)() = + InitializeClonedVariables; +__declspec(allocate(".CRT$XLAB")) void (NTAPI *__asan_tls_init)(void *, + unsigned long, void *) = asan_thread_init; + //////////////////////////////////////////////////////////////////////////////// // For some reason, the MD CRT doesn't call the C/C++ terminators during on DLL // unload or on exit. ASan relies on LLVM global_dtors to call // __asan_unregister_globals on these events, which unfortunately doesn't work // with the MD runtime, see PR22545 for the details. // To work around this, for each DLL we schedule a call to UnregisterGlobals // using atexit() that calls a small subset of C terminators // where LLVM global_dtors is placed. Fingers crossed, no other C terminators // are there. extern "C" int __cdecl atexit(void (__cdecl *f)(void)); extern "C" void __cdecl _initterm(void *a, void *b); namespace { __declspec(allocate(".CRT$XTW")) void* before_global_dtors = 0; __declspec(allocate(".CRT$XTY")) void* after_global_dtors = 0; void UnregisterGlobals() { _initterm(&before_global_dtors, &after_global_dtors); } int ScheduleUnregisterGlobals() { return atexit(UnregisterGlobals); } +} // namespace // We need to call 'atexit(UnregisterGlobals);' as early as possible, but after // atexit() is initialized (.CRT$XIC). As this is executed before C++ // initializers (think ctors for globals), UnregisterGlobals gets executed after // dtors for C++ globals. __declspec(allocate(".CRT$XID")) int (*__asan_schedule_unregister_globals)() = ScheduleUnregisterGlobals; -} // namespace - //////////////////////////////////////////////////////////////////////////////// // ASan SEH handling. // We need to set the ASan-specific SEH handler at the end of CRT initialization // of each module (see also asan_win.cc). extern "C" { __declspec(dllimport) int __asan_set_seh_filter(); static int SetSEHFilter() { return __asan_set_seh_filter(); } // Unfortunately, putting a pointer to __asan_set_seh_filter into // __asan_intercept_seh gets optimized out, so we have to use an extra function. __declspec(allocate(".CRT$XCAB")) int (*__asan_seh_interceptor)() = SetSEHFilter; } + +ASAN_LINK_GLOBALS_WIN() #endif // ASAN_DYNAMIC_RUNTIME_THUNK Index: projects/clang400-import/contrib/compiler-rt/lib/builtins/arm/aeabi_idivmod.S =================================================================== --- projects/clang400-import/contrib/compiler-rt/lib/builtins/arm/aeabi_idivmod.S (revision 311696) +++ projects/clang400-import/contrib/compiler-rt/lib/builtins/arm/aeabi_idivmod.S (revision 311697) @@ -1,31 +1,49 @@ //===-- aeabi_idivmod.S - EABI idivmod implementation ---------------------===// // // The LLVM Compiler Infrastructure // // This file is dual licensed under the MIT and the University of Illinois Open // Source Licenses. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #include "../assembly.h" // struct { int quot, int rem} __aeabi_idivmod(int numerator, int denominator) { // int rem, quot; // quot = __divmodsi4(numerator, denominator, &rem); // return {quot, rem}; // } +#if defined(__MINGW32__) +#define __aeabi_idivmod __rt_sdiv +#endif + .syntax unified .p2align 2 DEFINE_COMPILERRT_FUNCTION(__aeabi_idivmod) +#if __ARM_ARCH_ISA_THUMB == 1 + push {r0, r1, lr} + bl SYMBOL_NAME(__divsi3) + pop {r1, r2, r3} // now r0 = quot, r1 = num, r2 = denom + muls r2, r2, r0 // r2 = quot * denom + subs r1, r1, r2 + JMP (r3) +#else push { lr } sub sp, sp, #4 mov r2, sp +#if defined(__MINGW32__) + mov r3, r0 + mov r0, r1 + mov r1, r3 +#endif bl SYMBOL_NAME(__divmodsi4) ldr r1, [sp] add sp, sp, #4 pop { pc } +#endif // __ARM_ARCH_ISA_THUMB == 1 END_COMPILERRT_FUNCTION(__aeabi_idivmod) NO_EXEC_STACK_DIRECTIVE Index: projects/clang400-import/contrib/compiler-rt/lib/builtins/arm/aeabi_ldivmod.S =================================================================== --- projects/clang400-import/contrib/compiler-rt/lib/builtins/arm/aeabi_ldivmod.S (revision 311696) +++ projects/clang400-import/contrib/compiler-rt/lib/builtins/arm/aeabi_ldivmod.S (revision 311697) @@ -1,34 +1,46 @@ //===-- aeabi_ldivmod.S - EABI ldivmod implementation ---------------------===// // // The LLVM Compiler Infrastructure // // This file is dual licensed under the MIT and the University of Illinois Open // Source Licenses. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #include "../assembly.h" // struct { int64_t quot, int64_t rem} // __aeabi_ldivmod(int64_t numerator, int64_t denominator) { // int64_t rem, quot; // quot = __divmoddi4(numerator, denominator, &rem); // return {quot, rem}; // } +#if defined(__MINGW32__) +#define __aeabi_ldivmod __rt_sdiv64 +#endif + .syntax unified .p2align 2 DEFINE_COMPILERRT_FUNCTION(__aeabi_ldivmod) push {r11, lr} sub sp, sp, #16 add r12, sp, #8 str r12, [sp] +#if defined(__MINGW32__) + mov r12, r0 + mov r0, r2 + mov r2, r12 + mov r12, r1 + mov r1, r3 + mov r3, r12 +#endif bl SYMBOL_NAME(__divmoddi4) ldr r2, [sp, #8] ldr r3, [sp, #12] add sp, sp, #16 pop {r11, pc} END_COMPILERRT_FUNCTION(__aeabi_ldivmod) NO_EXEC_STACK_DIRECTIVE Index: projects/clang400-import/contrib/compiler-rt/lib/builtins/arm/aeabi_uidivmod.S =================================================================== --- projects/clang400-import/contrib/compiler-rt/lib/builtins/arm/aeabi_uidivmod.S (revision 311696) +++ projects/clang400-import/contrib/compiler-rt/lib/builtins/arm/aeabi_uidivmod.S (revision 311697) @@ -1,32 +1,56 @@ //===-- aeabi_uidivmod.S - EABI uidivmod implementation -------------------===// // // The LLVM Compiler Infrastructure // // This file is dual licensed under the MIT and the University of Illinois Open // Source Licenses. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #include "../assembly.h" // struct { unsigned quot, unsigned rem} // __aeabi_uidivmod(unsigned numerator, unsigned denominator) { // unsigned rem, quot; // quot = __udivmodsi4(numerator, denominator, &rem); // return {quot, rem}; // } +#if defined(__MINGW32__) +#define __aeabi_uidivmod __rt_udiv +#endif + .syntax unified .p2align 2 DEFINE_COMPILERRT_FUNCTION(__aeabi_uidivmod) +#if __ARM_ARCH_ISA_THUMB == 1 + cmp r0, r1 + bcc LOCAL_LABEL(case_denom_larger) + push {r0, r1, lr} + bl SYMBOL_NAME(__aeabi_uidiv) + pop {r1, r2, r3} + muls r2, r2, r0 // r2 = quot * denom + subs r1, r1, r2 + JMP (r3) +LOCAL_LABEL(case_denom_larger): + movs r1, r0 + movs r0, #0 + JMP (lr) +#else push { lr } sub sp, sp, #4 mov r2, sp +#if defined(__MINGW32__) + mov r3, r0 + mov r0, r1 + mov r1, r3 +#endif bl SYMBOL_NAME(__udivmodsi4) ldr r1, [sp] add sp, sp, #4 pop { pc } +#endif END_COMPILERRT_FUNCTION(__aeabi_uidivmod) NO_EXEC_STACK_DIRECTIVE Index: projects/clang400-import/contrib/compiler-rt/lib/builtins/arm/aeabi_uldivmod.S =================================================================== --- projects/clang400-import/contrib/compiler-rt/lib/builtins/arm/aeabi_uldivmod.S (revision 311696) +++ projects/clang400-import/contrib/compiler-rt/lib/builtins/arm/aeabi_uldivmod.S (revision 311697) @@ -1,34 +1,46 @@ //===-- aeabi_uldivmod.S - EABI uldivmod implementation -------------------===// // // The LLVM Compiler Infrastructure // // This file is dual licensed under the MIT and the University of Illinois Open // Source Licenses. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #include "../assembly.h" // struct { uint64_t quot, uint64_t rem} // __aeabi_uldivmod(uint64_t numerator, uint64_t denominator) { // uint64_t rem, quot; // quot = __udivmoddi4(numerator, denominator, &rem); // return {quot, rem}; // } +#if defined(__MINGW32__) +#define __aeabi_uldivmod __rt_udiv64 +#endif + .syntax unified .p2align 2 DEFINE_COMPILERRT_FUNCTION(__aeabi_uldivmod) push {r11, lr} sub sp, sp, #16 add r12, sp, #8 str r12, [sp] +#if defined(__MINGW32__) + mov r12, r0 + mov r0, r2 + mov r2, r12 + mov r12, r1 + mov r1, r3 + mov r3, r12 +#endif bl SYMBOL_NAME(__udivmoddi4) ldr r2, [sp, #8] ldr r3, [sp, #12] add sp, sp, #16 pop {r11, pc} END_COMPILERRT_FUNCTION(__aeabi_uldivmod) NO_EXEC_STACK_DIRECTIVE Index: projects/clang400-import/contrib/compiler-rt/lib/builtins/arm/comparesf2.S =================================================================== --- projects/clang400-import/contrib/compiler-rt/lib/builtins/arm/comparesf2.S (revision 311696) +++ projects/clang400-import/contrib/compiler-rt/lib/builtins/arm/comparesf2.S (revision 311697) @@ -1,151 +1,154 @@ //===-- comparesf2.S - Implement single-precision soft-float comparisons --===// // // The LLVM Compiler Infrastructure // // This file is dual licensed under the MIT and the University of Illinois Open // Source Licenses. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // This file implements the following soft-fp_t comparison routines: // // __eqsf2 __gesf2 __unordsf2 // __lesf2 __gtsf2 // __ltsf2 // __nesf2 // // The semantics of the routines grouped in each column are identical, so there // is a single implementation for each, with multiple names. // // The routines behave as follows: // // __lesf2(a,b) returns -1 if a < b // 0 if a == b // 1 if a > b // 1 if either a or b is NaN // // __gesf2(a,b) returns -1 if a < b // 0 if a == b // 1 if a > b // -1 if either a or b is NaN // // __unordsf2(a,b) returns 0 if both a and b are numbers // 1 if either a or b is NaN // // Note that __lesf2( ) and __gesf2( ) are identical except in their handling of // NaN values. // //===----------------------------------------------------------------------===// #include "../assembly.h" .syntax unified +#if __ARM_ARCH_ISA_THUMB == 2 +.thumb +#endif .p2align 2 DEFINE_COMPILERRT_FUNCTION(__eqsf2) // Make copies of a and b with the sign bit shifted off the top. These will // be used to detect zeros and NaNs. mov r2, r0, lsl #1 mov r3, r1, lsl #1 // We do the comparison in three stages (ignoring NaN values for the time // being). First, we orr the absolute values of a and b; this sets the Z // flag if both a and b are zero (of either sign). The shift of r3 doesn't // effect this at all, but it *does* make sure that the C flag is clear for // the subsequent operations. orrs r12, r2, r3, lsr #1 // Next, we check if a and b have the same or different signs. If they have // opposite signs, this eor will set the N flag. it ne eorsne r12, r0, r1 // If a and b are equal (either both zeros or bit identical; again, we're // ignoring NaNs for now), this subtract will zero out r0. If they have the // same sign, the flags are updated as they would be for a comparison of the // absolute values of a and b. it pl subspl r0, r2, r3 // If a is smaller in magnitude than b and both have the same sign, place // the negation of the sign of b in r0. Thus, if both are negative and // a > b, this sets r0 to 0; if both are positive and a < b, this sets // r0 to -1. // // This is also done if a and b have opposite signs and are not both zero, // because in that case the subtract was not performed and the C flag is // still clear from the shift argument in orrs; if a is positive and b // negative, this places 0 in r0; if a is negative and b positive, -1 is // placed in r0. it lo mvnlo r0, r1, asr #31 // If a is greater in magnitude than b and both have the same sign, place // the sign of b in r0. Thus, if both are negative and a < b, -1 is placed // in r0, which is the desired result. Conversely, if both are positive // and a > b, zero is placed in r0. it hi movhi r0, r1, asr #31 // If you've been keeping track, at this point r0 contains -1 if a < b and // 0 if a >= b. All that remains to be done is to set it to 1 if a > b. // If a == b, then the Z flag is set, so we can get the correct final value // into r0 by simply or'ing with 1 if Z is clear. it ne orrne r0, r0, #1 // Finally, we need to deal with NaNs. If either argument is NaN, replace // the value in r0 with 1. cmp r2, #0xff000000 ite ls cmpls r3, #0xff000000 movhi r0, #1 JMP(lr) END_COMPILERRT_FUNCTION(__eqsf2) DEFINE_COMPILERRT_FUNCTION_ALIAS(__lesf2, __eqsf2) DEFINE_COMPILERRT_FUNCTION_ALIAS(__ltsf2, __eqsf2) DEFINE_COMPILERRT_FUNCTION_ALIAS(__nesf2, __eqsf2) .p2align 2 DEFINE_COMPILERRT_FUNCTION(__gtsf2) // Identical to the preceding except in that we return -1 for NaN values. // Given that the two paths share so much code, one might be tempted to // unify them; however, the extra code needed to do so makes the code size // to performance tradeoff very hard to justify for such small functions. mov r2, r0, lsl #1 mov r3, r1, lsl #1 orrs r12, r2, r3, lsr #1 it ne eorsne r12, r0, r1 it pl subspl r0, r2, r3 it lo mvnlo r0, r1, asr #31 it hi movhi r0, r1, asr #31 it ne orrne r0, r0, #1 cmp r2, #0xff000000 ite ls cmpls r3, #0xff000000 movhi r0, #-1 JMP(lr) END_COMPILERRT_FUNCTION(__gtsf2) DEFINE_COMPILERRT_FUNCTION_ALIAS(__gesf2, __gtsf2) .p2align 2 DEFINE_COMPILERRT_FUNCTION(__unordsf2) // Return 1 for NaN values, 0 otherwise. mov r2, r0, lsl #1 mov r3, r1, lsl #1 mov r0, #0 cmp r2, #0xff000000 ite ls cmpls r3, #0xff000000 movhi r0, #1 JMP(lr) END_COMPILERRT_FUNCTION(__unordsf2) DEFINE_AEABI_FUNCTION_ALIAS(__aeabi_fcmpun, __unordsf2) NO_EXEC_STACK_DIRECTIVE Index: projects/clang400-import/contrib/compiler-rt/lib/builtins/arm/divsi3.S =================================================================== --- projects/clang400-import/contrib/compiler-rt/lib/builtins/arm/divsi3.S (revision 311696) +++ projects/clang400-import/contrib/compiler-rt/lib/builtins/arm/divsi3.S (revision 311697) @@ -1,68 +1,88 @@ /*===-- divsi3.S - 32-bit signed integer divide ---------------------------===// * * The LLVM Compiler Infrastructure * * This file is dual licensed under the MIT and the University of Illinois Open * Source Licenses. See LICENSE.TXT for details. * *===----------------------------------------------------------------------===// * * This file implements the __divsi3 (32-bit signed integer divide) function * for the ARM architecture as a wrapper around the unsigned routine. * *===----------------------------------------------------------------------===*/ #include "../assembly.h" #define ESTABLISH_FRAME \ push {r4, r7, lr} ;\ add r7, sp, #4 #define CLEAR_FRAME_AND_RETURN \ pop {r4, r7, pc} .syntax unified .text #if __ARM_ARCH_ISA_THUMB == 2 .thumb #endif .p2align 3 // Ok, APCS and AAPCS agree on 32 bit args, so it's safe to use the same routine. DEFINE_AEABI_FUNCTION_ALIAS(__aeabi_idiv, __divsi3) @ int __divsi3(int divident, int divisor) @ Calculate and return the quotient of the (signed) division. #if __ARM_ARCH_ISA_THUMB == 2 DEFINE_COMPILERRT_THUMB_FUNCTION(__divsi3) #else DEFINE_COMPILERRT_FUNCTION(__divsi3) #endif #if __ARM_ARCH_EXT_IDIV__ tst r1,r1 beq LOCAL_LABEL(divzero) sdiv r0, r0, r1 bx lr LOCAL_LABEL(divzero): mov r0,#0 bx lr #else ESTABLISH_FRAME // Set aside the sign of the quotient. +# if __ARM_ARCH_ISA_THUMB == 1 + movs r4, r0 + eors r4, r1 +# else eor r4, r0, r1 +# endif // Take absolute value of a and b via abs(x) = (x^(x >> 31)) - (x >> 31). +# if __ARM_ARCH_ISA_THUMB == 1 + asrs r2, r0, #31 + asrs r3, r1, #31 + eors r0, r2 + eors r1, r3 + subs r0, r0, r2 + subs r1, r1, r3 +# else eor r2, r0, r0, asr #31 eor r3, r1, r1, asr #31 sub r0, r2, r0, asr #31 sub r1, r3, r1, asr #31 +# endif // abs(a) / abs(b) bl SYMBOL_NAME(__udivsi3) // Apply sign of quotient to result and return. +# if __ARM_ARCH_ISA_THUMB == 1 + asrs r4, #31 + eors r0, r4 + subs r0, r0, r4 +# else eor r0, r0, r4, asr #31 sub r0, r0, r4, asr #31 +# endif CLEAR_FRAME_AND_RETURN #endif END_COMPILERRT_FUNCTION(__divsi3) NO_EXEC_STACK_DIRECTIVE Index: projects/clang400-import/contrib/compiler-rt/lib/builtins/arm/udivsi3.S =================================================================== --- projects/clang400-import/contrib/compiler-rt/lib/builtins/arm/udivsi3.S (revision 311696) +++ projects/clang400-import/contrib/compiler-rt/lib/builtins/arm/udivsi3.S (revision 311697) @@ -1,173 +1,268 @@ /*===-- udivsi3.S - 32-bit unsigned integer divide ------------------------===// * * The LLVM Compiler Infrastructure * * This file is dual licensed under the MIT and the University of Illinois Open * Source Licenses. See LICENSE.TXT for details. * *===----------------------------------------------------------------------===// * * This file implements the __udivsi3 (32-bit unsigned integer divide) * function for the ARM 32-bit architecture. * *===----------------------------------------------------------------------===*/ #include "../assembly.h" .syntax unified .text #if __ARM_ARCH_ISA_THUMB == 2 .thumb #endif .p2align 2 DEFINE_AEABI_FUNCTION_ALIAS(__aeabi_uidiv, __udivsi3) @ unsigned int __udivsi3(unsigned int divident, unsigned int divisor) @ Calculate and return the quotient of the (unsigned) division. #if __ARM_ARCH_ISA_THUMB == 2 DEFINE_COMPILERRT_THUMB_FUNCTION(__udivsi3) #else DEFINE_COMPILERRT_FUNCTION(__udivsi3) #endif #if __ARM_ARCH_EXT_IDIV__ tst r1, r1 beq LOCAL_LABEL(divby0) udiv r0, r0, r1 bx lr #else cmp r1, #1 bcc LOCAL_LABEL(divby0) +#if __ARM_ARCH_ISA_THUMB == 1 + bne LOCAL_LABEL(num_neq_denom) + JMP(lr) +LOCAL_LABEL(num_neq_denom): +#else IT(eq) JMPc(lr, eq) +#endif cmp r0, r1 +#if __ARM_ARCH_ISA_THUMB == 1 + bhs LOCAL_LABEL(num_ge_denom) + movs r0, #0 + JMP(lr) +LOCAL_LABEL(num_ge_denom): +#else ITT(cc) movcc r0, #0 JMPc(lr, cc) +#endif + /* * Implement division using binary long division algorithm. * * r0 is the numerator, r1 the denominator. * * The code before JMP computes the correct shift I, so that * r0 and (r1 << I) have the highest bit set in the same position. * At the time of JMP, ip := .Ldiv0block - 12 * I. * This depends on the fixed instruction size of block. * For ARM mode, this is 12 Bytes, for THUMB mode 14 Bytes. * * block(shift) implements the test-and-update-quotient core. * It assumes (r0 << shift) can be computed without overflow and * that (r0 << shift) < 2 * r1. The quotient is stored in r3. */ -# ifdef __ARM_FEATURE_CLZ +# if defined(__ARM_FEATURE_CLZ) clz ip, r0 clz r3, r1 /* r0 >= r1 implies clz(r0) <= clz(r1), so ip <= r3. */ sub r3, r3, ip # if __ARM_ARCH_ISA_THUMB == 2 adr ip, LOCAL_LABEL(div0block) + 1 sub ip, ip, r3, lsl #1 # else adr ip, LOCAL_LABEL(div0block) # endif sub ip, ip, r3, lsl #2 sub ip, ip, r3, lsl #3 mov r3, #0 bx ip -# else +# else /* No CLZ Feature */ # if __ARM_ARCH_ISA_THUMB == 2 # error THUMB mode requires CLZ or UDIV # endif +# if __ARM_ARCH_ISA_THUMB == 1 +# define BLOCK_SIZE 10 +# else +# define BLOCK_SIZE 12 +# endif + mov r2, r0 +# if __ARM_ARCH_ISA_THUMB == 1 + mov ip, r0 + adr r0, LOCAL_LABEL(div0block) + adds r0, #1 +# else adr ip, LOCAL_LABEL(div0block) - - lsr r3, r2, #16 +# endif + lsrs r3, r2, #16 cmp r3, r1 +# if __ARM_ARCH_ISA_THUMB == 1 + blo LOCAL_LABEL(skip_16) + movs r2, r3 + subs r0, r0, #(16 * BLOCK_SIZE) +LOCAL_LABEL(skip_16): +# else movhs r2, r3 - subhs ip, ip, #(16 * 12) + subhs ip, ip, #(16 * BLOCK_SIZE) +# endif - lsr r3, r2, #8 + lsrs r3, r2, #8 cmp r3, r1 +# if __ARM_ARCH_ISA_THUMB == 1 + blo LOCAL_LABEL(skip_8) + movs r2, r3 + subs r0, r0, #(8 * BLOCK_SIZE) +LOCAL_LABEL(skip_8): +# else movhs r2, r3 - subhs ip, ip, #(8 * 12) + subhs ip, ip, #(8 * BLOCK_SIZE) +# endif - lsr r3, r2, #4 + lsrs r3, r2, #4 cmp r3, r1 +# if __ARM_ARCH_ISA_THUMB == 1 + blo LOCAL_LABEL(skip_4) + movs r2, r3 + subs r0, r0, #(4 * BLOCK_SIZE) +LOCAL_LABEL(skip_4): +# else movhs r2, r3 - subhs ip, #(4 * 12) + subhs ip, #(4 * BLOCK_SIZE) +# endif - lsr r3, r2, #2 + lsrs r3, r2, #2 cmp r3, r1 +# if __ARM_ARCH_ISA_THUMB == 1 + blo LOCAL_LABEL(skip_2) + movs r2, r3 + subs r0, r0, #(2 * BLOCK_SIZE) +LOCAL_LABEL(skip_2): +# else movhs r2, r3 - subhs ip, ip, #(2 * 12) + subhs ip, ip, #(2 * BLOCK_SIZE) +# endif /* Last block, no need to update r2 or r3. */ +# if __ARM_ARCH_ISA_THUMB == 1 + lsrs r3, r2, #1 + cmp r3, r1 + blo LOCAL_LABEL(skip_1) + subs r0, r0, #(1 * BLOCK_SIZE) +LOCAL_LABEL(skip_1): + movs r2, r0 + mov r0, ip + movs r3, #0 + JMP (r2) + +# else cmp r1, r2, lsr #1 - subls ip, ip, #(1 * 12) + subls ip, ip, #(1 * BLOCK_SIZE) - mov r3, #0 + movs r3, #0 JMP(ip) -# endif +# endif +# endif /* __ARM_FEATURE_CLZ */ + #define IMM # + /* due to the range limit of branch in Thumb1, we have to place the + block closer */ +LOCAL_LABEL(divby0): + movs r0, #0 +# if defined(__ARM_EABI__) + bl __aeabi_idiv0 // due to relocation limit, can't use b. +# endif + JMP(lr) + +#if __ARM_ARCH_ISA_THUMB == 1 #define block(shift) \ + lsls r2, r1, IMM shift; \ + cmp r0, r2; \ + blo LOCAL_LABEL(block_skip_##shift); \ + subs r0, r0, r2; \ + LOCAL_LABEL(block_skip_##shift) :; \ + adcs r3, r3 /* same as ((r3 << 1) | Carry). Carry is set if r0 >= r2. */ + + /* TODO: if current location counter is not not word aligned, we don't + need the .p2align and nop */ + /* Label div0block must be word-aligned. First align block 31 */ + .p2align 2 + nop /* Padding to align div0block as 31 blocks = 310 bytes */ + +#else +#define block(shift) \ cmp r0, r1, lsl IMM shift; \ ITT(hs); \ WIDE(addhs) r3, r3, IMM (1 << shift); \ WIDE(subhs) r0, r0, r1, lsl IMM shift +#endif block(31) block(30) block(29) block(28) block(27) block(26) block(25) block(24) block(23) block(22) block(21) block(20) block(19) block(18) block(17) block(16) block(15) block(14) block(13) block(12) block(11) block(10) block(9) block(8) block(7) block(6) block(5) block(4) block(3) block(2) block(1) LOCAL_LABEL(div0block): block(0) mov r0, r3 JMP(lr) #endif /* __ARM_ARCH_EXT_IDIV__ */ +#if __ARM_ARCH_EXT_IDIV__ LOCAL_LABEL(divby0): - mov r0, #0 -#ifdef __ARM_EABI__ - b __aeabi_idiv0 -#else - JMP(lr) + mov r0, #0 +# ifdef __ARM_EABI__ + b __aeabi_idiv0 +# else + JMP(lr) +# endif #endif END_COMPILERRT_FUNCTION(__udivsi3) NO_EXEC_STACK_DIRECTIVE Index: projects/clang400-import/contrib/compiler-rt/lib/builtins/assembly.h =================================================================== --- projects/clang400-import/contrib/compiler-rt/lib/builtins/assembly.h (revision 311696) +++ projects/clang400-import/contrib/compiler-rt/lib/builtins/assembly.h (revision 311697) @@ -1,168 +1,169 @@ /* ===-- assembly.h - compiler-rt assembler support macros -----------------=== * * The LLVM Compiler Infrastructure * * This file is dual licensed under the MIT and the University of Illinois Open * Source Licenses. See LICENSE.TXT for details. * * ===----------------------------------------------------------------------=== * * This file defines macros for use in compiler-rt assembler source. * This file is not part of the interface of this library. * * ===----------------------------------------------------------------------=== */ #ifndef COMPILERRT_ASSEMBLY_H #define COMPILERRT_ASSEMBLY_H #if defined(__POWERPC__) || defined(__powerpc__) || defined(__ppc__) #define SEPARATOR @ #else #define SEPARATOR ; #endif #if defined(__APPLE__) #define HIDDEN(name) .private_extern name #define LOCAL_LABEL(name) L_##name // tell linker it can break up file at label boundaries #define FILE_LEVEL_DIRECTIVE .subsections_via_symbols #define SYMBOL_IS_FUNC(name) #define CONST_SECTION .const #define NO_EXEC_STACK_DIRECTIVE #elif defined(__ELF__) #define HIDDEN(name) .hidden name #define LOCAL_LABEL(name) .L_##name #define FILE_LEVEL_DIRECTIVE #if defined(__arm__) #define SYMBOL_IS_FUNC(name) .type name,%function #else #define SYMBOL_IS_FUNC(name) .type name,@function #endif #define CONST_SECTION .section .rodata #if defined(__GNU__) || defined(__ANDROID__) || defined(__FreeBSD__) #define NO_EXEC_STACK_DIRECTIVE .section .note.GNU-stack,"",%progbits #else #define NO_EXEC_STACK_DIRECTIVE #endif #else // !__APPLE__ && !__ELF__ #define HIDDEN(name) #define LOCAL_LABEL(name) .L ## name #define FILE_LEVEL_DIRECTIVE #define SYMBOL_IS_FUNC(name) \ .def name SEPARATOR \ .scl 2 SEPARATOR \ .type 32 SEPARATOR \ .endef #define CONST_SECTION .section .rdata,"rd" #define NO_EXEC_STACK_DIRECTIVE #endif #if defined(__arm__) #if defined(__ARM_ARCH_4T__) || __ARM_ARCH >= 5 #define ARM_HAS_BX #endif -#if !defined(__ARM_FEATURE_CLZ) && \ +#if !defined(__ARM_FEATURE_CLZ) && __ARM_ARCH_ISA_THUMB != 1 && \ (__ARM_ARCH >= 6 || (__ARM_ARCH == 5 && !defined(__ARM_ARCH_5__))) #define __ARM_FEATURE_CLZ #endif #ifdef ARM_HAS_BX #define JMP(r) bx r #define JMPc(r, c) bx##c r #else #define JMP(r) mov pc, r #define JMPc(r, c) mov##c pc, r #endif // pop {pc} can't switch Thumb mode on ARMv4T #if __ARM_ARCH >= 5 #define POP_PC() pop {pc} #else #define POP_PC() \ pop {ip}; \ JMP(ip) #endif #if __ARM_ARCH_ISA_THUMB == 2 #define IT(cond) it cond #define ITT(cond) itt cond #else #define IT(cond) #define ITT(cond) #endif #if __ARM_ARCH_ISA_THUMB == 2 #define WIDE(op) op.w #else #define WIDE(op) op #endif #endif #define GLUE2(a, b) a##b #define GLUE(a, b) GLUE2(a, b) #define SYMBOL_NAME(name) GLUE(__USER_LABEL_PREFIX__, name) #ifdef VISIBILITY_HIDDEN #define DECLARE_SYMBOL_VISIBILITY(name) \ HIDDEN(SYMBOL_NAME(name)) SEPARATOR #else #define DECLARE_SYMBOL_VISIBILITY(name) #endif #define DEFINE_COMPILERRT_FUNCTION(name) \ FILE_LEVEL_DIRECTIVE SEPARATOR \ .globl SYMBOL_NAME(name) SEPARATOR \ SYMBOL_IS_FUNC(SYMBOL_NAME(name)) SEPARATOR \ DECLARE_SYMBOL_VISIBILITY(name) \ SYMBOL_NAME(name): #define DEFINE_COMPILERRT_THUMB_FUNCTION(name) \ FILE_LEVEL_DIRECTIVE SEPARATOR \ .globl SYMBOL_NAME(name) SEPARATOR \ SYMBOL_IS_FUNC(SYMBOL_NAME(name)) SEPARATOR \ DECLARE_SYMBOL_VISIBILITY(name) SEPARATOR \ .thumb_func SEPARATOR \ SYMBOL_NAME(name): #define DEFINE_COMPILERRT_PRIVATE_FUNCTION(name) \ FILE_LEVEL_DIRECTIVE SEPARATOR \ .globl SYMBOL_NAME(name) SEPARATOR \ SYMBOL_IS_FUNC(SYMBOL_NAME(name)) SEPARATOR \ HIDDEN(SYMBOL_NAME(name)) SEPARATOR \ SYMBOL_NAME(name): #define DEFINE_COMPILERRT_PRIVATE_FUNCTION_UNMANGLED(name) \ .globl name SEPARATOR \ SYMBOL_IS_FUNC(name) SEPARATOR \ HIDDEN(name) SEPARATOR \ name: #define DEFINE_COMPILERRT_FUNCTION_ALIAS(name, target) \ .globl SYMBOL_NAME(name) SEPARATOR \ SYMBOL_IS_FUNC(SYMBOL_NAME(name)) SEPARATOR \ + DECLARE_SYMBOL_VISIBILITY(SYMBOL_NAME(name)) SEPARATOR \ .set SYMBOL_NAME(name), SYMBOL_NAME(target) SEPARATOR #if defined(__ARM_EABI__) #define DEFINE_AEABI_FUNCTION_ALIAS(aeabi_name, name) \ DEFINE_COMPILERRT_FUNCTION_ALIAS(aeabi_name, name) #else #define DEFINE_AEABI_FUNCTION_ALIAS(aeabi_name, name) #endif #ifdef __ELF__ #define END_COMPILERRT_FUNCTION(name) \ .size SYMBOL_NAME(name), . - SYMBOL_NAME(name) #else #define END_COMPILERRT_FUNCTION(name) #endif #endif /* COMPILERRT_ASSEMBLY_H */ Index: projects/clang400-import/contrib/compiler-rt/lib/builtins/atomic.c =================================================================== --- projects/clang400-import/contrib/compiler-rt/lib/builtins/atomic.c (revision 311696) +++ projects/clang400-import/contrib/compiler-rt/lib/builtins/atomic.c (revision 311697) @@ -1,331 +1,338 @@ /*===-- atomic.c - Implement support functions for atomic operations.------=== * * The LLVM Compiler Infrastructure * * This file is dual licensed under the MIT and the University of Illinois Open * Source Licenses. See LICENSE.TXT for details. * *===----------------------------------------------------------------------=== * * atomic.c defines a set of functions for performing atomic accesses on * arbitrary-sized memory locations. This design uses locks that should * be fast in the uncontended case, for two reasons: * * 1) This code must work with C programs that do not link to anything * (including pthreads) and so it should not depend on any pthread * functions. * 2) Atomic operations, rather than explicit mutexes, are most commonly used * on code where contended operations are rate. * * To avoid needing a per-object lock, this code allocates an array of * locks and hashes the object pointers to find the one that it should use. * For operations that must be atomic on two locations, the lower lock is * always acquired first, to avoid deadlock. * *===----------------------------------------------------------------------=== */ #include #include #include "assembly.h" // Clang objects if you redefine a builtin. This little hack allows us to // define a function with the same name as an intrinsic. #pragma redefine_extname __atomic_load_c SYMBOL_NAME(__atomic_load) #pragma redefine_extname __atomic_store_c SYMBOL_NAME(__atomic_store) #pragma redefine_extname __atomic_exchange_c SYMBOL_NAME(__atomic_exchange) #pragma redefine_extname __atomic_compare_exchange_c SYMBOL_NAME(__atomic_compare_exchange) /// Number of locks. This allocates one page on 32-bit platforms, two on /// 64-bit. This can be specified externally if a different trade between /// memory usage and contention probability is required for a given platform. #ifndef SPINLOCK_COUNT #define SPINLOCK_COUNT (1<<10) #endif static const long SPINLOCK_MASK = SPINLOCK_COUNT - 1; //////////////////////////////////////////////////////////////////////////////// // Platform-specific lock implementation. Falls back to spinlocks if none is // defined. Each platform should define the Lock type, and corresponding // lock() and unlock() functions. //////////////////////////////////////////////////////////////////////////////// #ifdef __FreeBSD__ #include #include #include #include typedef struct _usem Lock; __inline static void unlock(Lock *l) { __c11_atomic_store((_Atomic(uint32_t)*)&l->_count, 1, __ATOMIC_RELEASE); __c11_atomic_thread_fence(__ATOMIC_SEQ_CST); if (l->_has_waiters) _umtx_op(l, UMTX_OP_SEM_WAKE, 1, 0, 0); } __inline static void lock(Lock *l) { uint32_t old = 1; while (!__c11_atomic_compare_exchange_weak((_Atomic(uint32_t)*)&l->_count, &old, 0, __ATOMIC_ACQUIRE, __ATOMIC_RELAXED)) { _umtx_op(l, UMTX_OP_SEM_WAIT, 0, 0, 0); old = 1; } } /// locks for atomic operations static Lock locks[SPINLOCK_COUNT] = { [0 ... SPINLOCK_COUNT-1] = {0,1,0} }; #elif defined(__APPLE__) #include typedef OSSpinLock Lock; __inline static void unlock(Lock *l) { OSSpinLockUnlock(l); } /// Locks a lock. In the current implementation, this is potentially /// unbounded in the contended case. __inline static void lock(Lock *l) { OSSpinLockLock(l); } static Lock locks[SPINLOCK_COUNT]; // initialized to OS_SPINLOCK_INIT which is 0 #else typedef _Atomic(uintptr_t) Lock; /// Unlock a lock. This is a release operation. __inline static void unlock(Lock *l) { __c11_atomic_store(l, 0, __ATOMIC_RELEASE); } /// Locks a lock. In the current implementation, this is potentially /// unbounded in the contended case. __inline static void lock(Lock *l) { uintptr_t old = 0; while (!__c11_atomic_compare_exchange_weak(l, &old, 1, __ATOMIC_ACQUIRE, __ATOMIC_RELAXED)) old = 0; } /// locks for atomic operations static Lock locks[SPINLOCK_COUNT]; #endif /// Returns a lock to use for a given pointer. static __inline Lock *lock_for_pointer(void *ptr) { intptr_t hash = (intptr_t)ptr; // Disregard the lowest 4 bits. We want all values that may be part of the // same memory operation to hash to the same value and therefore use the same // lock. hash >>= 4; // Use the next bits as the basis for the hash intptr_t low = hash & SPINLOCK_MASK; // Now use the high(er) set of bits to perturb the hash, so that we don't // get collisions from atomic fields in a single object hash >>= 16; hash ^= low; // Return a pointer to the word to use return locks + (hash & SPINLOCK_MASK); } /// Macros for determining whether a size is lock free. Clang can not yet /// codegen __atomic_is_lock_free(16), so for now we assume 16-byte values are /// not lock free. #define IS_LOCK_FREE_1 __c11_atomic_is_lock_free(1) #define IS_LOCK_FREE_2 __c11_atomic_is_lock_free(2) #define IS_LOCK_FREE_4 __c11_atomic_is_lock_free(4) #define IS_LOCK_FREE_8 __c11_atomic_is_lock_free(8) #define IS_LOCK_FREE_16 0 /// Macro that calls the compiler-generated lock-free versions of functions /// when they exist. #define LOCK_FREE_CASES() \ do {\ switch (size) {\ case 2:\ if (IS_LOCK_FREE_2) {\ LOCK_FREE_ACTION(uint16_t);\ }\ case 4:\ if (IS_LOCK_FREE_4) {\ LOCK_FREE_ACTION(uint32_t);\ }\ case 8:\ if (IS_LOCK_FREE_8) {\ LOCK_FREE_ACTION(uint64_t);\ }\ case 16:\ if (IS_LOCK_FREE_16) {\ /* FIXME: __uint128_t isn't available on 32 bit platforms. LOCK_FREE_ACTION(__uint128_t);*/\ }\ }\ } while (0) /// An atomic load operation. This is atomic with respect to the source /// pointer only. void __atomic_load_c(int size, void *src, void *dest, int model) { #define LOCK_FREE_ACTION(type) \ *((type*)dest) = __c11_atomic_load((_Atomic(type)*)src, model);\ return; LOCK_FREE_CASES(); #undef LOCK_FREE_ACTION Lock *l = lock_for_pointer(src); lock(l); memcpy(dest, src, size); unlock(l); } /// An atomic store operation. This is atomic with respect to the destination /// pointer only. void __atomic_store_c(int size, void *dest, void *src, int model) { #define LOCK_FREE_ACTION(type) \ __c11_atomic_store((_Atomic(type)*)dest, *(type*)dest, model);\ return; LOCK_FREE_CASES(); #undef LOCK_FREE_ACTION Lock *l = lock_for_pointer(dest); lock(l); memcpy(dest, src, size); unlock(l); } /// Atomic compare and exchange operation. If the value at *ptr is identical /// to the value at *expected, then this copies value at *desired to *ptr. If /// they are not, then this stores the current value from *ptr in *expected. /// /// This function returns 1 if the exchange takes place or 0 if it fails. int __atomic_compare_exchange_c(int size, void *ptr, void *expected, void *desired, int success, int failure) { #define LOCK_FREE_ACTION(type) \ return __c11_atomic_compare_exchange_strong((_Atomic(type)*)ptr, (type*)expected,\ *(type*)desired, success, failure) LOCK_FREE_CASES(); #undef LOCK_FREE_ACTION Lock *l = lock_for_pointer(ptr); lock(l); if (memcmp(ptr, expected, size) == 0) { memcpy(ptr, desired, size); unlock(l); return 1; } memcpy(expected, ptr, size); unlock(l); return 0; } /// Performs an atomic exchange operation between two pointers. This is atomic /// with respect to the target address. void __atomic_exchange_c(int size, void *ptr, void *val, void *old, int model) { #define LOCK_FREE_ACTION(type) \ *(type*)old = __c11_atomic_exchange((_Atomic(type)*)ptr, *(type*)val,\ model);\ return; LOCK_FREE_CASES(); #undef LOCK_FREE_ACTION Lock *l = lock_for_pointer(ptr); lock(l); memcpy(old, ptr, size); memcpy(ptr, val, size); unlock(l); } //////////////////////////////////////////////////////////////////////////////// // Where the size is known at compile time, the compiler may emit calls to // specialised versions of the above functions. //////////////////////////////////////////////////////////////////////////////// +#ifdef __SIZEOF_INT128__ #define OPTIMISED_CASES\ OPTIMISED_CASE(1, IS_LOCK_FREE_1, uint8_t)\ OPTIMISED_CASE(2, IS_LOCK_FREE_2, uint16_t)\ OPTIMISED_CASE(4, IS_LOCK_FREE_4, uint32_t)\ OPTIMISED_CASE(8, IS_LOCK_FREE_8, uint64_t)\ - /* FIXME: __uint128_t isn't available on 32 bit platforms. - OPTIMISED_CASE(16, IS_LOCK_FREE_16, __uint128_t)*/\ + OPTIMISED_CASE(16, IS_LOCK_FREE_16, __uint128_t) +#else +#define OPTIMISED_CASES\ + OPTIMISED_CASE(1, IS_LOCK_FREE_1, uint8_t)\ + OPTIMISED_CASE(2, IS_LOCK_FREE_2, uint16_t)\ + OPTIMISED_CASE(4, IS_LOCK_FREE_4, uint32_t)\ + OPTIMISED_CASE(8, IS_LOCK_FREE_8, uint64_t) +#endif #define OPTIMISED_CASE(n, lockfree, type)\ type __atomic_load_##n(type *src, int model) {\ if (lockfree)\ return __c11_atomic_load((_Atomic(type)*)src, model);\ Lock *l = lock_for_pointer(src);\ lock(l);\ type val = *src;\ unlock(l);\ return val;\ } OPTIMISED_CASES #undef OPTIMISED_CASE #define OPTIMISED_CASE(n, lockfree, type)\ void __atomic_store_##n(type *dest, type val, int model) {\ if (lockfree) {\ __c11_atomic_store((_Atomic(type)*)dest, val, model);\ return;\ }\ Lock *l = lock_for_pointer(dest);\ lock(l);\ *dest = val;\ unlock(l);\ return;\ } OPTIMISED_CASES #undef OPTIMISED_CASE #define OPTIMISED_CASE(n, lockfree, type)\ type __atomic_exchange_##n(type *dest, type val, int model) {\ if (lockfree)\ return __c11_atomic_exchange((_Atomic(type)*)dest, val, model);\ Lock *l = lock_for_pointer(dest);\ lock(l);\ type tmp = *dest;\ *dest = val;\ unlock(l);\ return tmp;\ } OPTIMISED_CASES #undef OPTIMISED_CASE #define OPTIMISED_CASE(n, lockfree, type)\ int __atomic_compare_exchange_##n(type *ptr, type *expected, type desired,\ int success, int failure) {\ if (lockfree)\ return __c11_atomic_compare_exchange_strong((_Atomic(type)*)ptr, expected, desired,\ success, failure);\ Lock *l = lock_for_pointer(ptr);\ lock(l);\ if (*ptr == *expected) {\ *ptr = desired;\ unlock(l);\ return 1;\ }\ *expected = *ptr;\ unlock(l);\ return 0;\ } OPTIMISED_CASES #undef OPTIMISED_CASE //////////////////////////////////////////////////////////////////////////////// // Atomic read-modify-write operations for integers of various sizes. //////////////////////////////////////////////////////////////////////////////// #define ATOMIC_RMW(n, lockfree, type, opname, op) \ type __atomic_fetch_##opname##_##n(type *ptr, type val, int model) {\ if (lockfree) \ return __c11_atomic_fetch_##opname((_Atomic(type)*)ptr, val, model);\ Lock *l = lock_for_pointer(ptr);\ lock(l);\ type tmp = *ptr;\ *ptr = tmp op val;\ unlock(l);\ return tmp;\ } #define OPTIMISED_CASE(n, lockfree, type) ATOMIC_RMW(n, lockfree, type, add, +) OPTIMISED_CASES #undef OPTIMISED_CASE #define OPTIMISED_CASE(n, lockfree, type) ATOMIC_RMW(n, lockfree, type, sub, -) OPTIMISED_CASES #undef OPTIMISED_CASE #define OPTIMISED_CASE(n, lockfree, type) ATOMIC_RMW(n, lockfree, type, and, &) OPTIMISED_CASES #undef OPTIMISED_CASE #define OPTIMISED_CASE(n, lockfree, type) ATOMIC_RMW(n, lockfree, type, or, |) OPTIMISED_CASES #undef OPTIMISED_CASE #define OPTIMISED_CASE(n, lockfree, type) ATOMIC_RMW(n, lockfree, type, xor, ^) OPTIMISED_CASES #undef OPTIMISED_CASE Index: projects/clang400-import/contrib/compiler-rt/lib/builtins/clear_cache.c =================================================================== --- projects/clang400-import/contrib/compiler-rt/lib/builtins/clear_cache.c (revision 311696) +++ projects/clang400-import/contrib/compiler-rt/lib/builtins/clear_cache.c (revision 311697) @@ -1,170 +1,172 @@ /* ===-- clear_cache.c - Implement __clear_cache ---------------------------=== * * The LLVM Compiler Infrastructure * * This file is dual licensed under the MIT and the University of Illinois Open * Source Licenses. See LICENSE.TXT for details. * * ===----------------------------------------------------------------------=== */ #include "int_lib.h" #include #if __APPLE__ #include #endif #if defined(_WIN32) /* Forward declare Win32 APIs since the GCC mode driver does not handle the newer SDKs as well as needed. */ uint32_t FlushInstructionCache(uintptr_t hProcess, void *lpBaseAddress, uintptr_t dwSize); uintptr_t GetCurrentProcess(void); #endif #if (defined(__FreeBSD__) || defined(__Bitrig__)) && defined(__arm__) #include #include #endif #if defined(__NetBSD__) && defined(__arm__) #include #endif #if defined(__mips__) && !defined(__FreeBSD__) #include #include #include #if defined(__ANDROID__) && defined(__LP64__) /* * clear_mips_cache - Invalidates instruction cache for Mips. */ static void clear_mips_cache(const void* Addr, size_t Size) { asm volatile ( ".set push\n" ".set noreorder\n" ".set noat\n" "beq %[Size], $zero, 20f\n" /* If size == 0, branch around. */ "nop\n" "daddu %[Size], %[Addr], %[Size]\n" /* Calculate end address + 1 */ "rdhwr $v0, $1\n" /* Get step size for SYNCI. $1 is $HW_SYNCI_Step */ "beq $v0, $zero, 20f\n" /* If no caches require synchronization, branch around. */ "nop\n" "10:\n" "synci 0(%[Addr])\n" /* Synchronize all caches around address. */ "daddu %[Addr], %[Addr], $v0\n" /* Add step size. */ "sltu $at, %[Addr], %[Size]\n" /* Compare current with end address. */ "bne $at, $zero, 10b\n" /* Branch if more to do. */ "nop\n" "sync\n" /* Clear memory hazards. */ "20:\n" "bal 30f\n" "nop\n" "30:\n" "daddiu $ra, $ra, 12\n" /* $ra has a value of $pc here. Add offset of 12 to point to the instruction after the last nop. */ "jr.hb $ra\n" /* Return, clearing instruction hazards. */ "nop\n" ".set pop\n" : [Addr] "+r"(Addr), [Size] "+r"(Size) :: "at", "ra", "v0", "memory" ); } #endif #endif #if defined(__linux__) && defined(__arm__) #include #endif /* * The compiler generates calls to __clear_cache() when creating * trampoline functions on the stack for use with nested functions. * It is expected to invalidate the instruction cache for the * specified range. */ void __clear_cache(void *start, void *end) { #if __i386__ || __x86_64__ /* * Intel processors have a unified instruction and data cache * so there is nothing to do */ #elif defined(__arm__) && !defined(__APPLE__) #if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__Bitrig__) struct arm_sync_icache_args arg; arg.addr = (uintptr_t)start; arg.len = (uintptr_t)end - (uintptr_t)start; sysarch(ARM_SYNC_ICACHE, &arg); #elif defined(__linux__) register int start_reg __asm("r0") = (int) (intptr_t) start; const register int end_reg __asm("r1") = (int) (intptr_t) end; + const register int flags __asm("r2") = 0; const register int syscall_nr __asm("r7") = __ARM_NR_cacheflush; __asm __volatile("svc 0x0" : "=r"(start_reg) - : "r"(syscall_nr), "r"(start_reg), "r"(end_reg)); + : "r"(syscall_nr), "r"(start_reg), "r"(end_reg), + "r"(flags)); if (start_reg != 0) { compilerrt_abort(); } #elif defined(_WIN32) FlushInstructionCache(GetCurrentProcess(), start, end - start); #else compilerrt_abort(); #endif #elif defined(__mips__) && !defined(__FreeBSD__) const uintptr_t start_int = (uintptr_t) start; const uintptr_t end_int = (uintptr_t) end; #if defined(__ANDROID__) && defined(__LP64__) // Call synci implementation for short address range. const uintptr_t address_range_limit = 256; if ((end_int - start_int) <= address_range_limit) { clear_mips_cache(start, (end_int - start_int)); } else { syscall(__NR_cacheflush, start, (end_int - start_int), BCACHE); } #else syscall(__NR_cacheflush, start, (end_int - start_int), BCACHE); #endif #elif defined(__aarch64__) && !defined(__APPLE__) uint64_t xstart = (uint64_t)(uintptr_t) start; uint64_t xend = (uint64_t)(uintptr_t) end; uint64_t addr; // Get Cache Type Info uint64_t ctr_el0; __asm __volatile("mrs %0, ctr_el0" : "=r"(ctr_el0)); /* * dc & ic instructions must use 64bit registers so we don't use * uintptr_t in case this runs in an IPL32 environment. */ const size_t dcache_line_size = 4 << ((ctr_el0 >> 16) & 15); for (addr = xstart; addr < xend; addr += dcache_line_size) __asm __volatile("dc cvau, %0" :: "r"(addr)); __asm __volatile("dsb ish"); const size_t icache_line_size = 4 << ((ctr_el0 >> 0) & 15); for (addr = xstart; addr < xend; addr += icache_line_size) __asm __volatile("ic ivau, %0" :: "r"(addr)); __asm __volatile("isb sy"); #else #if __APPLE__ /* On Darwin, sys_icache_invalidate() provides this functionality */ sys_icache_invalidate(start, end-start); #else compilerrt_abort(); #endif #endif } Index: projects/clang400-import/contrib/compiler-rt/lib/builtins/floattitf.c =================================================================== --- projects/clang400-import/contrib/compiler-rt/lib/builtins/floattitf.c (nonexistent) +++ projects/clang400-import/contrib/compiler-rt/lib/builtins/floattitf.c (revision 311697) @@ -0,0 +1,82 @@ +//===-- lib/floattitf.c - int128 -> quad-precision conversion -----*- C -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements ti_int to quad-precision conversion for the +// compiler-rt library in the IEEE-754 default round-to-nearest, ties-to-even +// mode. +// +//===----------------------------------------------------------------------===// + +#define QUAD_PRECISION +#include "fp_lib.h" +#include "int_lib.h" + +/* Returns: convert a ti_int to a fp_t, rounding toward even. */ + +/* Assumption: fp_t is a IEEE 128 bit floating point type + * ti_int is a 128 bit integral type + */ + +/* seee eeee eeee eeee mmmm mmmm mmmm mmmm | mmmm mmmm mmmm mmmm mmmm mmmm mmmm mmmm | + * mmmm mmmm mmmm mmmm mmmm mmmm mmmm mmmm | mmmm mmmm mmmm mmmm mmmm mmmm mmmm mmmm + */ + +#if defined(CRT_HAS_128BIT) && defined(CRT_LDBL_128BIT) +COMPILER_RT_ABI fp_t +__floattitf(ti_int a) { + if (a == 0) + return 0.0; + const unsigned N = sizeof(ti_int) * CHAR_BIT; + const ti_int s = a >> (N-1); + a = (a ^ s) - s; + int sd = N - __clzti2(a); /* number of significant digits */ + int e = sd - 1; /* exponent */ + if (sd > LDBL_MANT_DIG) { + /* start: 0000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQxxxxxxxxxxxxxxxxxx + * finish: 000000000000000000000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQR + * 12345678901234567890123456 + * 1 = msb 1 bit + * P = bit LDBL_MANT_DIG-1 bits to the right of 1 + * Q = bit LDBL_MANT_DIG bits to the right of 1 + * R = "or" of all bits to the right of Q + */ + switch (sd) { + case LDBL_MANT_DIG + 1: + a <<= 1; + break; + case LDBL_MANT_DIG + 2: + break; + default: + a = ((tu_int)a >> (sd - (LDBL_MANT_DIG+2))) | + ((a & ((tu_int)(-1) >> ((N + LDBL_MANT_DIG+2) - sd))) != 0); + }; + /* finish: */ + a |= (a & 4) != 0; /* Or P into R */ + ++a; /* round - this step may add a significant bit */ + a >>= 2; /* dump Q and R */ + /* a is now rounded to LDBL_MANT_DIG or LDBL_MANT_DIG+1 bits */ + if (a & ((tu_int)1 << LDBL_MANT_DIG)) { + a >>= 1; + ++e; + } + /* a is now rounded to LDBL_MANT_DIG bits */ + } else { + a <<= (LDBL_MANT_DIG - sd); + /* a is now rounded to LDBL_MANT_DIG bits */ + } + + long_double_bits fb; + fb.u.high.all = (s & 0x8000000000000000LL) /* sign */ + | (du_int)(e + 16383) << 48 /* exponent */ + | ((a >> 64) & 0x0000ffffffffffffLL); /* significand */ + fb.u.low.all = (du_int)(a); + return fb.f; +} + +#endif Property changes on: projects/clang400-import/contrib/compiler-rt/lib/builtins/floattitf.c ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: projects/clang400-import/contrib/compiler-rt/lib/builtins/floatuntitf.c =================================================================== --- projects/clang400-import/contrib/compiler-rt/lib/builtins/floatuntitf.c (nonexistent) +++ projects/clang400-import/contrib/compiler-rt/lib/builtins/floatuntitf.c (revision 311697) @@ -0,0 +1,79 @@ +//===-- lib/floatuntitf.c - uint128 -> quad-precision conversion --*- C -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements tu_int to quad-precision conversion for the +// compiler-rt library in the IEEE-754 default round-to-nearest, ties-to-even +// mode. +// +//===----------------------------------------------------------------------===// + +#define QUAD_PRECISION +#include "fp_lib.h" +#include "int_lib.h" + +/* Returns: convert a tu_int to a fp_t, rounding toward even. */ + +/* Assumption: fp_t is a IEEE 128 bit floating point type + * tu_int is a 128 bit integral type + */ + +/* seee eeee eeee eeee mmmm mmmm mmmm mmmm | mmmm mmmm mmmm mmmm mmmm mmmm mmmm mmmm | + * mmmm mmmm mmmm mmmm mmmm mmmm mmmm mmmm | mmmm mmmm mmmm mmmm mmmm mmmm mmmm mmmm + */ + +#if defined(CRT_HAS_128BIT) && defined(CRT_LDBL_128BIT) +COMPILER_RT_ABI fp_t +__floatuntitf(tu_int a) { + if (a == 0) + return 0.0; + const unsigned N = sizeof(tu_int) * CHAR_BIT; + int sd = N - __clzti2(a); /* number of significant digits */ + int e = sd - 1; /* exponent */ + if (sd > LDBL_MANT_DIG) { + /* start: 0000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQxxxxxxxxxxxxxxxxxx + * finish: 000000000000000000000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQR + * 12345678901234567890123456 + * 1 = msb 1 bit + * P = bit LDBL_MANT_DIG-1 bits to the right of 1 + * Q = bit LDBL_MANT_DIG bits to the right of 1 + * R = "or" of all bits to the right of Q + */ + switch (sd) { + case LDBL_MANT_DIG + 1: + a <<= 1; + break; + case LDBL_MANT_DIG + 2: + break; + default: + a = (a >> (sd - (LDBL_MANT_DIG+2))) | + ((a & ((tu_int)(-1) >> ((N + LDBL_MANT_DIG+2) - sd))) != 0); + }; + /* finish: */ + a |= (a & 4) != 0; /* Or P into R */ + ++a; /* round - this step may add a significant bit */ + a >>= 2; /* dump Q and R */ + /* a is now rounded to LDBL_MANT_DIG or LDBL_MANT_DIG+1 bits */ + if (a & ((tu_int)1 << LDBL_MANT_DIG)) { + a >>= 1; + ++e; + } + /* a is now rounded to LDBL_MANT_DIG bits */ + } else { + a <<= (LDBL_MANT_DIG - sd); + /* a is now rounded to LDBL_MANT_DIG bits */ + } + + long_double_bits fb; + fb.u.high.all = (du_int)(e + 16383) << 48 /* exponent */ + | ((a >> 64) & 0x0000ffffffffffffLL); /* significand */ + fb.u.low.all = (du_int)(a); + return fb.f; +} + +#endif Property changes on: projects/clang400-import/contrib/compiler-rt/lib/builtins/floatuntitf.c ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: projects/clang400-import/contrib/compiler-rt/lib/builtins/int_lib.h =================================================================== --- projects/clang400-import/contrib/compiler-rt/lib/builtins/int_lib.h (revision 311696) +++ projects/clang400-import/contrib/compiler-rt/lib/builtins/int_lib.h (revision 311697) @@ -1,159 +1,159 @@ /* ===-- int_lib.h - configuration header for compiler-rt -----------------=== * * The LLVM Compiler Infrastructure * * This file is dual licensed under the MIT and the University of Illinois Open * Source Licenses. See LICENSE.TXT for details. * * ===----------------------------------------------------------------------=== * * This file is a configuration header for compiler-rt. * This file is not part of the interface of this library. * * ===----------------------------------------------------------------------=== */ #ifndef INT_LIB_H #define INT_LIB_H /* Assumption: Signed integral is 2's complement. */ /* Assumption: Right shift of signed negative is arithmetic shift. */ /* Assumption: Endianness is little or big (not mixed). */ #if defined(__ELF__) #define FNALIAS(alias_name, original_name) \ void alias_name() __attribute__((alias(#original_name))) #else #define FNALIAS(alias, name) _Pragma("GCC error(\"alias unsupported on this file format\")") #endif /* ABI macro definitions */ #if __ARM_EABI__ # define ARM_EABI_FNALIAS(aeabi_name, name) \ void __aeabi_##aeabi_name() __attribute__((alias("__" #name))); # if !defined(__clang__) && defined(__GNUC__) && \ (__GNUC__ < 4 || __GNUC__ == 4 && __GNUC_MINOR__ < 5) /* The pcs attribute was introduced in GCC 4.5.0 */ # define COMPILER_RT_ABI # else # define COMPILER_RT_ABI __attribute__((pcs("aapcs"))) # endif #else # define ARM_EABI_FNALIAS(aeabi_name, name) # define COMPILER_RT_ABI #endif #ifdef _MSC_VER #define ALWAYS_INLINE __forceinline #define NOINLINE __declspec(noinline) #define NORETURN __declspec(noreturn) #define UNUSED #else #define ALWAYS_INLINE __attribute__((always_inline)) #define NOINLINE __attribute__((noinline)) #define NORETURN __attribute__((noreturn)) #define UNUSED __attribute__((unused)) #endif #if defined(__NetBSD__) && (defined(_KERNEL) || defined(_STANDALONE)) /* * Kernel and boot environment can't use normal headers, * so use the equivalent system headers. */ # include # include # include #else /* Include the standard compiler builtin headers we use functionality from. */ # include # include # include # include #endif /* Include the commonly used internal type definitions. */ #include "int_types.h" /* Include internal utility function declarations. */ #include "int_util.h" /* * Workaround for LLVM bug 11663. Prevent endless recursion in * __c?zdi2(), where calls to __builtin_c?z() are expanded to * __c?zdi2() instead of __c?zsi2(). * * Instead of placing this workaround in c?zdi2.c, put it in this * global header to prevent other C files from making the detour * through __c?zdi2() as well. * * This problem has been observed on FreeBSD for sparc64 and * mips64 with GCC 4.2.1, and for riscv with GCC 5.2.0. * Presumably it's any version of GCC, and targeting an arch that * does not have dedicated bit counting instructions. */ #if defined(__FreeBSD__) && (defined(__sparc64__) || \ defined(__mips_n64) || defined(__mips_o64) || defined(__riscv__)) si_int __clzsi2(si_int); si_int __ctzsi2(si_int); #define __builtin_clz __clzsi2 #define __builtin_ctz __ctzsi2 #endif /* FreeBSD && (sparc64 || mips_n64 || mips_o64) */ COMPILER_RT_ABI si_int __paritysi2(si_int a); COMPILER_RT_ABI si_int __paritydi2(di_int a); COMPILER_RT_ABI di_int __divdi3(di_int a, di_int b); COMPILER_RT_ABI si_int __divsi3(si_int a, si_int b); COMPILER_RT_ABI su_int __udivsi3(su_int n, su_int d); COMPILER_RT_ABI su_int __udivmodsi4(su_int a, su_int b, su_int* rem); COMPILER_RT_ABI du_int __udivmoddi4(du_int a, du_int b, du_int* rem); #ifdef CRT_HAS_128BIT COMPILER_RT_ABI si_int __clzti2(ti_int a); COMPILER_RT_ABI tu_int __udivmodti4(tu_int a, tu_int b, tu_int* rem); #endif /* Definitions for builtins unavailable on MSVC */ #if defined(_MSC_VER) && !defined(__clang__) #include uint32_t __inline __builtin_ctz(uint32_t value) { - uint32_t trailing_zero = 0; + unsigned long trailing_zero = 0; if (_BitScanForward(&trailing_zero, value)) return trailing_zero; return 32; } uint32_t __inline __builtin_clz(uint32_t value) { - uint32_t leading_zero = 0; + unsigned long leading_zero = 0; if (_BitScanReverse(&leading_zero, value)) return 31 - leading_zero; return 32; } #if defined(_M_ARM) || defined(_M_X64) uint32_t __inline __builtin_clzll(uint64_t value) { - uint32_t leading_zero = 0; + unsigned long leading_zero = 0; if (_BitScanReverse64(&leading_zero, value)) return 63 - leading_zero; return 64; } #else uint32_t __inline __builtin_clzll(uint64_t value) { if (value == 0) return 64; uint32_t msh = (uint32_t)(value >> 32); uint32_t lsh = (uint32_t)(value & 0xFFFFFFFF); if (msh != 0) return __builtin_clz(msh); return 32 + __builtin_clz(lsh); } #endif #define __builtin_clzl __builtin_clzll #endif /* defined(_MSC_VER) && !defined(__clang__) */ #endif /* INT_LIB_H */ Index: projects/clang400-import/contrib/compiler-rt/lib/builtins/mingw_fixfloat.c =================================================================== --- projects/clang400-import/contrib/compiler-rt/lib/builtins/mingw_fixfloat.c (nonexistent) +++ projects/clang400-import/contrib/compiler-rt/lib/builtins/mingw_fixfloat.c (revision 311697) @@ -0,0 +1,36 @@ +/* ===-- mingw_fixfloat.c - Wrap int/float conversions for arm/windows -----=== + * + * The LLVM Compiler Infrastructure + * + * This file is dual licensed under the MIT and the University of Illinois Open + * Source Licenses. See LICENSE.TXT for details. + * + * ===----------------------------------------------------------------------=== + */ + +#include "int_lib.h" + +COMPILER_RT_ABI di_int __fixdfdi(double a); +COMPILER_RT_ABI di_int __fixsfdi(float a); +COMPILER_RT_ABI du_int __fixunsdfdi(double a); +COMPILER_RT_ABI du_int __fixunssfdi(float a); +COMPILER_RT_ABI double __floatdidf(di_int a); +COMPILER_RT_ABI float __floatdisf(di_int a); +COMPILER_RT_ABI double __floatundidf(du_int a); +COMPILER_RT_ABI float __floatundisf(du_int a); + +COMPILER_RT_ABI di_int __dtoi64(double a) { return __fixdfdi(a); } + +COMPILER_RT_ABI di_int __stoi64(float a) { return __fixsfdi(a); } + +COMPILER_RT_ABI du_int __dtou64(double a) { return __fixunsdfdi(a); } + +COMPILER_RT_ABI du_int __stou64(float a) { return __fixunssfdi(a); } + +COMPILER_RT_ABI double __i64tod(di_int a) { return __floatdidf(a); } + +COMPILER_RT_ABI float __i64tos(di_int a) { return __floatdisf(a); } + +COMPILER_RT_ABI double __u64tod(du_int a) { return __floatundidf(a); } + +COMPILER_RT_ABI float __u64tos(du_int a) { return __floatundisf(a); } Property changes on: projects/clang400-import/contrib/compiler-rt/lib/builtins/mingw_fixfloat.c ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: projects/clang400-import/contrib/compiler-rt/lib/cfi/cfi.cc =================================================================== --- projects/clang400-import/contrib/compiler-rt/lib/cfi/cfi.cc (revision 311696) +++ projects/clang400-import/contrib/compiler-rt/lib/cfi/cfi.cc (revision 311697) @@ -1,420 +1,422 @@ //===-------- cfi.cc ------------------------------------------------------===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // This file implements the runtime support for the cross-DSO CFI. // //===----------------------------------------------------------------------===// #include #include #include #include #include typedef ElfW(Phdr) Elf_Phdr; typedef ElfW(Ehdr) Elf_Ehdr; #include "interception/interception.h" #include "sanitizer_common/sanitizer_common.h" #include "sanitizer_common/sanitizer_flag_parser.h" #include "ubsan/ubsan_init.h" #include "ubsan/ubsan_flags.h" #ifdef CFI_ENABLE_DIAG #include "ubsan/ubsan_handlers.h" #endif +using namespace __sanitizer; + namespace __cfi { #define kCfiShadowLimitsStorageSize 4096 // 1 page // Lets hope that the data segment is mapped with 4K pages. // The pointer to the cfi shadow region is stored at the start of this page. // The rest of the page is unused and re-mapped read-only. static union { char space[kCfiShadowLimitsStorageSize]; struct { uptr start; uptr size; } limits; } cfi_shadow_limits_storage __attribute__((aligned(kCfiShadowLimitsStorageSize))); static constexpr uptr kShadowGranularity = 12; static constexpr uptr kShadowAlign = 1UL << kShadowGranularity; // 4096 static constexpr uint16_t kInvalidShadow = 0; static constexpr uint16_t kUncheckedShadow = 0xFFFFU; // Get the start address of the CFI shadow region. uptr GetShadow() { return cfi_shadow_limits_storage.limits.start; } uptr GetShadowSize() { return cfi_shadow_limits_storage.limits.size; } // This will only work while the shadow is not allocated. void SetShadowSize(uptr size) { cfi_shadow_limits_storage.limits.size = size; } uptr MemToShadowOffset(uptr x) { return (x >> kShadowGranularity) << 1; } uint16_t *MemToShadow(uptr x, uptr shadow_base) { return (uint16_t *)(shadow_base + MemToShadowOffset(x)); } typedef int (*CFICheckFn)(u64, void *, void *); // This class reads and decodes the shadow contents. class ShadowValue { uptr addr; uint16_t v; explicit ShadowValue(uptr addr, uint16_t v) : addr(addr), v(v) {} public: bool is_invalid() const { return v == kInvalidShadow; } bool is_unchecked() const { return v == kUncheckedShadow; } CFICheckFn get_cfi_check() const { assert(!is_invalid() && !is_unchecked()); uptr aligned_addr = addr & ~(kShadowAlign - 1); uptr p = aligned_addr - (((uptr)v - 1) << kShadowGranularity); return reinterpret_cast(p); } // Load a shadow value for the given application memory address. static const ShadowValue load(uptr addr) { uptr shadow_base = GetShadow(); uptr shadow_offset = MemToShadowOffset(addr); if (shadow_offset > GetShadowSize()) return ShadowValue(addr, kInvalidShadow); else return ShadowValue( addr, *reinterpret_cast(shadow_base + shadow_offset)); } }; class ShadowBuilder { uptr shadow_; public: // Allocate a new empty shadow (for the entire address space) on the side. void Start(); // Mark the given address range as unchecked. // This is used for uninstrumented libraries like libc. // Any CFI check with a target in that range will pass. void AddUnchecked(uptr begin, uptr end); // Mark the given address range as belonging to a library with the given // cfi_check function. void Add(uptr begin, uptr end, uptr cfi_check); // Finish shadow construction. Atomically switch the current active shadow // region with the newly constructed one and deallocate the former. void Install(); }; void ShadowBuilder::Start() { shadow_ = (uptr)MmapNoReserveOrDie(GetShadowSize(), "CFI shadow"); VReport(1, "CFI: shadow at %zx .. %zx\n", shadow_, shadow_ + GetShadowSize()); } void ShadowBuilder::AddUnchecked(uptr begin, uptr end) { uint16_t *shadow_begin = MemToShadow(begin, shadow_); uint16_t *shadow_end = MemToShadow(end - 1, shadow_) + 1; memset(shadow_begin, kUncheckedShadow, (shadow_end - shadow_begin) * sizeof(*shadow_begin)); } void ShadowBuilder::Add(uptr begin, uptr end, uptr cfi_check) { assert((cfi_check & (kShadowAlign - 1)) == 0); // Don't fill anything below cfi_check. We can not represent those addresses // in the shadow, and must make sure at codegen to place all valid call // targets above cfi_check. begin = Max(begin, cfi_check); uint16_t *s = MemToShadow(begin, shadow_); uint16_t *s_end = MemToShadow(end - 1, shadow_) + 1; uint16_t sv = ((begin - cfi_check) >> kShadowGranularity) + 1; for (; s < s_end; s++, sv++) *s = sv; } #if SANITIZER_LINUX void ShadowBuilder::Install() { MprotectReadOnly(shadow_, GetShadowSize()); uptr main_shadow = GetShadow(); if (main_shadow) { // Update. void *res = mremap((void *)shadow_, GetShadowSize(), GetShadowSize(), MREMAP_MAYMOVE | MREMAP_FIXED, (void *)main_shadow); CHECK(res != MAP_FAILED); } else { // Initial setup. CHECK_EQ(kCfiShadowLimitsStorageSize, GetPageSizeCached()); CHECK_EQ(0, GetShadow()); cfi_shadow_limits_storage.limits.start = shadow_; MprotectReadOnly((uptr)&cfi_shadow_limits_storage, sizeof(cfi_shadow_limits_storage)); CHECK_EQ(shadow_, GetShadow()); } } #else #error not implemented #endif // This is a workaround for a glibc bug: // https://sourceware.org/bugzilla/show_bug.cgi?id=15199 // Other platforms can, hopefully, just do // dlopen(RTLD_NOLOAD | RTLD_LAZY) // dlsym("__cfi_check"). uptr find_cfi_check_in_dso(dl_phdr_info *info) { const ElfW(Dyn) *dynamic = nullptr; for (int i = 0; i < info->dlpi_phnum; ++i) { if (info->dlpi_phdr[i].p_type == PT_DYNAMIC) { dynamic = (const ElfW(Dyn) *)(info->dlpi_addr + info->dlpi_phdr[i].p_vaddr); break; } } if (!dynamic) return 0; uptr strtab = 0, symtab = 0; for (const ElfW(Dyn) *p = dynamic; p->d_tag != PT_NULL; ++p) { if (p->d_tag == DT_SYMTAB) symtab = p->d_un.d_ptr; else if (p->d_tag == DT_STRTAB) strtab = p->d_un.d_ptr; } if (symtab > strtab) { VReport(1, "Can not handle: symtab > strtab (%p > %zx)\n", symtab, strtab); return 0; } // Verify that strtab and symtab are inside of the same LOAD segment. // This excludes VDSO, which has (very high) bogus strtab and symtab pointers. int phdr_idx; for (phdr_idx = 0; phdr_idx < info->dlpi_phnum; phdr_idx++) { const Elf_Phdr *phdr = &info->dlpi_phdr[phdr_idx]; if (phdr->p_type == PT_LOAD) { uptr beg = info->dlpi_addr + phdr->p_vaddr; uptr end = beg + phdr->p_memsz; if (strtab >= beg && strtab < end && symtab >= beg && symtab < end) break; } } if (phdr_idx == info->dlpi_phnum) { // Nope, either different segments or just bogus pointers. // Can not handle this. VReport(1, "Can not handle: symtab %p, strtab %zx\n", symtab, strtab); return 0; } for (const ElfW(Sym) *p = (const ElfW(Sym) *)symtab; (ElfW(Addr))p < strtab; ++p) { char *name = (char*)(strtab + p->st_name); if (strcmp(name, "__cfi_check") == 0) { assert(p->st_info == ELF32_ST_INFO(STB_GLOBAL, STT_FUNC)); uptr addr = info->dlpi_addr + p->st_value; return addr; } } return 0; } int dl_iterate_phdr_cb(dl_phdr_info *info, size_t size, void *data) { uptr cfi_check = find_cfi_check_in_dso(info); if (cfi_check) VReport(1, "Module '%s' __cfi_check %zx\n", info->dlpi_name, cfi_check); ShadowBuilder *b = reinterpret_cast(data); for (int i = 0; i < info->dlpi_phnum; i++) { const Elf_Phdr *phdr = &info->dlpi_phdr[i]; if (phdr->p_type == PT_LOAD) { // Jump tables are in the executable segment. // VTables are in the non-executable one. // Need to fill shadow for both. // FIXME: reject writable if vtables are in the r/o segment. Depend on // PT_RELRO? uptr cur_beg = info->dlpi_addr + phdr->p_vaddr; uptr cur_end = cur_beg + phdr->p_memsz; if (cfi_check) { VReport(1, " %zx .. %zx\n", cur_beg, cur_end); b->Add(cur_beg, cur_end, cfi_check); } else { b->AddUnchecked(cur_beg, cur_end); } } } return 0; } // Init or update shadow for the current set of loaded libraries. void UpdateShadow() { ShadowBuilder b; b.Start(); dl_iterate_phdr(dl_iterate_phdr_cb, &b); b.Install(); } void InitShadow() { CHECK_EQ(0, GetShadow()); CHECK_EQ(0, GetShadowSize()); uptr vma = GetMaxVirtualAddress(); // Shadow is 2 -> 2**kShadowGranularity. SetShadowSize((vma >> (kShadowGranularity - 1)) + 1); VReport(1, "CFI: VMA size %zx, shadow size %zx\n", vma, GetShadowSize()); UpdateShadow(); } THREADLOCAL int in_loader; BlockingMutex shadow_update_lock(LINKER_INITIALIZED); void EnterLoader() { if (in_loader == 0) { shadow_update_lock.Lock(); } ++in_loader; } void ExitLoader() { CHECK(in_loader > 0); --in_loader; UpdateShadow(); if (in_loader == 0) { shadow_update_lock.Unlock(); } } ALWAYS_INLINE void CfiSlowPathCommon(u64 CallSiteTypeId, void *Ptr, void *DiagData) { uptr Addr = (uptr)Ptr; VReport(3, "__cfi_slowpath: %llx, %p\n", CallSiteTypeId, Ptr); ShadowValue sv = ShadowValue::load(Addr); if (sv.is_invalid()) { VReport(1, "CFI: invalid memory region for a check target: %p\n", Ptr); #ifdef CFI_ENABLE_DIAG if (DiagData) { __ubsan_handle_cfi_check_fail( reinterpret_cast<__ubsan::CFICheckFailData *>(DiagData), Addr, false); return; } #endif Trap(); } if (sv.is_unchecked()) { VReport(2, "CFI: unchecked call (shadow=FFFF): %p\n", Ptr); return; } CFICheckFn cfi_check = sv.get_cfi_check(); VReport(2, "__cfi_check at %p\n", cfi_check); cfi_check(CallSiteTypeId, Ptr, DiagData); } void InitializeFlags() { SetCommonFlagsDefaults(); #ifdef CFI_ENABLE_DIAG __ubsan::Flags *uf = __ubsan::flags(); uf->SetDefaults(); #endif FlagParser cfi_parser; RegisterCommonFlags(&cfi_parser); cfi_parser.ParseString(GetEnv("CFI_OPTIONS")); #ifdef CFI_ENABLE_DIAG FlagParser ubsan_parser; __ubsan::RegisterUbsanFlags(&ubsan_parser, uf); RegisterCommonFlags(&ubsan_parser); const char *ubsan_default_options = __ubsan::MaybeCallUbsanDefaultOptions(); ubsan_parser.ParseString(ubsan_default_options); ubsan_parser.ParseString(GetEnv("UBSAN_OPTIONS")); #endif InitializeCommonFlags(); if (Verbosity()) ReportUnrecognizedFlags(); if (common_flags()->help) { cfi_parser.PrintFlagDescriptions(); } } } // namespace __cfi using namespace __cfi; extern "C" SANITIZER_INTERFACE_ATTRIBUTE void __cfi_slowpath(u64 CallSiteTypeId, void *Ptr) { CfiSlowPathCommon(CallSiteTypeId, Ptr, nullptr); } #ifdef CFI_ENABLE_DIAG extern "C" SANITIZER_INTERFACE_ATTRIBUTE void __cfi_slowpath_diag(u64 CallSiteTypeId, void *Ptr, void *DiagData) { CfiSlowPathCommon(CallSiteTypeId, Ptr, DiagData); } #endif // Setup shadow for dlopen()ed libraries. // The actual shadow setup happens after dlopen() returns, which means that // a library can not be a target of any CFI checks while its constructors are // running. It's unclear how to fix this without some extra help from libc. // In glibc, mmap inside dlopen is not interceptable. // Maybe a seccomp-bpf filter? // We could insert a high-priority constructor into the library, but that would // not help with the uninstrumented libraries. INTERCEPTOR(void*, dlopen, const char *filename, int flag) { EnterLoader(); void *handle = REAL(dlopen)(filename, flag); ExitLoader(); return handle; } INTERCEPTOR(int, dlclose, void *handle) { EnterLoader(); int res = REAL(dlclose)(handle); ExitLoader(); return res; } extern "C" SANITIZER_INTERFACE_ATTRIBUTE #if !SANITIZER_CAN_USE_PREINIT_ARRAY // On ELF platforms, the constructor is invoked using .preinit_array (see below) __attribute__((constructor(0))) #endif void __cfi_init() { SanitizerToolName = "CFI"; InitializeFlags(); InitShadow(); INTERCEPT_FUNCTION(dlopen); INTERCEPT_FUNCTION(dlclose); #ifdef CFI_ENABLE_DIAG __ubsan::InitAsPlugin(); #endif } #if SANITIZER_CAN_USE_PREINIT_ARRAY // On ELF platforms, run cfi initialization before any other constructors. // On other platforms we use the constructor attribute to arrange to run our // initialization early. extern "C" { __attribute__((section(".preinit_array"), used)) void (*__cfi_preinit)(void) = __cfi_init; } #endif Index: projects/clang400-import/contrib/compiler-rt/lib/dfsan/dfsan.cc =================================================================== --- projects/clang400-import/contrib/compiler-rt/lib/dfsan/dfsan.cc (revision 311696) +++ projects/clang400-import/contrib/compiler-rt/lib/dfsan/dfsan.cc (revision 311697) @@ -1,430 +1,451 @@ //===-- dfsan.cc ----------------------------------------------------------===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // This file is a part of DataFlowSanitizer. // // DataFlowSanitizer runtime. This file defines the public interface to // DataFlowSanitizer as well as the definition of certain runtime functions // called automatically by the compiler (specifically the instrumentation pass // in llvm/lib/Transforms/Instrumentation/DataFlowSanitizer.cpp). // // The public interface is defined in include/sanitizer/dfsan_interface.h whose // functions are prefixed dfsan_ while the compiler interface functions are // prefixed __dfsan_. //===----------------------------------------------------------------------===// #include "sanitizer_common/sanitizer_atomic.h" #include "sanitizer_common/sanitizer_common.h" #include "sanitizer_common/sanitizer_flags.h" #include "sanitizer_common/sanitizer_flag_parser.h" #include "sanitizer_common/sanitizer_libc.h" #include "dfsan/dfsan.h" using namespace __dfsan; typedef atomic_uint16_t atomic_dfsan_label; static const dfsan_label kInitializingLabel = -1; static const uptr kNumLabels = 1 << (sizeof(dfsan_label) * 8); static atomic_dfsan_label __dfsan_last_label; static dfsan_label_info __dfsan_label_info[kNumLabels]; Flags __dfsan::flags_data; SANITIZER_INTERFACE_ATTRIBUTE THREADLOCAL dfsan_label __dfsan_retval_tls; SANITIZER_INTERFACE_ATTRIBUTE THREADLOCAL dfsan_label __dfsan_arg_tls[64]; SANITIZER_INTERFACE_ATTRIBUTE uptr __dfsan_shadow_ptr_mask; // On Linux/x86_64, memory is laid out as follows: // // +--------------------+ 0x800000000000 (top of memory) // | application memory | // +--------------------+ 0x700000008000 (kAppAddr) // | | // | unused | // | | // +--------------------+ 0x200200000000 (kUnusedAddr) // | union table | // +--------------------+ 0x200000000000 (kUnionTableAddr) // | shadow memory | // +--------------------+ 0x000000010000 (kShadowAddr) // | reserved by kernel | // +--------------------+ 0x000000000000 // // To derive a shadow memory address from an application memory address, // bits 44-46 are cleared to bring the address into the range // [0x000000008000,0x100000000000). Then the address is shifted left by 1 to // account for the double byte representation of shadow labels and move the // address into the shadow memory range. See the function shadow_for below. // On Linux/MIPS64, memory is laid out as follows: // // +--------------------+ 0x10000000000 (top of memory) // | application memory | // +--------------------+ 0xF000008000 (kAppAddr) // | | // | unused | // | | // +--------------------+ 0x2200000000 (kUnusedAddr) // | union table | // +--------------------+ 0x2000000000 (kUnionTableAddr) // | shadow memory | // +--------------------+ 0x0000010000 (kShadowAddr) // | reserved by kernel | // +--------------------+ 0x0000000000 // On Linux/AArch64 (39-bit VMA), memory is laid out as follow: // // +--------------------+ 0x8000000000 (top of memory) // | application memory | // +--------------------+ 0x7000008000 (kAppAddr) // | | // | unused | // | | // +--------------------+ 0x1200000000 (kUnusedAddr) // | union table | // +--------------------+ 0x1000000000 (kUnionTableAddr) // | shadow memory | // +--------------------+ 0x0000010000 (kShadowAddr) // | reserved by kernel | // +--------------------+ 0x0000000000 // On Linux/AArch64 (42-bit VMA), memory is laid out as follow: // // +--------------------+ 0x40000000000 (top of memory) // | application memory | // +--------------------+ 0x3ff00008000 (kAppAddr) // | | // | unused | // | | // +--------------------+ 0x1200000000 (kUnusedAddr) // | union table | // +--------------------+ 0x8000000000 (kUnionTableAddr) // | shadow memory | // +--------------------+ 0x0000010000 (kShadowAddr) // | reserved by kernel | // +--------------------+ 0x0000000000 +// On Linux/AArch64 (48-bit VMA), memory is laid out as follow: +// +// +--------------------+ 0x1000000000000 (top of memory) +// | application memory | +// +--------------------+ 0xffff00008000 (kAppAddr) +// | unused | +// +--------------------+ 0xaaaab0000000 (top of PIE address) +// | application PIE | +// +--------------------+ 0xaaaaa0000000 (top of PIE address) +// | | +// | unused | +// | | +// +--------------------+ 0x1200000000 (kUnusedAddr) +// | union table | +// +--------------------+ 0x8000000000 (kUnionTableAddr) +// | shadow memory | +// +--------------------+ 0x0000010000 (kShadowAddr) +// | reserved by kernel | +// +--------------------+ 0x0000000000 + typedef atomic_dfsan_label dfsan_union_table_t[kNumLabels][kNumLabels]; #ifdef DFSAN_RUNTIME_VMA // Runtime detected VMA size. int __dfsan::vmaSize; #endif static uptr UnusedAddr() { return MappingArchImpl() + sizeof(dfsan_union_table_t); } static atomic_dfsan_label *union_table(dfsan_label l1, dfsan_label l2) { return &(*(dfsan_union_table_t *) UnionTableAddr())[l1][l2]; } // Checks we do not run out of labels. static void dfsan_check_label(dfsan_label label) { if (label == kInitializingLabel) { Report("FATAL: DataFlowSanitizer: out of labels\n"); Die(); } } // Resolves the union of two unequal labels. Nonequality is a precondition for // this function (the instrumentation pass inlines the equality test). extern "C" SANITIZER_INTERFACE_ATTRIBUTE dfsan_label __dfsan_union(dfsan_label l1, dfsan_label l2) { DCHECK_NE(l1, l2); if (l1 == 0) return l2; if (l2 == 0) return l1; if (l1 > l2) Swap(l1, l2); atomic_dfsan_label *table_ent = union_table(l1, l2); // We need to deal with the case where two threads concurrently request // a union of the same pair of labels. If the table entry is uninitialized, // (i.e. 0) use a compare-exchange to set the entry to kInitializingLabel // (i.e. -1) to mark that we are initializing it. dfsan_label label = 0; if (atomic_compare_exchange_strong(table_ent, &label, kInitializingLabel, memory_order_acquire)) { // Check whether l2 subsumes l1. We don't need to check whether l1 // subsumes l2 because we are guaranteed here that l1 < l2, and (at least // in the cases we are interested in) a label may only subsume labels // created earlier (i.e. with a lower numerical value). if (__dfsan_label_info[l2].l1 == l1 || __dfsan_label_info[l2].l2 == l1) { label = l2; } else { label = atomic_fetch_add(&__dfsan_last_label, 1, memory_order_relaxed) + 1; dfsan_check_label(label); __dfsan_label_info[label].l1 = l1; __dfsan_label_info[label].l2 = l2; } atomic_store(table_ent, label, memory_order_release); } else if (label == kInitializingLabel) { // Another thread is initializing the entry. Wait until it is finished. do { internal_sched_yield(); label = atomic_load(table_ent, memory_order_acquire); } while (label == kInitializingLabel); } return label; } extern "C" SANITIZER_INTERFACE_ATTRIBUTE dfsan_label __dfsan_union_load(const dfsan_label *ls, uptr n) { dfsan_label label = ls[0]; for (uptr i = 1; i != n; ++i) { dfsan_label next_label = ls[i]; if (label != next_label) label = __dfsan_union(label, next_label); } return label; } extern "C" SANITIZER_INTERFACE_ATTRIBUTE void __dfsan_unimplemented(char *fname) { if (flags().warn_unimplemented) Report("WARNING: DataFlowSanitizer: call to uninstrumented function %s\n", fname); } // Use '-mllvm -dfsan-debug-nonzero-labels' and break on this function // to try to figure out where labels are being introduced in a nominally // label-free program. extern "C" SANITIZER_INTERFACE_ATTRIBUTE void __dfsan_nonzero_label() { if (flags().warn_nonzero_labels) Report("WARNING: DataFlowSanitizer: saw nonzero label\n"); } // Indirect call to an uninstrumented vararg function. We don't have a way of // handling these at the moment. extern "C" SANITIZER_INTERFACE_ATTRIBUTE void __dfsan_vararg_wrapper(const char *fname) { Report("FATAL: DataFlowSanitizer: unsupported indirect call to vararg " "function %s\n", fname); Die(); } // Like __dfsan_union, but for use from the client or custom functions. Hence // the equality comparison is done here before calling __dfsan_union. SANITIZER_INTERFACE_ATTRIBUTE dfsan_label dfsan_union(dfsan_label l1, dfsan_label l2) { if (l1 == l2) return l1; return __dfsan_union(l1, l2); } extern "C" SANITIZER_INTERFACE_ATTRIBUTE dfsan_label dfsan_create_label(const char *desc, void *userdata) { dfsan_label label = atomic_fetch_add(&__dfsan_last_label, 1, memory_order_relaxed) + 1; dfsan_check_label(label); __dfsan_label_info[label].l1 = __dfsan_label_info[label].l2 = 0; __dfsan_label_info[label].desc = desc; __dfsan_label_info[label].userdata = userdata; return label; } extern "C" SANITIZER_INTERFACE_ATTRIBUTE void __dfsan_set_label(dfsan_label label, void *addr, uptr size) { for (dfsan_label *labelp = shadow_for(addr); size != 0; --size, ++labelp) { // Don't write the label if it is already the value we need it to be. // In a program where most addresses are not labeled, it is common that // a page of shadow memory is entirely zeroed. The Linux copy-on-write // implementation will share all of the zeroed pages, making a copy of a // page when any value is written. The un-sharing will happen even if // the value written does not change the value in memory. Avoiding the // write when both |label| and |*labelp| are zero dramatically reduces // the amount of real memory used by large programs. if (label == *labelp) continue; *labelp = label; } } SANITIZER_INTERFACE_ATTRIBUTE void dfsan_set_label(dfsan_label label, void *addr, uptr size) { __dfsan_set_label(label, addr, size); } SANITIZER_INTERFACE_ATTRIBUTE void dfsan_add_label(dfsan_label label, void *addr, uptr size) { for (dfsan_label *labelp = shadow_for(addr); size != 0; --size, ++labelp) if (*labelp != label) *labelp = __dfsan_union(*labelp, label); } // Unlike the other dfsan interface functions the behavior of this function // depends on the label of one of its arguments. Hence it is implemented as a // custom function. extern "C" SANITIZER_INTERFACE_ATTRIBUTE dfsan_label __dfsw_dfsan_get_label(long data, dfsan_label data_label, dfsan_label *ret_label) { *ret_label = 0; return data_label; } SANITIZER_INTERFACE_ATTRIBUTE dfsan_label dfsan_read_label(const void *addr, uptr size) { if (size == 0) return 0; return __dfsan_union_load(shadow_for(addr), size); } extern "C" SANITIZER_INTERFACE_ATTRIBUTE const struct dfsan_label_info *dfsan_get_label_info(dfsan_label label) { return &__dfsan_label_info[label]; } extern "C" SANITIZER_INTERFACE_ATTRIBUTE int dfsan_has_label(dfsan_label label, dfsan_label elem) { if (label == elem) return true; const dfsan_label_info *info = dfsan_get_label_info(label); if (info->l1 != 0) { return dfsan_has_label(info->l1, elem) || dfsan_has_label(info->l2, elem); } else { return false; } } extern "C" SANITIZER_INTERFACE_ATTRIBUTE dfsan_label dfsan_has_label_with_desc(dfsan_label label, const char *desc) { const dfsan_label_info *info = dfsan_get_label_info(label); if (info->l1 != 0) { return dfsan_has_label_with_desc(info->l1, desc) || dfsan_has_label_with_desc(info->l2, desc); } else { return internal_strcmp(desc, info->desc) == 0; } } extern "C" SANITIZER_INTERFACE_ATTRIBUTE uptr dfsan_get_label_count(void) { dfsan_label max_label_allocated = atomic_load(&__dfsan_last_label, memory_order_relaxed); return static_cast(max_label_allocated); } extern "C" SANITIZER_INTERFACE_ATTRIBUTE void dfsan_dump_labels(int fd) { dfsan_label last_label = atomic_load(&__dfsan_last_label, memory_order_relaxed); for (uptr l = 1; l <= last_label; ++l) { char buf[64]; internal_snprintf(buf, sizeof(buf), "%u %u %u ", l, __dfsan_label_info[l].l1, __dfsan_label_info[l].l2); WriteToFile(fd, buf, internal_strlen(buf)); if (__dfsan_label_info[l].l1 == 0 && __dfsan_label_info[l].desc) { WriteToFile(fd, __dfsan_label_info[l].desc, internal_strlen(__dfsan_label_info[l].desc)); } WriteToFile(fd, "\n", 1); } } void Flags::SetDefaults() { #define DFSAN_FLAG(Type, Name, DefaultValue, Description) Name = DefaultValue; #include "dfsan_flags.inc" #undef DFSAN_FLAG } static void RegisterDfsanFlags(FlagParser *parser, Flags *f) { #define DFSAN_FLAG(Type, Name, DefaultValue, Description) \ RegisterFlag(parser, #Name, Description, &f->Name); #include "dfsan_flags.inc" #undef DFSAN_FLAG } static void InitializeFlags() { SetCommonFlagsDefaults(); flags().SetDefaults(); FlagParser parser; RegisterCommonFlags(&parser); RegisterDfsanFlags(&parser, &flags()); parser.ParseString(GetEnv("DFSAN_OPTIONS")); InitializeCommonFlags(); if (Verbosity()) ReportUnrecognizedFlags(); if (common_flags()->help) parser.PrintFlagDescriptions(); } static void InitializePlatformEarly() { AvoidCVE_2016_2143(); #ifdef DFSAN_RUNTIME_VMA __dfsan::vmaSize = (MostSignificantSetBitIndex(GET_CURRENT_FRAME()) + 1); - if (__dfsan::vmaSize == 39 || __dfsan::vmaSize == 42) { + if (__dfsan::vmaSize == 39 || __dfsan::vmaSize == 42 || + __dfsan::vmaSize == 48) { __dfsan_shadow_ptr_mask = ShadowMask(); } else { Printf("FATAL: DataFlowSanitizer: unsupported VMA range\n"); - Printf("FATAL: Found %d - Supported 39 and 42\n", __dfsan::vmaSize); + Printf("FATAL: Found %d - Supported 39, 42, and 48\n", __dfsan::vmaSize); Die(); } #endif } static void dfsan_fini() { if (internal_strcmp(flags().dump_labels_at_exit, "") != 0) { fd_t fd = OpenFile(flags().dump_labels_at_exit, WrOnly); if (fd == kInvalidFd) { Report("WARNING: DataFlowSanitizer: unable to open output file %s\n", flags().dump_labels_at_exit); return; } Report("INFO: DataFlowSanitizer: dumping labels to %s\n", flags().dump_labels_at_exit); dfsan_dump_labels(fd); CloseFile(fd); } } static void dfsan_init(int argc, char **argv, char **envp) { InitializeFlags(); InitializePlatformEarly(); MmapFixedNoReserve(ShadowAddr(), UnusedAddr() - ShadowAddr()); // Protect the region of memory we don't use, to preserve the one-to-one // mapping from application to shadow memory. But if ASLR is disabled, Linux // will load our executable in the middle of our unused region. This mostly // works so long as the program doesn't use too much memory. We support this // case by disabling memory protection when ASLR is disabled. uptr init_addr = (uptr)&dfsan_init; if (!(init_addr >= UnusedAddr() && init_addr < AppAddr())) MmapFixedNoAccess(UnusedAddr(), AppAddr() - UnusedAddr()); InitializeInterceptors(); // Register the fini callback to run when the program terminates successfully // or it is killed by the runtime. Atexit(dfsan_fini); AddDieCallback(dfsan_fini); __dfsan_label_info[kInitializingLabel].desc = ""; } #if SANITIZER_CAN_USE_PREINIT_ARRAY __attribute__((section(".preinit_array"), used)) static void (*dfsan_init_ptr)(int, char **, char **) = dfsan_init; #endif Index: projects/clang400-import/contrib/compiler-rt/lib/dfsan/dfsan.h =================================================================== --- projects/clang400-import/contrib/compiler-rt/lib/dfsan/dfsan.h (revision 311696) +++ projects/clang400-import/contrib/compiler-rt/lib/dfsan/dfsan.h (revision 311697) @@ -1,70 +1,73 @@ //===-- dfsan.h -------------------------------------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // This file is a part of DataFlowSanitizer. // // Private DFSan header. //===----------------------------------------------------------------------===// #ifndef DFSAN_H #define DFSAN_H #include "sanitizer_common/sanitizer_internal_defs.h" #include "dfsan_platform.h" +using __sanitizer::uptr; +using __sanitizer::u16; + // Copy declarations from public sanitizer/dfsan_interface.h header here. typedef u16 dfsan_label; struct dfsan_label_info { dfsan_label l1; dfsan_label l2; const char *desc; void *userdata; }; extern "C" { void dfsan_add_label(dfsan_label label, void *addr, uptr size); void dfsan_set_label(dfsan_label label, void *addr, uptr size); dfsan_label dfsan_read_label(const void *addr, uptr size); dfsan_label dfsan_union(dfsan_label l1, dfsan_label l2); } // extern "C" template void dfsan_set_label(dfsan_label label, T &data) { // NOLINT dfsan_set_label(label, (void *)&data, sizeof(T)); } namespace __dfsan { void InitializeInterceptors(); inline dfsan_label *shadow_for(void *ptr) { return (dfsan_label *) ((((uptr) ptr) & ShadowMask()) << 1); } inline const dfsan_label *shadow_for(const void *ptr) { return shadow_for(const_cast(ptr)); } struct Flags { #define DFSAN_FLAG(Type, Name, DefaultValue, Description) Type Name; #include "dfsan_flags.inc" #undef DFSAN_FLAG void SetDefaults(); }; extern Flags flags_data; inline Flags &flags() { return flags_data; } } // namespace __dfsan #endif // DFSAN_H Index: projects/clang400-import/contrib/compiler-rt/lib/dfsan/dfsan_interceptors.cc =================================================================== --- projects/clang400-import/contrib/compiler-rt/lib/dfsan/dfsan_interceptors.cc (revision 311696) +++ projects/clang400-import/contrib/compiler-rt/lib/dfsan/dfsan_interceptors.cc (revision 311697) @@ -1,44 +1,46 @@ //===-- dfsan_interceptors.cc ---------------------------------------------===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // This file is a part of DataFlowSanitizer. // // Interceptors for standard library functions. //===----------------------------------------------------------------------===// #include "dfsan/dfsan.h" #include "interception/interception.h" #include "sanitizer_common/sanitizer_common.h" +using namespace __sanitizer; + INTERCEPTOR(void *, mmap, void *addr, SIZE_T length, int prot, int flags, int fd, OFF_T offset) { void *res = REAL(mmap)(addr, length, prot, flags, fd, offset); if (res != (void*)-1) dfsan_set_label(0, res, RoundUpTo(length, GetPageSize())); return res; } INTERCEPTOR(void *, mmap64, void *addr, SIZE_T length, int prot, int flags, int fd, OFF64_T offset) { void *res = REAL(mmap64)(addr, length, prot, flags, fd, offset); if (res != (void*)-1) dfsan_set_label(0, res, RoundUpTo(length, GetPageSize())); return res; } namespace __dfsan { void InitializeInterceptors() { static int inited = 0; CHECK_EQ(inited, 0); INTERCEPT_FUNCTION(mmap); INTERCEPT_FUNCTION(mmap64); inited = 1; } } // namespace __dfsan Index: projects/clang400-import/contrib/compiler-rt/lib/dfsan/dfsan_platform.h =================================================================== --- projects/clang400-import/contrib/compiler-rt/lib/dfsan/dfsan_platform.h (revision 311696) +++ projects/clang400-import/contrib/compiler-rt/lib/dfsan/dfsan_platform.h (revision 311697) @@ -1,107 +1,116 @@ //===-- dfsan_platform.h ----------------------------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // This file is a part of DataFlowSanitizer. // // Platform specific information for DFSan. //===----------------------------------------------------------------------===// #ifndef DFSAN_PLATFORM_H #define DFSAN_PLATFORM_H namespace __dfsan { #if defined(__x86_64__) struct Mapping { static const uptr kShadowAddr = 0x10000; static const uptr kUnionTableAddr = 0x200000000000; static const uptr kAppAddr = 0x700000008000; static const uptr kShadowMask = ~0x700000000000; }; #elif defined(__mips64) struct Mapping { static const uptr kShadowAddr = 0x10000; static const uptr kUnionTableAddr = 0x2000000000; static const uptr kAppAddr = 0xF000008000; static const uptr kShadowMask = ~0xF000000000; }; #elif defined(__aarch64__) struct Mapping39 { static const uptr kShadowAddr = 0x10000; static const uptr kUnionTableAddr = 0x1000000000; static const uptr kAppAddr = 0x7000008000; static const uptr kShadowMask = ~0x7800000000; }; struct Mapping42 { static const uptr kShadowAddr = 0x10000; static const uptr kUnionTableAddr = 0x8000000000; static const uptr kAppAddr = 0x3ff00008000; static const uptr kShadowMask = ~0x3c000000000; }; +struct Mapping48 { + static const uptr kShadowAddr = 0x10000; + static const uptr kUnionTableAddr = 0x8000000000; + static const uptr kAppAddr = 0xffff00008000; + static const uptr kShadowMask = ~0xfffff0000000; +}; + extern int vmaSize; # define DFSAN_RUNTIME_VMA 1 #else # error "DFSan not supported for this platform!" #endif enum MappingType { MAPPING_SHADOW_ADDR, MAPPING_UNION_TABLE_ADDR, MAPPING_APP_ADDR, MAPPING_SHADOW_MASK }; template uptr MappingImpl(void) { switch (Type) { case MAPPING_SHADOW_ADDR: return Mapping::kShadowAddr; case MAPPING_UNION_TABLE_ADDR: return Mapping::kUnionTableAddr; case MAPPING_APP_ADDR: return Mapping::kAppAddr; case MAPPING_SHADOW_MASK: return Mapping::kShadowMask; } } template uptr MappingArchImpl(void) { #ifdef __aarch64__ - if (vmaSize == 39) - return MappingImpl(); - else - return MappingImpl(); + switch (vmaSize) { + case 39: return MappingImpl(); + case 42: return MappingImpl(); + case 48: return MappingImpl(); + } DCHECK(0); + return 0; #else return MappingImpl(); #endif } ALWAYS_INLINE uptr ShadowAddr() { return MappingArchImpl(); } ALWAYS_INLINE uptr UnionTableAddr() { return MappingArchImpl(); } ALWAYS_INLINE uptr AppAddr() { return MappingArchImpl(); } ALWAYS_INLINE uptr ShadowMask() { return MappingArchImpl(); } } // namespace __dfsan #endif Index: projects/clang400-import/contrib/compiler-rt/lib/dfsan/done_abilist.txt =================================================================== --- projects/clang400-import/contrib/compiler-rt/lib/dfsan/done_abilist.txt (revision 311696) +++ projects/clang400-import/contrib/compiler-rt/lib/dfsan/done_abilist.txt (revision 311697) @@ -1,306 +1,314 @@ fun:main=uninstrumented fun:main=discard ############################################################################### # DFSan interface functions ############################################################################### fun:dfsan_union=uninstrumented fun:dfsan_union=discard fun:dfsan_create_label=uninstrumented fun:dfsan_create_label=discard fun:dfsan_set_label=uninstrumented fun:dfsan_set_label=discard fun:dfsan_add_label=uninstrumented fun:dfsan_add_label=discard fun:dfsan_get_label=uninstrumented fun:dfsan_get_label=custom fun:dfsan_read_label=uninstrumented fun:dfsan_read_label=discard fun:dfsan_get_label_count=uninstrumented fun:dfsan_get_label_count=discard fun:dfsan_get_label_info=uninstrumented fun:dfsan_get_label_info=discard fun:dfsan_has_label=uninstrumented fun:dfsan_has_label=discard fun:dfsan_has_label_with_desc=uninstrumented fun:dfsan_has_label_with_desc=discard fun:dfsan_set_write_callback=uninstrumented fun:dfsan_set_write_callback=custom ############################################################################### # glibc ############################################################################### fun:malloc=discard fun:realloc=discard fun:free=discard # Functions that return a value that depends on the input, but the output might # not be necessarily data-dependent on the input. fun:isalpha=functional fun:isdigit=functional fun:isprint=functional fun:isxdigit=functional fun:isalnum=functional fun:ispunct=functional fun:isspace=functional fun:tolower=functional fun:toupper=functional # Functions that return a value that is data-dependent on the input. fun:btowc=functional fun:exp=functional fun:exp2=functional fun:fabs=functional fun:finite=functional fun:floor=functional fun:fmod=functional fun:isinf=functional fun:isnan=functional fun:log=functional fun:modf=functional fun:pow=functional fun:round=functional fun:sqrt=functional fun:wctob=functional # Functions that produce an output that does not depend on the input (shadow is # zeroed automatically). fun:__assert_fail=discard fun:__ctype_b_loc=discard fun:__cxa_atexit=discard fun:__errno_location=discard fun:__newlocale=discard fun:__sbrk=discard fun:__sigsetjmp=discard fun:__uselocale=discard fun:__wctype_l=discard fun:access=discard fun:alarm=discard fun:atexit=discard fun:bind=discard fun:chdir=discard fun:close=discard fun:closedir=discard fun:connect=discard fun:dladdr=discard fun:dlclose=discard fun:fclose=discard fun:feof=discard fun:ferror=discard fun:fflush=discard fun:fileno=discard fun:fopen=discard fun:fprintf=discard fun:fputc=discard fun:fputc=discard fun:fputs=discard fun:fputs=discard fun:fseek=discard fun:ftell=discard fun:fwrite=discard fun:getenv=discard fun:getuid=discard fun:geteuid=discard fun:getpagesize=discard fun:getpid=discard fun:kill=discard fun:listen=discard fun:lseek=discard fun:mkdir=discard fun:mmap=discard fun:munmap=discard fun:open=discard fun:pipe=discard fun:posix_fadvise=discard fun:posix_memalign=discard fun:prctl=discard fun:printf=discard fun:pthread_sigmask=discard fun:putc=discard fun:putchar=discard fun:puts=discard fun:rand=discard fun:random=discard fun:remove=discard fun:sched_getcpu=discard fun:sched_get_priority_max=discard fun:sched_setaffinity=discard fun:sched_yield=discard fun:sem_destroy=discard fun:sem_init=discard fun:sem_post=discard fun:sem_wait=discard fun:send=discard fun:sendmsg=discard fun:sendto=discard fun:setsockopt=discard fun:shutdown=discard fun:sleep=discard fun:socket=discard fun:strerror=discard fun:strspn=discard fun:strcspn=discard fun:symlink=discard fun:syscall=discard fun:unlink=discard fun:uselocale=discard # Functions that produce output does not depend on the input (need to zero the # shadow manually). fun:calloc=custom fun:clock_gettime=custom fun:dlopen=custom fun:fgets=custom fun:fstat=custom fun:getcwd=custom fun:get_current_dir_name=custom fun:gethostname=custom fun:getrlimit=custom fun:getrusage=custom fun:nanosleep=custom fun:pread=custom fun:read=custom fun:socketpair=custom fun:stat=custom fun:time=custom # Functions that produce an output that depend on the input (propagate the # shadow manually). fun:ctime_r=custom fun:inet_pton=custom fun:localtime_r=custom fun:memcpy=custom fun:memset=custom fun:strcpy=custom fun:strdup=custom fun:strncpy=custom fun:strtod=custom fun:strtol=custom fun:strtoll=custom fun:strtoul=custom fun:strtoull=custom # Functions that produce an output that is computed from the input, but is not # necessarily data dependent. fun:memchr=custom fun:memcmp=custom fun:strcasecmp=custom fun:strchr=custom fun:strcmp=custom fun:strlen=custom fun:strncasecmp=custom fun:strncmp=custom fun:strrchr=custom fun:strstr=custom # Functions which take action based on global state, such as running a callback # set by a sepperate function. fun:write=custom # Functions that take a callback (wrap the callback manually). fun:dl_iterate_phdr=custom fun:getpwuid_r=custom fun:poll=custom fun:sched_getaffinity=custom fun:select=custom fun:sigemptyset=custom fun:sigaction=custom fun:gettimeofday=custom # sprintf-like fun:sprintf=custom fun:snprintf=custom # TODO: custom fun:asprintf=discard fun:qsort=discard ############################################################################### # pthread ############################################################################### fun:pthread_equal=discard fun:pthread_getspecific=discard fun:pthread_key_create=discard fun:pthread_key_delete=discard fun:pthread_mutex_destroy=discard fun:pthread_mutex_init=discard fun:pthread_mutex_lock=discard fun:pthread_mutex_trylock=discard fun:pthread_mutex_unlock=discard fun:pthread_mutexattr_destroy=discard fun:pthread_mutexattr_init=discard fun:pthread_mutexattr_settype=discard fun:pthread_once=discard fun:pthread_self=discard fun:pthread_setspecific=discard # Functions that take a callback (wrap the callback manually). fun:pthread_create=custom ############################################################################### # libffi/libgo ############################################################################### # Functions that are written in asm or are called from asm. fun:ffi_call_unix64=uninstrumented fun:ffi_call_unix64=discard fun:ffi_closure_unix64_inner=uninstrumented fun:ffi_closure_unix64_inner=discard fun:ffi_closure_unix64=uninstrumented fun:ffi_closure_unix64=discard fun:__go_get_closure=uninstrumented fun:__go_get_closure=discard fun:__go_makefunc_can_recover=uninstrumented fun:__go_makefunc_can_recover=discard fun:__go_makefunc_returning=uninstrumented fun:__go_makefunc_returning=discard fun:reflect.MakeFuncStubGo=uninstrumented fun:reflect.MakeFuncStubGo=discard fun:reflect.makeFuncStub=uninstrumented fun:reflect.makeFuncStub=discard ############################################################################### # lib/Fuzzer ############################################################################### # Replaces __sanitizer_cov_trace_cmp with __dfsw___sanitizer_cov_trace_cmp fun:__sanitizer_cov_trace_cmp=custom fun:__sanitizer_cov_trace_cmp=uninstrumented +fun:__sanitizer_cov_trace_cmp1=custom +fun:__sanitizer_cov_trace_cmp1=uninstrumented +fun:__sanitizer_cov_trace_cmp2=custom +fun:__sanitizer_cov_trace_cmp2=uninstrumented +fun:__sanitizer_cov_trace_cmp4=custom +fun:__sanitizer_cov_trace_cmp4=uninstrumented +fun:__sanitizer_cov_trace_cmp8=custom +fun:__sanitizer_cov_trace_cmp8=uninstrumented # Similar for __sanitizer_cov_trace_switch fun:__sanitizer_cov_trace_switch=custom fun:__sanitizer_cov_trace_switch=uninstrumented # Ignores all other __sanitizer callbacks. fun:__sanitizer_cov=uninstrumented fun:__sanitizer_cov=discard fun:__sanitizer_cov_module_init=uninstrumented fun:__sanitizer_cov_module_init=discard fun:__sanitizer_cov_with_check=uninstrumented fun:__sanitizer_cov_with_check=discard fun:__sanitizer_cov_indir_call16=uninstrumented fun:__sanitizer_cov_indir_call16=discard fun:__sanitizer_cov_indir_call16=uninstrumented fun:__sanitizer_cov_indir_call16=discard fun:__sanitizer_reset_coverage=uninstrumented fun:__sanitizer_reset_coverage=discard fun:__sanitizer_set_death_callback=uninstrumented fun:__sanitizer_set_death_callback=discard fun:__sanitizer_get_coverage_guards=uninstrumented fun:__sanitizer_get_coverage_guards=discard fun:__sanitizer_get_number_of_counters=uninstrumented fun:__sanitizer_get_number_of_counters=discard fun:__sanitizer_update_counter_bitset_and_clear_counters=uninstrumented fun:__sanitizer_update_counter_bitset_and_clear_counters=discard fun:__sanitizer_get_total_unique_coverage=uninstrumented fun:__sanitizer_get_total_unique_coverage=discard fun:__sanitizer_get_total_unique_coverage=uninstrumented fun:__sanitizer_get_total_unique_coverage=discard fun:__sanitizer_update_counter_bitset_and_clear_counters=uninstrumented fun:__sanitizer_update_counter_bitset_and_clear_counters=discard # Ignores the dfsan wrappers. fun:__dfsw_*=uninstrumented fun:__dfsw_*=discard # Don't add extra parameters to the Fuzzer callback. fun:LLVMFuzzerTestOneInput=uninstrumented Index: projects/clang400-import/contrib/compiler-rt/lib/esan/cache_frag.cpp =================================================================== --- projects/clang400-import/contrib/compiler-rt/lib/esan/cache_frag.cpp (revision 311696) +++ projects/clang400-import/contrib/compiler-rt/lib/esan/cache_frag.cpp (revision 311697) @@ -1,208 +1,208 @@ //===-- cache_frag.cpp ----------------------------------------------------===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // This file is a part of EfficiencySanitizer, a family of performance tuners. // // This file contains cache fragmentation-specific code. //===----------------------------------------------------------------------===// #include "esan.h" #include "esan_flags.h" #include "sanitizer_common/sanitizer_addrhashmap.h" #include "sanitizer_common/sanitizer_common.h" #include "sanitizer_common/sanitizer_placement_new.h" #include namespace __esan { //===-- Struct field access counter runtime -------------------------------===// // This should be kept consistent with LLVM's EfficiencySanitizer StructInfo. struct StructInfo { const char *StructName; u32 Size; u32 NumFields; u32 *FieldOffset; // auxiliary struct field info. u32 *FieldSize; // auxiliary struct field info. const char **FieldTypeName; // auxiliary struct field info. u64 *FieldCounters; u64 *ArrayCounter; bool hasAuxFieldInfo() { return FieldOffset != nullptr; } }; // This should be kept consistent with LLVM's EfficiencySanitizer CacheFragInfo. // The tool-specific information per compilation unit (module). struct CacheFragInfo { const char *UnitName; u32 NumStructs; StructInfo *Structs; }; struct StructCounter { StructInfo *Struct; u64 Count; // The total access count of the struct. u64 Ratio; // Difference ratio for the struct layout access. }; // We use StructHashMap to keep track of an unique copy of StructCounter. typedef AddrHashMap StructHashMap; struct Context { StructHashMap StructMap; u32 NumStructs; u64 TotalCount; // The total access count of all structs. }; static Context *Ctx; static void reportStructSummary() { // FIXME: provide a better struct field access summary report. Report("%s: total struct field access count = %llu\n", SanitizerToolName, Ctx->TotalCount); } // FIXME: we are still exploring proper ways to evaluate the difference between // struct field counts. Currently, we use a simple formula to calculate the // difference ratio: V1/V2. static inline u64 computeDifferenceRatio(u64 Val1, u64 Val2) { if (Val2 > Val1) { Swap(Val1, Val2); } if (Val2 == 0) Val2 = 1; return (Val1 / Val2); } static void reportStructCounter(StructHashMap::Handle &Handle) { const u32 TypePrintLimit = 512; const char *type, *start, *end; StructInfo *Struct = Handle->Struct; // Union field address calculation is done via bitcast instead of GEP, // so the count for union is always 0. // We skip the union report to avoid confusion. if (strncmp(Struct->StructName, "union.", 6) == 0) return; // Remove the '.' after class/struct during print. if (strncmp(Struct->StructName, "class.", 6) == 0) { type = "class"; start = &Struct->StructName[6]; } else { type = "struct"; start = &Struct->StructName[7]; } - // Remove the suffixes with '#' during print. - end = strchr(start, '#'); + // Remove the suffixes with '$' during print. + end = strchr(start, '$'); CHECK(end != nullptr); Report(" %s %.*s\n", type, end - start, start); Report(" size = %u, count = %llu, ratio = %llu, array access = %llu\n", Struct->Size, Handle->Count, Handle->Ratio, *Struct->ArrayCounter); if (Struct->hasAuxFieldInfo()) { for (u32 i = 0; i < Struct->NumFields; ++i) { Report(" #%2u: offset = %u,\t size = %u," "\t count = %llu,\t type = %.*s\n", i, Struct->FieldOffset[i], Struct->FieldSize[i], Struct->FieldCounters[i], TypePrintLimit, Struct->FieldTypeName[i]); } } else { for (u32 i = 0; i < Struct->NumFields; ++i) { Report(" #%2u: count = %llu\n", i, Struct->FieldCounters[i]); } } } static void computeStructRatio(StructHashMap::Handle &Handle) { Handle->Ratio = 0; Handle->Count = Handle->Struct->FieldCounters[0]; for (u32 i = 1; i < Handle->Struct->NumFields; ++i) { Handle->Count += Handle->Struct->FieldCounters[i]; Handle->Ratio += computeDifferenceRatio( Handle->Struct->FieldCounters[i - 1], Handle->Struct->FieldCounters[i]); } Ctx->TotalCount += Handle->Count; if (Handle->Ratio >= (u64)getFlags()->report_threshold || (Verbosity() >= 1 && Handle->Count > 0)) reportStructCounter(Handle); } static void registerStructInfo(CacheFragInfo *CacheFrag) { for (u32 i = 0; i < CacheFrag->NumStructs; ++i) { StructInfo *Struct = &CacheFrag->Structs[i]; StructHashMap::Handle H(&Ctx->StructMap, (uptr)Struct->FieldCounters); if (H.created()) { VPrintf(2, " Register %s: %u fields\n", Struct->StructName, Struct->NumFields); H->Struct = Struct; ++Ctx->NumStructs; } else { VPrintf(2, " Duplicated %s: %u fields\n", Struct->StructName, Struct->NumFields); } } } static void unregisterStructInfo(CacheFragInfo *CacheFrag) { // FIXME: if the library is unloaded before finalizeCacheFrag, we should // collect the result for later report. for (u32 i = 0; i < CacheFrag->NumStructs; ++i) { StructInfo *Struct = &CacheFrag->Structs[i]; StructHashMap::Handle H(&Ctx->StructMap, (uptr)Struct->FieldCounters, true); if (H.exists()) { VPrintf(2, " Unregister %s: %u fields\n", Struct->StructName, Struct->NumFields); // FIXME: we should move this call to finalizeCacheFrag once we can // iterate over the hash map there. computeStructRatio(H); --Ctx->NumStructs; } else { VPrintf(2, " Duplicated %s: %u fields\n", Struct->StructName, Struct->NumFields); } } static bool Reported = false; if (Ctx->NumStructs == 0 && !Reported) { Reported = true; reportStructSummary(); } } //===-- Init/exit functions -----------------------------------------------===// void processCacheFragCompilationUnitInit(void *Ptr) { CacheFragInfo *CacheFrag = (CacheFragInfo *)Ptr; VPrintf(2, "in esan::%s: %s with %u class(es)/struct(s)\n", __FUNCTION__, CacheFrag->UnitName, CacheFrag->NumStructs); registerStructInfo(CacheFrag); } void processCacheFragCompilationUnitExit(void *Ptr) { CacheFragInfo *CacheFrag = (CacheFragInfo *)Ptr; VPrintf(2, "in esan::%s: %s with %u class(es)/struct(s)\n", __FUNCTION__, CacheFrag->UnitName, CacheFrag->NumStructs); unregisterStructInfo(CacheFrag); } void initializeCacheFrag() { VPrintf(2, "in esan::%s\n", __FUNCTION__); // We use placement new to initialize Ctx before C++ static initializaion. // We make CtxMem 8-byte aligned for atomic operations in AddrHashMap. static u64 CtxMem[sizeof(Context) / sizeof(u64) + 1]; Ctx = new (CtxMem) Context(); Ctx->NumStructs = 0; } int finalizeCacheFrag() { VPrintf(2, "in esan::%s\n", __FUNCTION__); return 0; } void reportCacheFrag() { VPrintf(2, "in esan::%s\n", __FUNCTION__); // FIXME: Not yet implemented. We need to iterate over all of the // compilation unit data. } } // namespace __esan Index: projects/clang400-import/contrib/compiler-rt/lib/esan/esan.cpp =================================================================== --- projects/clang400-import/contrib/compiler-rt/lib/esan/esan.cpp (revision 311696) +++ projects/clang400-import/contrib/compiler-rt/lib/esan/esan.cpp (revision 311697) @@ -1,270 +1,278 @@ //===-- esan.cpp ----------------------------------------------------------===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // This file is a part of EfficiencySanitizer, a family of performance tuners. // // Main file (entry points) for the Esan run-time. //===----------------------------------------------------------------------===// #include "esan.h" #include "esan_flags.h" #include "esan_interface_internal.h" #include "esan_shadow.h" #include "cache_frag.h" #include "sanitizer_common/sanitizer_common.h" #include "sanitizer_common/sanitizer_flag_parser.h" #include "sanitizer_common/sanitizer_flags.h" #include "working_set.h" // See comment below. extern "C" { extern void __cxa_atexit(void (*function)(void)); } namespace __esan { bool EsanIsInitialized; bool EsanDuringInit; ShadowMapping Mapping; // Different tools use different scales within the same shadow mapping scheme. // The scale used here must match that used by the compiler instrumentation. // This array is indexed by the ToolType enum. static const uptr ShadowScale[] = { 0, // ESAN_None. 2, // ESAN_CacheFrag: 4B:1B, so 4 to 1 == >>2. 6, // ESAN_WorkingSet: 64B:1B, so 64 to 1 == >>6. }; // We are combining multiple performance tuning tools under the umbrella of // one EfficiencySanitizer super-tool. Most of our tools have very similar // memory access instrumentation, shadow memory mapping, libc interception, // etc., and there is typically more shared code than distinct code. // // We are not willing to dispatch on tool dynamically in our fastpath // instrumentation: thus, which tool to use is a static option selected // at compile time and passed to __esan_init(). // // We are willing to pay the overhead of tool dispatch in the slowpath to more // easily share code. We expect to only come here rarely. // If this becomes a performance hit, we can add separate interface // routines for each subtool (e.g., __esan_cache_frag_aligned_load_4). // But for libc interceptors, we'll have to do one of the following: // A) Add multiple-include support to sanitizer_common_interceptors.inc, // instantiate it separately for each tool, and call the selected // tool's intercept setup code. // B) Build separate static runtime libraries, one for each tool. // C) Completely split the tools into separate sanitizers. void processRangeAccess(uptr PC, uptr Addr, int Size, bool IsWrite) { VPrintf(3, "in esan::%s %p: %c %p %d\n", __FUNCTION__, PC, IsWrite ? 'w' : 'r', Addr, Size); if (__esan_which_tool == ESAN_CacheFrag) { // TODO(bruening): add shadow mapping and update shadow bits here. // We'll move this to cache_frag.cpp once we have something. } else if (__esan_which_tool == ESAN_WorkingSet) { processRangeAccessWorkingSet(PC, Addr, Size, IsWrite); } } bool processSignal(int SigNum, void (*Handler)(int), void (**Result)(int)) { if (__esan_which_tool == ESAN_WorkingSet) return processWorkingSetSignal(SigNum, Handler, Result); return true; } bool processSigaction(int SigNum, const void *Act, void *OldAct) { if (__esan_which_tool == ESAN_WorkingSet) return processWorkingSetSigaction(SigNum, Act, OldAct); return true; } bool processSigprocmask(int How, void *Set, void *OldSet) { if (__esan_which_tool == ESAN_WorkingSet) return processWorkingSetSigprocmask(How, Set, OldSet); return true; } #if SANITIZER_DEBUG static bool verifyShadowScheme() { // Sanity checks for our shadow mapping scheme. uptr AppStart, AppEnd; if (Verbosity() >= 3) { for (int i = 0; getAppRegion(i, &AppStart, &AppEnd); ++i) { VPrintf(3, "App #%d: [%zx-%zx) (%zuGB)\n", i, AppStart, AppEnd, (AppEnd - AppStart) >> 30); } } for (int Scale = 0; Scale < 8; ++Scale) { Mapping.initialize(Scale); if (Verbosity() >= 3) { VPrintf(3, "\nChecking scale %d\n", Scale); uptr ShadowStart, ShadowEnd; for (int i = 0; getShadowRegion(i, &ShadowStart, &ShadowEnd); ++i) { VPrintf(3, "Shadow #%d: [%zx-%zx) (%zuGB)\n", i, ShadowStart, ShadowEnd, (ShadowEnd - ShadowStart) >> 30); } for (int i = 0; getShadowRegion(i, &ShadowStart, &ShadowEnd); ++i) { VPrintf(3, "Shadow(Shadow) #%d: [%zx-%zx)\n", i, appToShadow(ShadowStart), appToShadow(ShadowEnd - 1)+1); } } for (int i = 0; getAppRegion(i, &AppStart, &AppEnd); ++i) { DCHECK(isAppMem(AppStart)); DCHECK(!isAppMem(AppStart - 1)); DCHECK(isAppMem(AppEnd - 1)); DCHECK(!isAppMem(AppEnd)); DCHECK(!isShadowMem(AppStart)); DCHECK(!isShadowMem(AppEnd - 1)); DCHECK(isShadowMem(appToShadow(AppStart))); DCHECK(isShadowMem(appToShadow(AppEnd - 1))); // Double-shadow checks. DCHECK(!isShadowMem(appToShadow(appToShadow(AppStart)))); DCHECK(!isShadowMem(appToShadow(appToShadow(AppEnd - 1)))); } // Ensure no shadow regions overlap each other. uptr ShadowAStart, ShadowBStart, ShadowAEnd, ShadowBEnd; for (int i = 0; getShadowRegion(i, &ShadowAStart, &ShadowAEnd); ++i) { for (int j = 0; getShadowRegion(j, &ShadowBStart, &ShadowBEnd); ++j) { DCHECK(i == j || ShadowAStart >= ShadowBEnd || ShadowAEnd <= ShadowBStart); } } } return true; } #endif +uptr VmaSize; + static void initializeShadow() { verifyAddressSpace(); + + // This is based on the assumption that the intial stack is always allocated + // in the topmost segment of the user address space and the assumption + // holds true on all the platforms currently supported. + VmaSize = + (MostSignificantSetBitIndex(GET_CURRENT_FRAME()) + 1); DCHECK(verifyShadowScheme()); Mapping.initialize(ShadowScale[__esan_which_tool]); VPrintf(1, "Shadow scale=%d offset=%p\n", Mapping.Scale, Mapping.Offset); uptr ShadowStart, ShadowEnd; for (int i = 0; getShadowRegion(i, &ShadowStart, &ShadowEnd); ++i) { VPrintf(1, "Shadow #%d: [%zx-%zx) (%zuGB)\n", i, ShadowStart, ShadowEnd, (ShadowEnd - ShadowStart) >> 30); uptr Map; if (__esan_which_tool == ESAN_WorkingSet) { // We want to identify all shadow pages that are touched so we start // out inaccessible. Map = (uptr)MmapFixedNoAccess(ShadowStart, ShadowEnd- ShadowStart, "shadow"); } else { Map = (uptr)MmapFixedNoReserve(ShadowStart, ShadowEnd - ShadowStart, "shadow"); } if (Map != ShadowStart) { Printf("FATAL: EfficiencySanitizer failed to map its shadow memory.\n"); Die(); } if (common_flags()->no_huge_pages_for_shadow) NoHugePagesInRegion(ShadowStart, ShadowEnd - ShadowStart); if (common_flags()->use_madv_dontdump) DontDumpShadowMemory(ShadowStart, ShadowEnd - ShadowStart); // TODO: Call MmapNoAccess() on in-between regions. } } void initializeLibrary(ToolType Tool) { // We assume there is only one thread during init, but we need to // guard against double-init when we're (re-)called from an // early interceptor. if (EsanIsInitialized || EsanDuringInit) return; EsanDuringInit = true; CHECK(Tool == __esan_which_tool); SanitizerToolName = "EfficiencySanitizer"; CacheBinaryName(); initializeFlags(); // Intercepting libc _exit or exit via COMMON_INTERCEPTOR_ON_EXIT only // finalizes on an explicit exit call by the app. To handle a normal // exit we register an atexit handler. ::__cxa_atexit((void (*)())finalizeLibrary); VPrintf(1, "in esan::%s\n", __FUNCTION__); if (__esan_which_tool <= ESAN_None || __esan_which_tool >= ESAN_Max) { Printf("ERROR: unknown tool %d requested\n", __esan_which_tool); Die(); } initializeShadow(); if (__esan_which_tool == ESAN_WorkingSet) initializeShadowWorkingSet(); initializeInterceptors(); if (__esan_which_tool == ESAN_CacheFrag) { initializeCacheFrag(); } else if (__esan_which_tool == ESAN_WorkingSet) { initializeWorkingSet(); } EsanIsInitialized = true; EsanDuringInit = false; } int finalizeLibrary() { VPrintf(1, "in esan::%s\n", __FUNCTION__); if (__esan_which_tool == ESAN_CacheFrag) { return finalizeCacheFrag(); } else if (__esan_which_tool == ESAN_WorkingSet) { return finalizeWorkingSet(); } return 0; } void reportResults() { VPrintf(1, "in esan::%s\n", __FUNCTION__); if (__esan_which_tool == ESAN_CacheFrag) { return reportCacheFrag(); } else if (__esan_which_tool == ESAN_WorkingSet) { return reportWorkingSet(); } } void processCompilationUnitInit(void *Ptr) { VPrintf(2, "in esan::%s\n", __FUNCTION__); if (__esan_which_tool == ESAN_CacheFrag) { DCHECK(Ptr != nullptr); processCacheFragCompilationUnitInit(Ptr); } else { DCHECK(Ptr == nullptr); } } // This is called when the containing module is unloaded. // For the main executable module, this is called after finalizeLibrary. void processCompilationUnitExit(void *Ptr) { VPrintf(2, "in esan::%s\n", __FUNCTION__); if (__esan_which_tool == ESAN_CacheFrag) { DCHECK(Ptr != nullptr); processCacheFragCompilationUnitExit(Ptr); } else { DCHECK(Ptr == nullptr); } } unsigned int getSampleCount() { VPrintf(1, "in esan::%s\n", __FUNCTION__); if (__esan_which_tool == ESAN_WorkingSet) { return getSampleCountWorkingSet(); } return 0; } } // namespace __esan Index: projects/clang400-import/contrib/compiler-rt/lib/esan/esan.h =================================================================== --- projects/clang400-import/contrib/compiler-rt/lib/esan/esan.h (revision 311696) +++ projects/clang400-import/contrib/compiler-rt/lib/esan/esan.h (revision 311697) @@ -1,60 +1,61 @@ //===-- esan.h --------------------------------------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // This file is a part of EfficiencySanitizer, a family of performance tuners. // // Main internal esan header file. // // Ground rules: // - C++ run-time should not be used (static CTORs, RTTI, exceptions, static // function-scope locals) // - All functions/classes/etc reside in namespace __esan, except for those // declared in esan_interface_internal.h. // - Platform-specific files should be used instead of ifdefs (*). // - No system headers included in header files (*). // - Platform specific headers included only into platform-specific files (*). // // (*) Except when inlining is critical for performance. //===----------------------------------------------------------------------===// #ifndef ESAN_H #define ESAN_H #include "interception/interception.h" #include "sanitizer_common/sanitizer_common.h" #include "esan_interface_internal.h" namespace __esan { extern bool EsanIsInitialized; extern bool EsanDuringInit; +extern uptr VmaSize; void initializeLibrary(ToolType Tool); int finalizeLibrary(); void reportResults(); unsigned int getSampleCount(); // Esan creates the variable per tool per compilation unit at compile time // and passes its pointer Ptr to the runtime library. void processCompilationUnitInit(void *Ptr); void processCompilationUnitExit(void *Ptr); void processRangeAccess(uptr PC, uptr Addr, int Size, bool IsWrite); void initializeInterceptors(); // Platform-dependent routines. void verifyAddressSpace(); bool fixMmapAddr(void **Addr, SIZE_T Size, int Flags); uptr checkMmapResult(uptr Addr, SIZE_T Size); // The return value indicates whether to call the real version or not. bool processSignal(int SigNum, void (*Handler)(int), void (**Result)(int)); bool processSigaction(int SigNum, const void *Act, void *OldAct); bool processSigprocmask(int How, void *Set, void *OldSet); } // namespace __esan #endif // ESAN_H Index: projects/clang400-import/contrib/compiler-rt/lib/esan/esan_flags.cpp =================================================================== --- projects/clang400-import/contrib/compiler-rt/lib/esan/esan_flags.cpp (revision 311696) +++ projects/clang400-import/contrib/compiler-rt/lib/esan/esan_flags.cpp (revision 311697) @@ -1,58 +1,60 @@ //===-- esan_flags.cc -------------------------------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // This file is a part of EfficiencySanitizer, a family of performance tuners. // // Esan flag parsing logic. //===----------------------------------------------------------------------===// #include "esan_flags.h" #include "sanitizer_common/sanitizer_common.h" #include "sanitizer_common/sanitizer_flag_parser.h" #include "sanitizer_common/sanitizer_flags.h" +using namespace __sanitizer; + namespace __esan { static const char EsanOptsEnv[] = "ESAN_OPTIONS"; Flags EsanFlagsDontUseDirectly; void Flags::setDefaults() { #define ESAN_FLAG(Type, Name, DefaultValue, Description) Name = DefaultValue; #include "esan_flags.inc" #undef ESAN_FLAG } static void registerEsanFlags(FlagParser *Parser, Flags *F) { #define ESAN_FLAG(Type, Name, DefaultValue, Description) \ RegisterFlag(Parser, #Name, Description, &F->Name); #include "esan_flags.inc" #undef ESAN_FLAG } void initializeFlags() { SetCommonFlagsDefaults(); Flags *F = getFlags(); F->setDefaults(); FlagParser Parser; registerEsanFlags(&Parser, F); RegisterCommonFlags(&Parser); Parser.ParseString(GetEnv(EsanOptsEnv)); InitializeCommonFlags(); if (Verbosity()) ReportUnrecognizedFlags(); if (common_flags()->help) Parser.PrintFlagDescriptions(); __sanitizer_set_report_path(common_flags()->log_path); } } // namespace __esan Index: projects/clang400-import/contrib/compiler-rt/lib/esan/esan_hashtable.h =================================================================== --- projects/clang400-import/contrib/compiler-rt/lib/esan/esan_hashtable.h (nonexistent) +++ projects/clang400-import/contrib/compiler-rt/lib/esan/esan_hashtable.h (revision 311697) @@ -0,0 +1,381 @@ +//===-- esan_hashtable.h ----------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file is a part of EfficiencySanitizer, a family of performance tuners. +// +// Generic resizing hashtable. +//===----------------------------------------------------------------------===// + +#include "sanitizer_common/sanitizer_allocator_internal.h" +#include "sanitizer_common/sanitizer_internal_defs.h" +#include "sanitizer_common/sanitizer_mutex.h" +#include + +namespace __esan { + +//===----------------------------------------------------------------------===// +// Default hash and comparison functions +//===----------------------------------------------------------------------===// + +template struct DefaultHash { + size_t operator()(const T &Key) const { + return (size_t)Key; + } +}; + +template struct DefaultEqual { + bool operator()(const T &Key1, const T &Key2) const { + return Key1 == Key2; + } +}; + +//===----------------------------------------------------------------------===// +// HashTable declaration +//===----------------------------------------------------------------------===// + +// A simple resizing and mutex-locked hashtable. +// +// If the default hash functor is used, KeyTy must have an operator size_t(). +// If the default comparison functor is used, KeyTy must have an operator ==. +// +// By default all operations are internally-synchronized with a mutex, with no +// synchronization for payloads once hashtable functions return. If +// ExternalLock is set to true, the caller should call the lock() and unlock() +// routines around all hashtable operations and subsequent manipulation of +// payloads. +template , + typename EqualFuncTy = DefaultEqual > +class HashTable { +public: + // InitialCapacity must be a power of 2. + // ResizeFactor must be between 1 and 99 and indicates the + // maximum percentage full that the table should ever be. + HashTable(u32 InitialCapacity = 2048, u32 ResizeFactor = 70); + ~HashTable(); + bool lookup(const KeyTy &Key, DataTy &Payload); // Const except for Mutex. + bool add(const KeyTy &Key, const DataTy &Payload); + bool remove(const KeyTy &Key); + u32 size(); // Const except for Mutex. + // If the table is internally-synchronized, this lock must not be held + // while a hashtable function is called as it will deadlock: the lock + // is not recursive. This is meant for use with externally-synchronized + // tables or with an iterator. + void lock(); + void unlock(); + +private: + struct HashEntry { + KeyTy Key; + DataTy Payload; + HashEntry *Next; + }; + +public: + struct HashPair { + HashPair(KeyTy Key, DataTy Data) : Key(Key), Data(Data) {} + KeyTy Key; + DataTy Data; + }; + + // This iterator does not perform any synchronization. + // It expects the caller to lock the table across the whole iteration. + // Calling HashTable functions while using the iterator is not supported. + // The iterator returns copies of the keys and data. + class iterator { + public: + iterator( + HashTable *Table); + iterator(const iterator &Src) = default; + iterator &operator=(const iterator &Src) = default; + HashPair operator*(); + iterator &operator++(); + iterator &operator++(int); + bool operator==(const iterator &Cmp) const; + bool operator!=(const iterator &Cmp) const; + + private: + iterator( + HashTable *Table, + int Idx); + friend HashTable; + HashTable *Table; + int Idx; + HashTable::HashEntry + *Entry; + }; + + // No erase or insert iterator supported + iterator begin(); + iterator end(); + +private: + void resize(); + + HashEntry **Table; + u32 Capacity; + u32 Entries; + const u32 ResizeFactor; + BlockingMutex Mutex; + const HashFuncTy HashFunc; + const EqualFuncTy EqualFunc; +}; + +//===----------------------------------------------------------------------===// +// Hashtable implementation +//===----------------------------------------------------------------------===// + +template +HashTable::HashTable( + u32 InitialCapacity, u32 ResizeFactor) + : Capacity(InitialCapacity), Entries(0), ResizeFactor(ResizeFactor), + HashFunc(HashFuncTy()), EqualFunc(EqualFuncTy()) { + CHECK(IsPowerOfTwo(Capacity)); + CHECK(ResizeFactor >= 1 && ResizeFactor <= 99); + Table = (HashEntry **)InternalAlloc(Capacity * sizeof(HashEntry *)); + internal_memset(Table, 0, Capacity * sizeof(HashEntry *)); +} + +template +HashTable::~HashTable() { + for (u32 i = 0; i < Capacity; ++i) { + HashEntry *Entry = Table[i]; + while (Entry != nullptr) { + HashEntry *Next = Entry->Next; + Entry->Payload.~DataTy(); + InternalFree(Entry); + Entry = Next; + } + } + InternalFree(Table); +} + +template +u32 HashTable::size() { + u32 Res; + if (!ExternalLock) + Mutex.Lock(); + Res = Entries; + if (!ExternalLock) + Mutex.Unlock(); + return Res; +} + +template +bool HashTable::lookup( + const KeyTy &Key, DataTy &Payload) { + if (!ExternalLock) + Mutex.Lock(); + bool Found = false; + size_t Hash = HashFunc(Key) % Capacity; + HashEntry *Entry = Table[Hash]; + for (; Entry != nullptr; Entry = Entry->Next) { + if (EqualFunc(Entry->Key, Key)) { + Payload = Entry->Payload; + Found = true; + break; + } + } + if (!ExternalLock) + Mutex.Unlock(); + return Found; +} + +template +void HashTable::resize() { + if (!ExternalLock) + Mutex.CheckLocked(); + size_t OldCapacity = Capacity; + HashEntry **OldTable = Table; + Capacity *= 2; + Table = (HashEntry **)InternalAlloc(Capacity * sizeof(HashEntry *)); + internal_memset(Table, 0, Capacity * sizeof(HashEntry *)); + // Re-hash + for (u32 i = 0; i < OldCapacity; ++i) { + HashEntry *OldEntry = OldTable[i]; + while (OldEntry != nullptr) { + HashEntry *Next = OldEntry->Next; + size_t Hash = HashFunc(OldEntry->Key) % Capacity; + OldEntry->Next = Table[Hash]; + Table[Hash] = OldEntry; + OldEntry = Next; + } + } +} + +template +bool HashTable::add( + const KeyTy &Key, const DataTy &Payload) { + if (!ExternalLock) + Mutex.Lock(); + bool Exists = false; + size_t Hash = HashFunc(Key) % Capacity; + HashEntry *Entry = Table[Hash]; + for (; Entry != nullptr; Entry = Entry->Next) { + if (EqualFunc(Entry->Key, Key)) { + Exists = true; + break; + } + } + if (!Exists) { + Entries++; + if (Entries * 100 >= Capacity * ResizeFactor) { + resize(); + Hash = HashFunc(Key) % Capacity; + } + HashEntry *Add = (HashEntry *)InternalAlloc(sizeof(*Add)); + Add->Key = Key; + Add->Payload = Payload; + Add->Next = Table[Hash]; + Table[Hash] = Add; + } + if (!ExternalLock) + Mutex.Unlock(); + return !Exists; +} + +template +bool HashTable::remove( + const KeyTy &Key) { + if (!ExternalLock) + Mutex.Lock(); + bool Found = false; + size_t Hash = HashFunc(Key) % Capacity; + HashEntry *Entry = Table[Hash]; + HashEntry *Prev = nullptr; + for (; Entry != nullptr; Prev = Entry, Entry = Entry->Next) { + if (EqualFunc(Entry->Key, Key)) { + Found = true; + Entries--; + if (Prev == nullptr) + Table[Hash] = Entry->Next; + else + Prev->Next = Entry->Next; + Entry->Payload.~DataTy(); + InternalFree(Entry); + break; + } + } + if (!ExternalLock) + Mutex.Unlock(); + return Found; +} + +template +void HashTable::lock() { + Mutex.Lock(); +} + +template +void HashTable::unlock() { + Mutex.Unlock(); +} + +//===----------------------------------------------------------------------===// +// Iterator implementation +//===----------------------------------------------------------------------===// + +template +HashTable::iterator:: + iterator( + HashTable *Table) + : Table(Table), Idx(-1), Entry(nullptr) { + operator++(); +} + +template +HashTable::iterator:: + iterator( + HashTable *Table, + int Idx) + : Table(Table), Idx(Idx), Entry(nullptr) { + CHECK(Idx >= (int)Table->Capacity); // Only used to create end(). +} + +template +typename HashTable::HashPair + HashTable::iterator:: + operator*() { + CHECK(Idx >= 0 && Idx < (int)Table->Capacity); + CHECK(Entry != nullptr); + return HashPair(Entry->Key, Entry->Payload); +} + +template +typename HashTable::iterator & + HashTable::iterator:: + operator++() { + if (Entry != nullptr) + Entry = Entry->Next; + while (Entry == nullptr) { + ++Idx; + if (Idx >= (int)Table->Capacity) + break; // At end(). + Entry = Table->Table[Idx]; + } + return *this; +} + +template +typename HashTable::iterator & + HashTable::iterator:: + operator++(int) { + iterator Temp(*this); + operator++(); + return Temp; +} + +template +bool HashTable::iterator:: +operator==(const iterator &Cmp) const { + return Cmp.Table == Table && Cmp.Idx == Idx && Cmp.Entry == Entry; +} + +template +bool HashTable::iterator:: +operator!=(const iterator &Cmp) const { + return Cmp.Table != Table || Cmp.Idx != Idx || Cmp.Entry != Entry; +} + +template +typename HashTable::iterator +HashTable::begin() { + return iterator(this); +} + +template +typename HashTable::iterator +HashTable::end() { + return iterator(this, Capacity); +} + +} // namespace __esan Property changes on: projects/clang400-import/contrib/compiler-rt/lib/esan/esan_hashtable.h ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: projects/clang400-import/contrib/compiler-rt/lib/esan/esan_interceptors.cpp =================================================================== --- projects/clang400-import/contrib/compiler-rt/lib/esan/esan_interceptors.cpp (revision 311696) +++ projects/clang400-import/contrib/compiler-rt/lib/esan/esan_interceptors.cpp (revision 311697) @@ -1,547 +1,561 @@ //===-- esan_interceptors.cpp ---------------------------------------------===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // This file is a part of EfficiencySanitizer, a family of performance tuners. // // Interception routines for the esan run-time. //===----------------------------------------------------------------------===// #include "esan.h" #include "esan_shadow.h" #include "interception/interception.h" #include "sanitizer_common/sanitizer_common.h" #include "sanitizer_common/sanitizer_libc.h" #include "sanitizer_common/sanitizer_linux.h" #include "sanitizer_common/sanitizer_stacktrace.h" using namespace __esan; // NOLINT #define CUR_PC() (StackTrace::GetCurrentPc()) //===----------------------------------------------------------------------===// // Interception via sanitizer common interceptors //===----------------------------------------------------------------------===// // Get the per-platform defines for what is possible to intercept #include "sanitizer_common/sanitizer_platform_interceptors.h" // TODO(bruening): tsan disables several interceptors (getpwent, etc.) claiming // that interception is a perf hit: should we do the same? // We have no need to intercept: #undef SANITIZER_INTERCEPT_TLS_GET_ADDR // TODO(bruening): the common realpath interceptor assumes malloc is // intercepted! We should try to parametrize that, though we'll // intercept malloc soon ourselves and can then remove this undef. #undef SANITIZER_INTERCEPT_REALPATH // We provide our own version: #undef SANITIZER_INTERCEPT_SIGPROCMASK #define COMMON_INTERCEPTOR_NOTHING_IS_INITIALIZED (!EsanIsInitialized) #define COMMON_INTERCEPT_FUNCTION(name) INTERCEPT_FUNCTION(name) #define COMMON_INTERCEPT_FUNCTION_VER(name, ver) \ INTERCEPT_FUNCTION_VER(name, ver) // We must initialize during early interceptors, to support tcmalloc. // This means that for some apps we fully initialize prior to // __esan_init() being called. // We currently do not use ctx. #define COMMON_INTERCEPTOR_ENTER(ctx, func, ...) \ do { \ if (UNLIKELY(COMMON_INTERCEPTOR_NOTHING_IS_INITIALIZED)) { \ if (!UNLIKELY(EsanDuringInit)) \ initializeLibrary(__esan_which_tool); \ return REAL(func)(__VA_ARGS__); \ } \ ctx = nullptr; \ (void)ctx; \ } while (false) #define COMMON_INTERCEPTOR_ENTER_NOIGNORE(ctx, func, ...) \ COMMON_INTERCEPTOR_ENTER(ctx, func, __VA_ARGS__) #define COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ptr, size) \ processRangeAccess(CUR_PC(), (uptr)ptr, size, true) #define COMMON_INTERCEPTOR_READ_RANGE(ctx, ptr, size) \ processRangeAccess(CUR_PC(), (uptr)ptr, size, false) // This is only called if the app explicitly calls exit(), not on // a normal exit. #define COMMON_INTERCEPTOR_ON_EXIT(ctx) finalizeLibrary() #define COMMON_INTERCEPTOR_FILE_OPEN(ctx, file, path) \ do { \ (void)(ctx); \ (void)(file); \ (void)(path); \ } while (false) #define COMMON_INTERCEPTOR_FILE_CLOSE(ctx, file) \ do { \ (void)(ctx); \ (void)(file); \ } while (false) #define COMMON_INTERCEPTOR_LIBRARY_LOADED(filename, handle) \ do { \ (void)(filename); \ (void)(handle); \ } while (false) #define COMMON_INTERCEPTOR_LIBRARY_UNLOADED() \ do { \ } while (false) #define COMMON_INTERCEPTOR_ACQUIRE(ctx, u) \ do { \ (void)(ctx); \ (void)(u); \ } while (false) #define COMMON_INTERCEPTOR_RELEASE(ctx, u) \ do { \ (void)(ctx); \ (void)(u); \ } while (false) #define COMMON_INTERCEPTOR_DIR_ACQUIRE(ctx, path) \ do { \ (void)(ctx); \ (void)(path); \ } while (false) #define COMMON_INTERCEPTOR_FD_ACQUIRE(ctx, fd) \ do { \ (void)(ctx); \ (void)(fd); \ } while (false) #define COMMON_INTERCEPTOR_FD_RELEASE(ctx, fd) \ do { \ (void)(ctx); \ (void)(fd); \ } while (false) #define COMMON_INTERCEPTOR_FD_ACCESS(ctx, fd) \ do { \ (void)(ctx); \ (void)(fd); \ } while (false) #define COMMON_INTERCEPTOR_FD_SOCKET_ACCEPT(ctx, fd, newfd) \ do { \ (void)(ctx); \ (void)(fd); \ (void)(newfd); \ } while (false) #define COMMON_INTERCEPTOR_SET_THREAD_NAME(ctx, name) \ do { \ (void)(ctx); \ (void)(name); \ } while (false) #define COMMON_INTERCEPTOR_SET_PTHREAD_NAME(ctx, thread, name) \ do { \ (void)(ctx); \ (void)(thread); \ (void)(name); \ } while (false) #define COMMON_INTERCEPTOR_BLOCK_REAL(name) REAL(name) #define COMMON_INTERCEPTOR_MUTEX_LOCK(ctx, m) \ do { \ (void)(ctx); \ (void)(m); \ } while (false) #define COMMON_INTERCEPTOR_MUTEX_UNLOCK(ctx, m) \ do { \ (void)(ctx); \ (void)(m); \ } while (false) #define COMMON_INTERCEPTOR_MUTEX_REPAIR(ctx, m) \ do { \ (void)(ctx); \ (void)(m); \ } while (false) #define COMMON_INTERCEPTOR_HANDLE_RECVMSG(ctx, msg) \ do { \ (void)(ctx); \ (void)(msg); \ } while (false) #define COMMON_INTERCEPTOR_USER_CALLBACK_START() \ do { \ } while (false) #define COMMON_INTERCEPTOR_USER_CALLBACK_END() \ do { \ } while (false) #include "sanitizer_common/sanitizer_common_interceptors.inc" //===----------------------------------------------------------------------===// // Syscall interception //===----------------------------------------------------------------------===// // We want the caller's PC b/c unlike the other function interceptors these // are separate pre and post functions called around the app's syscall(). #define COMMON_SYSCALL_PRE_READ_RANGE(ptr, size) \ processRangeAccess(GET_CALLER_PC(), (uptr)ptr, size, false) #define COMMON_SYSCALL_PRE_WRITE_RANGE(ptr, size) \ do { \ (void)(ptr); \ (void)(size); \ } while (false) #define COMMON_SYSCALL_POST_READ_RANGE(ptr, size) \ do { \ (void)(ptr); \ (void)(size); \ } while (false) // The actual amount written is in post, not pre. #define COMMON_SYSCALL_POST_WRITE_RANGE(ptr, size) \ processRangeAccess(GET_CALLER_PC(), (uptr)ptr, size, true) #define COMMON_SYSCALL_ACQUIRE(addr) \ do { \ (void)(addr); \ } while (false) #define COMMON_SYSCALL_RELEASE(addr) \ do { \ (void)(addr); \ } while (false) #define COMMON_SYSCALL_FD_CLOSE(fd) \ do { \ (void)(fd); \ } while (false) #define COMMON_SYSCALL_FD_ACQUIRE(fd) \ do { \ (void)(fd); \ } while (false) #define COMMON_SYSCALL_FD_RELEASE(fd) \ do { \ (void)(fd); \ } while (false) #define COMMON_SYSCALL_PRE_FORK() \ do { \ } while (false) #define COMMON_SYSCALL_POST_FORK(res) \ do { \ (void)(res); \ } while (false) #include "sanitizer_common/sanitizer_common_syscalls.inc" //===----------------------------------------------------------------------===// // Custom interceptors //===----------------------------------------------------------------------===// // TODO(bruening): move more of these to the common interception pool as they // are shared with tsan and asan. // While our other files match LLVM style, here we match sanitizer style as we // expect to move these to the common pool. INTERCEPTOR(char *, strcpy, char *dst, const char *src) { // NOLINT void *ctx; COMMON_INTERCEPTOR_ENTER(ctx, strcpy, dst, src); uptr srclen = internal_strlen(src); COMMON_INTERCEPTOR_WRITE_RANGE(ctx, dst, srclen + 1); COMMON_INTERCEPTOR_READ_RANGE(ctx, src, srclen + 1); return REAL(strcpy)(dst, src); // NOLINT } INTERCEPTOR(char *, strncpy, char *dst, char *src, uptr n) { void *ctx; COMMON_INTERCEPTOR_ENTER(ctx, strncpy, dst, src, n); uptr srclen = internal_strnlen(src, n); uptr copied_size = srclen + 1 > n ? n : srclen + 1; COMMON_INTERCEPTOR_WRITE_RANGE(ctx, dst, copied_size); COMMON_INTERCEPTOR_READ_RANGE(ctx, src, copied_size); return REAL(strncpy)(dst, src, n); } INTERCEPTOR(int, open, const char *name, int flags, int mode) { void *ctx; COMMON_INTERCEPTOR_ENTER(ctx, open, name, flags, mode); COMMON_INTERCEPTOR_READ_STRING(ctx, name, 0); return REAL(open)(name, flags, mode); } #if SANITIZER_LINUX INTERCEPTOR(int, open64, const char *name, int flags, int mode) { void *ctx; COMMON_INTERCEPTOR_ENTER(ctx, open64, name, flags, mode); COMMON_INTERCEPTOR_READ_STRING(ctx, name, 0); return REAL(open64)(name, flags, mode); } #define ESAN_MAYBE_INTERCEPT_OPEN64 INTERCEPT_FUNCTION(open64) #else #define ESAN_MAYBE_INTERCEPT_OPEN64 #endif INTERCEPTOR(int, creat, const char *name, int mode) { void *ctx; COMMON_INTERCEPTOR_ENTER(ctx, creat, name, mode); COMMON_INTERCEPTOR_READ_STRING(ctx, name, 0); return REAL(creat)(name, mode); } #if SANITIZER_LINUX INTERCEPTOR(int, creat64, const char *name, int mode) { void *ctx; COMMON_INTERCEPTOR_ENTER(ctx, creat64, name, mode); COMMON_INTERCEPTOR_READ_STRING(ctx, name, 0); return REAL(creat64)(name, mode); } #define ESAN_MAYBE_INTERCEPT_CREAT64 INTERCEPT_FUNCTION(creat64) #else #define ESAN_MAYBE_INTERCEPT_CREAT64 #endif INTERCEPTOR(int, unlink, char *path) { void *ctx; COMMON_INTERCEPTOR_ENTER(ctx, unlink, path); COMMON_INTERCEPTOR_READ_STRING(ctx, path, 0); return REAL(unlink)(path); } INTERCEPTOR(uptr, fread, void *ptr, uptr size, uptr nmemb, void *f) { void *ctx; COMMON_INTERCEPTOR_ENTER(ctx, fread, ptr, size, nmemb, f); COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ptr, size * nmemb); return REAL(fread)(ptr, size, nmemb, f); } INTERCEPTOR(uptr, fwrite, const void *p, uptr size, uptr nmemb, void *f) { void *ctx; COMMON_INTERCEPTOR_ENTER(ctx, fwrite, p, size, nmemb, f); COMMON_INTERCEPTOR_READ_RANGE(ctx, p, size * nmemb); return REAL(fwrite)(p, size, nmemb, f); } INTERCEPTOR(int, puts, const char *s) { void *ctx; COMMON_INTERCEPTOR_ENTER(ctx, puts, s); COMMON_INTERCEPTOR_READ_RANGE(ctx, s, internal_strlen(s)); return REAL(puts)(s); } INTERCEPTOR(int, rmdir, char *path) { void *ctx; COMMON_INTERCEPTOR_ENTER(ctx, rmdir, path); COMMON_INTERCEPTOR_READ_STRING(ctx, path, 0); return REAL(rmdir)(path); } //===----------------------------------------------------------------------===// // Shadow-related interceptors //===----------------------------------------------------------------------===// // These are candidates for sharing with all sanitizers if shadow memory // support is also standardized. INTERCEPTOR(void *, mmap, void *addr, SIZE_T sz, int prot, int flags, int fd, OFF_T off) { if (UNLIKELY(REAL(mmap) == nullptr)) { // With esan init during interceptor init and a static libc preventing // our early-calloc from triggering, we can end up here before our // REAL pointer is set up. return (void *)internal_mmap(addr, sz, prot, flags, fd, off); } void *ctx; COMMON_INTERCEPTOR_ENTER(ctx, mmap, addr, sz, prot, flags, fd, off); if (!fixMmapAddr(&addr, sz, flags)) return (void *)-1; void *result = REAL(mmap)(addr, sz, prot, flags, fd, off); return (void *)checkMmapResult((uptr)result, sz); } #if SANITIZER_LINUX INTERCEPTOR(void *, mmap64, void *addr, SIZE_T sz, int prot, int flags, int fd, OFF64_T off) { void *ctx; COMMON_INTERCEPTOR_ENTER(ctx, mmap64, addr, sz, prot, flags, fd, off); if (!fixMmapAddr(&addr, sz, flags)) return (void *)-1; void *result = REAL(mmap64)(addr, sz, prot, flags, fd, off); return (void *)checkMmapResult((uptr)result, sz); } #define ESAN_MAYBE_INTERCEPT_MMAP64 INTERCEPT_FUNCTION(mmap64) #else #define ESAN_MAYBE_INTERCEPT_MMAP64 #endif //===----------------------------------------------------------------------===// // Signal-related interceptors //===----------------------------------------------------------------------===// #if SANITIZER_LINUX typedef void (*signal_handler_t)(int); INTERCEPTOR(signal_handler_t, signal, int signum, signal_handler_t handler) { void *ctx; COMMON_INTERCEPTOR_ENTER(ctx, signal, signum, handler); signal_handler_t result; if (!processSignal(signum, handler, &result)) return result; else return REAL(signal)(signum, handler); } #define ESAN_MAYBE_INTERCEPT_SIGNAL INTERCEPT_FUNCTION(signal) #else #error Platform not supported #define ESAN_MAYBE_INTERCEPT_SIGNAL #endif #if SANITIZER_LINUX DECLARE_REAL(int, sigaction, int signum, const struct sigaction *act, struct sigaction *oldact) INTERCEPTOR(int, sigaction, int signum, const struct sigaction *act, struct sigaction *oldact) { void *ctx; COMMON_INTERCEPTOR_ENTER(ctx, sigaction, signum, act, oldact); if (!processSigaction(signum, act, oldact)) return 0; else return REAL(sigaction)(signum, act, oldact); } // This is required to properly use internal_sigaction. namespace __sanitizer { int real_sigaction(int signum, const void *act, void *oldact) { if (REAL(sigaction) == nullptr) { // With an instrumented allocator, this is called during interceptor init // and we need a raw syscall solution. return internal_sigaction_syscall(signum, act, oldact); } return REAL(sigaction)(signum, (const struct sigaction *)act, (struct sigaction *)oldact); } } // namespace __sanitizer #define ESAN_MAYBE_INTERCEPT_SIGACTION INTERCEPT_FUNCTION(sigaction) #else #error Platform not supported #define ESAN_MAYBE_INTERCEPT_SIGACTION #endif #if SANITIZER_LINUX INTERCEPTOR(int, sigprocmask, int how, __sanitizer_sigset_t *set, __sanitizer_sigset_t *oldset) { void *ctx; COMMON_INTERCEPTOR_ENTER(ctx, sigprocmask, how, set, oldset); int res = 0; if (processSigprocmask(how, set, oldset)) res = REAL(sigprocmask)(how, set, oldset); if (!res && oldset) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, oldset, sizeof(*oldset)); return res; } #define ESAN_MAYBE_INTERCEPT_SIGPROCMASK INTERCEPT_FUNCTION(sigprocmask) #else #define ESAN_MAYBE_INTERCEPT_SIGPROCMASK #endif #if !SANITIZER_WINDOWS 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); int res = 0; if (processSigprocmask(how, set, oldset)) res = REAL(sigprocmask)(how, set, oldset); if (!res && oldset) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, oldset, sizeof(*oldset)); return res; } #define ESAN_MAYBE_INTERCEPT_PTHREAD_SIGMASK INTERCEPT_FUNCTION(pthread_sigmask) #else #define ESAN_MAYBE_INTERCEPT_PTHREAD_SIGMASK #endif //===----------------------------------------------------------------------===// // Malloc interceptors //===----------------------------------------------------------------------===// -static char early_alloc_buf[128]; -static bool used_early_alloc_buf; +static const uptr early_alloc_buf_size = 4096; +static uptr allocated_bytes; +static char early_alloc_buf[early_alloc_buf_size]; +static bool isInEarlyAllocBuf(const void *ptr) { + return ((uptr)ptr >= (uptr)early_alloc_buf && + ((uptr)ptr - (uptr)early_alloc_buf) < sizeof(early_alloc_buf)); +} + static void *handleEarlyAlloc(uptr size) { // If esan is initialized during an interceptor (which happens with some // tcmalloc implementations that call pthread_mutex_lock), the call from - // dlsym to calloc will deadlock. There is only one such calloc (dlsym - // allocates a single pthread key), so we work around it by using a - // static buffer for the calloc request. The loader currently needs - // 32 bytes but we size at 128 to allow for future changes. + // dlsym to calloc will deadlock. + // dlsym may also call malloc before REAL(malloc) is retrieved from dlsym. + // We work around it by using a static buffer for the early malloc/calloc + // requests. // This solution will also allow us to deliberately intercept malloc & family // in the future (to perform tool actions on each allocation, without // replacing the allocator), as it also solves the problem of intercepting // calloc when it will itself be called before its REAL pointer is // initialized. - CHECK(!used_early_alloc_buf && size < sizeof(early_alloc_buf)); // We do not handle multiple threads here. This only happens at process init // time, and while it's possible for a shared library to create early threads // that race here, we consider that to be a corner case extreme enough that // it's not worth the effort to handle. - used_early_alloc_buf = true; - return (void *)early_alloc_buf; + void *mem = (void *)&early_alloc_buf[allocated_bytes]; + allocated_bytes += size; + CHECK_LT(allocated_bytes, early_alloc_buf_size); + return mem; } INTERCEPTOR(void*, calloc, uptr size, uptr n) { if (EsanDuringInit && REAL(calloc) == nullptr) return handleEarlyAlloc(size * n); void *ctx; COMMON_INTERCEPTOR_ENTER(ctx, calloc, size, n); void *res = REAL(calloc)(size, n); // The memory is zeroed and thus is all written. COMMON_INTERCEPTOR_WRITE_RANGE(nullptr, (uptr)res, size * n); return res; } +INTERCEPTOR(void*, malloc, uptr size) { + if (EsanDuringInit && REAL(malloc) == nullptr) + return handleEarlyAlloc(size); + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, malloc, size); + return REAL(malloc)(size); +} + INTERCEPTOR(void, free, void *p) { void *ctx; - COMMON_INTERCEPTOR_ENTER(ctx, free, p); - if (p == (void *)early_alloc_buf) { - // We expect just a singleton use but we clear this for cleanliness. - used_early_alloc_buf = false; + // There are only a few early allocation requests, so we simply skip the free. + if (isInEarlyAllocBuf(p)) return; - } + COMMON_INTERCEPTOR_ENTER(ctx, free, p); REAL(free)(p); } namespace __esan { void initializeInterceptors() { InitializeCommonInterceptors(); INTERCEPT_FUNCTION(strcpy); // NOLINT INTERCEPT_FUNCTION(strncpy); INTERCEPT_FUNCTION(open); ESAN_MAYBE_INTERCEPT_OPEN64; INTERCEPT_FUNCTION(creat); ESAN_MAYBE_INTERCEPT_CREAT64; INTERCEPT_FUNCTION(unlink); INTERCEPT_FUNCTION(fread); INTERCEPT_FUNCTION(fwrite); INTERCEPT_FUNCTION(puts); INTERCEPT_FUNCTION(rmdir); INTERCEPT_FUNCTION(mmap); ESAN_MAYBE_INTERCEPT_MMAP64; ESAN_MAYBE_INTERCEPT_SIGNAL; ESAN_MAYBE_INTERCEPT_SIGACTION; ESAN_MAYBE_INTERCEPT_SIGPROCMASK; ESAN_MAYBE_INTERCEPT_PTHREAD_SIGMASK; INTERCEPT_FUNCTION(calloc); + INTERCEPT_FUNCTION(malloc); INTERCEPT_FUNCTION(free); // TODO(bruening): intercept routines that other sanitizers intercept that // are not in the common pool or here yet, ideally by adding to the common // pool. Examples include wcslen and bcopy. // TODO(bruening): there are many more libc routines that read or write data // structures that no sanitizer is intercepting: sigaction, strtol, etc. } } // namespace __esan Index: projects/clang400-import/contrib/compiler-rt/lib/esan/esan_interface_internal.h =================================================================== --- projects/clang400-import/contrib/compiler-rt/lib/esan/esan_interface_internal.h (revision 311696) +++ projects/clang400-import/contrib/compiler-rt/lib/esan/esan_interface_internal.h (revision 311697) @@ -1,80 +1,83 @@ //===-- esan_interface_internal.h -------------------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // This file is a part of EfficiencySanitizer, a family of performance tuners. // // Calls to the functions declared in this header will be inserted by // the instrumentation module. //===----------------------------------------------------------------------===// #ifndef ESAN_INTERFACE_INTERNAL_H #define ESAN_INTERFACE_INTERNAL_H #include // This header should NOT include any other headers. // All functions in this header are extern "C" and start with __esan_. +using __sanitizer::uptr; +using __sanitizer::u32; + extern "C" { // This should be kept consistent with LLVM's EfficiencySanitizerOptions. // The value is passed as a 32-bit integer by the compiler. typedef enum Type : u32 { ESAN_None = 0, ESAN_CacheFrag, ESAN_WorkingSet, ESAN_Max, } ToolType; // To handle interceptors that invoke instrumented code prior to // __esan_init() being called, the instrumentation module creates this // global variable specifying the tool. extern ToolType __esan_which_tool; // This function should be called at the very beginning of the process, // before any instrumented code is executed and before any call to malloc. SANITIZER_INTERFACE_ATTRIBUTE void __esan_init(ToolType Tool, void *Ptr); SANITIZER_INTERFACE_ATTRIBUTE void __esan_exit(void *Ptr); // The instrumentation module will insert a call to one of these routines prior // to each load and store instruction for which we do not have "fastpath" // inlined instrumentation. These calls constitute the "slowpath" for our // tools. We have separate routines for each type of memory access to enable // targeted optimization. SANITIZER_INTERFACE_ATTRIBUTE void __esan_aligned_load1(void *Addr); SANITIZER_INTERFACE_ATTRIBUTE void __esan_aligned_load2(void *Addr); SANITIZER_INTERFACE_ATTRIBUTE void __esan_aligned_load4(void *Addr); SANITIZER_INTERFACE_ATTRIBUTE void __esan_aligned_load8(void *Addr); SANITIZER_INTERFACE_ATTRIBUTE void __esan_aligned_load16(void *Addr); SANITIZER_INTERFACE_ATTRIBUTE void __esan_aligned_store1(void *Addr); SANITIZER_INTERFACE_ATTRIBUTE void __esan_aligned_store2(void *Addr); SANITIZER_INTERFACE_ATTRIBUTE void __esan_aligned_store4(void *Addr); SANITIZER_INTERFACE_ATTRIBUTE void __esan_aligned_store8(void *Addr); SANITIZER_INTERFACE_ATTRIBUTE void __esan_aligned_store16(void *Addr); SANITIZER_INTERFACE_ATTRIBUTE void __esan_unaligned_load2(void *Addr); SANITIZER_INTERFACE_ATTRIBUTE void __esan_unaligned_load4(void *Addr); SANITIZER_INTERFACE_ATTRIBUTE void __esan_unaligned_load8(void *Addr); SANITIZER_INTERFACE_ATTRIBUTE void __esan_unaligned_load16(void *Addr); SANITIZER_INTERFACE_ATTRIBUTE void __esan_unaligned_store2(void *Addr); SANITIZER_INTERFACE_ATTRIBUTE void __esan_unaligned_store4(void *Addr); SANITIZER_INTERFACE_ATTRIBUTE void __esan_unaligned_store8(void *Addr); SANITIZER_INTERFACE_ATTRIBUTE void __esan_unaligned_store16(void *Addr); // These cover unusually-sized accesses. SANITIZER_INTERFACE_ATTRIBUTE void __esan_unaligned_loadN(void *Addr, uptr Size); SANITIZER_INTERFACE_ATTRIBUTE void __esan_unaligned_storeN(void *Addr, uptr Size); } // extern "C" #endif // ESAN_INTERFACE_INTERNAL_H Index: projects/clang400-import/contrib/compiler-rt/lib/esan/esan_linux.cpp =================================================================== --- projects/clang400-import/contrib/compiler-rt/lib/esan/esan_linux.cpp (revision 311696) +++ projects/clang400-import/contrib/compiler-rt/lib/esan/esan_linux.cpp (revision 311697) @@ -1,83 +1,83 @@ //===-- esan.cpp ----------------------------------------------------------===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // This file is a part of EfficiencySanitizer, a family of performance tuners. // // Linux-specific code for the Esan run-time. //===----------------------------------------------------------------------===// #include "sanitizer_common/sanitizer_platform.h" #if SANITIZER_FREEBSD || SANITIZER_LINUX #include "esan.h" #include "esan_shadow.h" #include "interception/interception.h" #include "sanitizer_common/sanitizer_common.h" #include #include namespace __esan { void verifyAddressSpace() { -#if SANITIZER_LINUX && defined(__x86_64__) +#if SANITIZER_LINUX && (defined(__x86_64__) || SANITIZER_MIPS64) // The kernel determines its mmap base from the stack size limit. // Our Linux 64-bit shadow mapping assumes the stack limit is less than a // terabyte, which keeps the mmap region above 0x7e00'. uptr StackLimit = GetStackSizeLimitInBytes(); if (StackSizeIsUnlimited() || StackLimit > MaxStackSize) { VReport(1, "The stack size limit is beyond the maximum supported.\n" "Re-execing with a stack size below 1TB.\n"); SetStackSizeLimitInBytes(MaxStackSize); ReExec(); } #endif } static bool liesWithinSingleAppRegion(uptr Start, SIZE_T Size) { uptr AppStart, AppEnd; for (int i = 0; getAppRegion(i, &AppStart, &AppEnd); ++i) { if (Start >= AppStart && Start + Size - 1 <= AppEnd) { return true; } } return false; } bool fixMmapAddr(void **Addr, SIZE_T Size, int Flags) { if (*Addr) { if (!liesWithinSingleAppRegion((uptr)*Addr, Size)) { VPrintf(1, "mmap conflict: [%p-%p) is not in an app region\n", *Addr, (uptr)*Addr + Size); if (Flags & MAP_FIXED) { errno = EINVAL; return false; } else { *Addr = 0; } } } return true; } uptr checkMmapResult(uptr Addr, SIZE_T Size) { if ((void *)Addr == MAP_FAILED) return Addr; if (!liesWithinSingleAppRegion(Addr, Size)) { // FIXME: attempt to dynamically add this as an app region if it // fits our shadow criteria. // We could also try to remap somewhere else. Printf("ERROR: unsupported mapping at [%p-%p)\n", Addr, Addr+Size); Die(); } return Addr; } } // namespace __esan #endif // SANITIZER_FREEBSD || SANITIZER_LINUX Index: projects/clang400-import/contrib/compiler-rt/lib/esan/esan_shadow.h =================================================================== --- projects/clang400-import/contrib/compiler-rt/lib/esan/esan_shadow.h (revision 311696) +++ projects/clang400-import/contrib/compiler-rt/lib/esan/esan_shadow.h (revision 311697) @@ -1,203 +1,292 @@ //===-- esan_shadow.h -------------------------------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // This file is a part of EfficiencySanitizer, a family of performance tuners. // // Shadow memory mappings for the esan run-time. //===----------------------------------------------------------------------===// #ifndef ESAN_SHADOW_H #define ESAN_SHADOW_H +#include "esan.h" #include #if SANITIZER_WORDSIZE != 64 #error Only 64-bit is supported #endif namespace __esan { +struct ApplicationRegion { + uptr Start; + uptr End; + bool ShadowMergedWithPrev; +}; + #if SANITIZER_LINUX && defined(__x86_64__) // Linux x86_64 // // Application memory falls into these 5 regions (ignoring the corner case // of PIE with a non-zero PT_LOAD base): // // [0x00000000'00000000, 0x00000100'00000000) non-PIE + heap // [0x00005500'00000000, 0x00005700'00000000) PIE // [0x00007e00'00000000, 0x00007fff'ff600000) libraries + stack, part 1 // [0x00007fff'ff601000, 0x00008000'00000000) libraries + stack, part 2 // [0xffffffff'ff600000, 0xffffffff'ff601000) vsyscall // // Although we can ignore the vsyscall for the most part as there are few data // references there (other sanitizers ignore it), we enforce a gap inside the // library region to distinguish the vsyscall's shadow, considering this gap to // be an invalid app region. // We disallow application memory outside of those 5 regions. // Our regions assume that the stack rlimit is less than a terabyte (otherwise // the Linux kernel's default mmap region drops below 0x7e00'), which we enforce // at init time (we can support larger and unlimited sizes for shadow // scaledowns, but it is difficult for 1:1 mappings). // // Our shadow memory is scaled from a 1:1 mapping and supports a scale // specified at library initialization time that can be any power-of-2 // scaledown (1x, 2x, 4x, 8x, 16x, etc.). // // We model our shadow memory after Umbra, a library used by the Dr. Memory // tool: https://github.com/DynamoRIO/drmemory/blob/master/umbra/umbra_x64.c. // We use Umbra's scheme as it was designed to support different // offsets, it supports two different shadow mappings (which we may want to // use for future tools), and it ensures that the shadow of a shadow will // not overlap either shadow memory or application memory. // // This formula translates from application memory to shadow memory: // // shadow(app) = ((app & 0x00000fff'ffffffff) + offset) >> scale // // Where the offset for 1:1 is 0x00001300'00000000. For other scales, the // offset is shifted left by the scale, except for scales of 1 and 2 where // it must be tweaked in order to pass the double-shadow test // (see the "shadow(shadow)" comments below): // scale == 0: 0x00001300'000000000 // scale == 1: 0x00002200'000000000 // scale == 2: 0x00004400'000000000 // scale >= 3: (0x00001300'000000000 << scale) // // Do not pass in the open-ended end value to the formula as it will fail. // // The resulting shadow memory regions for a 0 scaling are: // // [0x00001300'00000000, 0x00001400'00000000) // [0x00001800'00000000, 0x00001a00'00000000) // [0x00002100'00000000, 0x000022ff'ff600000) // [0x000022ff'ff601000, 0x00002300'00000000) // [0x000022ff'ff600000, 0x000022ff'ff601000] // // We also want to ensure that a wild access by the application into the shadow // regions will not corrupt our own shadow memory. shadow(shadow) ends up // disjoint from shadow(app): // // [0x00001600'00000000, 0x00001700'00000000) // [0x00001b00'00000000, 0x00001d00'00000000) // [0x00001400'00000000, 0x000015ff'ff600000] // [0x000015ff'ff601000, 0x00001600'00000000] // [0x000015ff'ff600000, 0x000015ff'ff601000] -struct ApplicationRegion { - uptr Start; - uptr End; - bool ShadowMergedWithPrev; -}; - static const struct ApplicationRegion AppRegions[] = { {0x0000000000000000ull, 0x0000010000000000u, false}, {0x0000550000000000u, 0x0000570000000000u, false}, // We make one shadow mapping to hold the shadow regions for all 3 of these // app regions, as the mappings interleave, and the gap between the 3rd and // 4th scales down below a page. {0x00007e0000000000u, 0x00007fffff600000u, false}, {0x00007fffff601000u, 0x0000800000000000u, true}, {0xffffffffff600000u, 0xffffffffff601000u, true}, }; + +#elif SANITIZER_LINUX && SANITIZER_MIPS64 + +// Application memory falls into these 3 regions +// +// [0x00000001'00000000, 0x00000002'00000000) non-PIE + heap +// [0x000000aa'00000000, 0x000000ab'00000000) PIE +// [0x000000ff'00000000, 0x000000ff'ffffffff) libraries + stack +// +// This formula translates from application memory to shadow memory: +// +// shadow(app) = ((app & 0x00000f'ffffffff) + offset) >> scale +// +// Where the offset for 1:1 is 0x000013'00000000. For other scales, the +// offset is shifted left by the scale, except for scales of 1 and 2 where +// it must be tweaked in order to pass the double-shadow test +// (see the "shadow(shadow)" comments below): +// scale == 0: 0x000013'00000000 +// scale == 1: 0x000022'00000000 +// scale == 2: 0x000044'00000000 +// scale >= 3: (0x000013'00000000 << scale) +// +// The resulting shadow memory regions for a 0 scaling are: +// +// [0x00000014'00000000, 0x00000015'00000000) +// [0x0000001d'00000000, 0x0000001e'00000000) +// [0x00000022'00000000, 0x00000022'ffffffff) +// +// We also want to ensure that a wild access by the application into the shadow +// regions will not corrupt our own shadow memory. shadow(shadow) ends up +// disjoint from shadow(app): +// +// [0x00000017'00000000, 0x00000018'00000000) +// [0x00000020'00000000, 0x00000021'00000000) +// [0x00000015'00000000, 0x00000015'ffffffff] + +static const struct ApplicationRegion AppRegions[] = { + {0x0100000000u, 0x0200000000u, false}, + {0xaa00000000u, 0xab00000000u, false}, + {0xff00000000u, 0xffffffffffu, false}, +}; + +#else +#error Platform not supported +#endif + static const u32 NumAppRegions = sizeof(AppRegions)/sizeof(AppRegions[0]); // See the comment above: we do not currently support a stack size rlimit // equal to or larger than 1TB. static const uptr MaxStackSize = (1ULL << 40) - 4096; class ShadowMapping { public: - static const uptr Mask = 0x00000fffffffffffu; + // The scale and offset vary by tool. uptr Scale; uptr Offset; + + // TODO(sagar.thakur): Try to hardcode the mask as done in the compiler + // instrumentation to reduce the runtime cost of appToShadow. + struct ShadowMemoryMask40 { + static const uptr Mask = 0x0000000fffffffffu; + }; + + struct ShadowMemoryMask47 { + static const uptr Mask = 0x00000fffffffffffu; + }; + void initialize(uptr ShadowScale) { - static const uptr OffsetArray[3] = { - 0x0000130000000000u, - 0x0000220000000000u, - 0x0000440000000000u, + + const uptr OffsetArray40[3] = { + 0x0000001300000000u, + 0x0000002200000000u, + 0x0000004400000000u, }; + + const uptr OffsetArray47[3] = { + 0x0000130000000000u, + 0x0000220000000000u, + 0x0000440000000000u, + }; + Scale = ShadowScale; - if (Scale <= 2) - Offset = OffsetArray[Scale]; - else - Offset = OffsetArray[0] << Scale; + switch (VmaSize) { + case 40: { + if (Scale <= 2) + Offset = OffsetArray40[Scale]; + else + Offset = OffsetArray40[0] << Scale; + } + break; + case 47: { + if (Scale <= 2) + Offset = OffsetArray47[Scale]; + else + Offset = OffsetArray47[0] << Scale; + } + break; + default: { + Printf("ERROR: %d-bit virtual memory address size not supported\n", VmaSize); + Die(); + } + } } }; extern ShadowMapping Mapping; -#else -// We'll want to use templatized functions over the ShadowMapping once -// we support more platforms. -#error Platform not supported -#endif static inline bool getAppRegion(u32 i, uptr *Start, uptr *End) { if (i >= NumAppRegions) return false; *Start = AppRegions[i].Start; *End = AppRegions[i].End; return true; } ALWAYS_INLINE bool isAppMem(uptr Mem) { for (u32 i = 0; i < NumAppRegions; ++i) { if (Mem >= AppRegions[i].Start && Mem < AppRegions[i].End) return true; } return false; } +template +uptr appToShadowImpl(uptr App) { + return (((App & Params::Mask) + Mapping.Offset) >> Mapping.Scale); +} + ALWAYS_INLINE uptr appToShadow(uptr App) { - return (((App & ShadowMapping::Mask) + Mapping.Offset) >> Mapping.Scale); + switch (VmaSize) { + case 40: return appToShadowImpl(App); + case 47: return appToShadowImpl(App); + default: { + Printf("ERROR: %d-bit virtual memory address size not supported\n", VmaSize); + Die(); + } + } } static inline bool getShadowRegion(u32 i, uptr *Start, uptr *End) { if (i >= NumAppRegions) return false; u32 UnmergedShadowCount = 0; u32 AppIdx; for (AppIdx = 0; AppIdx < NumAppRegions; ++AppIdx) { if (!AppRegions[AppIdx].ShadowMergedWithPrev) { if (UnmergedShadowCount == i) break; UnmergedShadowCount++; } } if (AppIdx >= NumAppRegions || UnmergedShadowCount != i) return false; *Start = appToShadow(AppRegions[AppIdx].Start); // The formula fails for the end itself. *End = appToShadow(AppRegions[AppIdx].End - 1) + 1; // Merge with adjacent shadow regions: for (++AppIdx; AppIdx < NumAppRegions; ++AppIdx) { if (!AppRegions[AppIdx].ShadowMergedWithPrev) break; *Start = Min(*Start, appToShadow(AppRegions[AppIdx].Start)); *End = Max(*End, appToShadow(AppRegions[AppIdx].End - 1) + 1); } return true; } ALWAYS_INLINE bool isShadowMem(uptr Mem) { // We assume this is not used on any critical performance path and so there's // no need to hardcode the mapping results. for (uptr i = 0; i < NumAppRegions; ++i) { if (Mem >= appToShadow(AppRegions[i].Start) && Mem < appToShadow(AppRegions[i].End - 1) + 1) return true; } return false; } } // namespace __esan #endif /* ESAN_SHADOW_H */ Index: projects/clang400-import/contrib/compiler-rt/lib/interception/interception.h =================================================================== --- projects/clang400-import/contrib/compiler-rt/lib/interception/interception.h (revision 311696) +++ projects/clang400-import/contrib/compiler-rt/lib/interception/interception.h (revision 311697) @@ -1,261 +1,263 @@ //===-- interception.h ------------------------------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // This file is a part of AddressSanitizer, an address sanity checker. // // Machinery for providing replacements/wrappers for system functions. //===----------------------------------------------------------------------===// #ifndef INTERCEPTION_H #define INTERCEPTION_H #if !defined(__linux__) && !defined(__FreeBSD__) && \ !defined(__APPLE__) && !defined(_WIN32) # error "Interception doesn't work on this operating system." #endif #include "sanitizer_common/sanitizer_internal_defs.h" // These typedefs should be used only in the interceptor definitions to replace // the standard system types (e.g. SSIZE_T instead of ssize_t) typedef __sanitizer::uptr SIZE_T; typedef __sanitizer::sptr SSIZE_T; typedef __sanitizer::sptr PTRDIFF_T; typedef __sanitizer::s64 INTMAX_T; typedef __sanitizer::OFF_T OFF_T; typedef __sanitizer::OFF64_T OFF64_T; // How to add an interceptor: // Suppose you need to wrap/replace system function (generally, from libc): // int foo(const char *bar, double baz); // You'll need to: // 1) define INTERCEPTOR(int, foo, const char *bar, double baz) { ... } in // your source file. See the notes below for cases when // INTERCEPTOR_WITH_SUFFIX(...) should be used instead. // 2) Call "INTERCEPT_FUNCTION(foo)" prior to the first call of "foo". // INTERCEPT_FUNCTION(foo) evaluates to "true" iff the function was // intercepted successfully. // You can access original function by calling REAL(foo)(bar, baz). // By default, REAL(foo) will be visible only inside your interceptor, and if // you want to use it in other parts of RTL, you'll need to: // 3a) add DECLARE_REAL(int, foo, const char*, double) to a // header file. // However, if the call "INTERCEPT_FUNCTION(foo)" and definition for // INTERCEPTOR(..., foo, ...) are in different files, you'll instead need to: // 3b) add DECLARE_REAL_AND_INTERCEPTOR(int, foo, const char*, double) // to a header file. // Notes: 1. Things may not work properly if macro INTERCEPTOR(...) {...} or // DECLARE_REAL(...) are located inside namespaces. // 2. On Mac you can also use: "OVERRIDE_FUNCTION(foo, zoo)" to // effectively redirect calls from "foo" to "zoo". In this case // you aren't required to implement // INTERCEPTOR(int, foo, const char *bar, double baz) {...} // but instead you'll have to add // DECLARE_REAL(int, foo, const char *bar, double baz) in your // source file (to define a pointer to overriden function). // 3. Some Mac functions have symbol variants discriminated by // additional suffixes, e.g. _$UNIX2003 (see // https://developer.apple.com/library/mac/#releasenotes/Darwin/SymbolVariantsRelNotes/index.html // for more details). To intercept such functions you need to use the // INTERCEPTOR_WITH_SUFFIX(...) macro. // How it works: // To replace system functions on Linux we just need to declare functions // with same names in our library and then obtain the real function pointers // using dlsym(). // There is one complication. A user may also intercept some of the functions // we intercept. To resolve this we declare our interceptors with __interceptor_ // prefix, and then make actual interceptors weak aliases to __interceptor_ // functions. // // This is not so on Mac OS, where the two-level namespace makes // our replacement functions invisible to other libraries. This may be overcomed // using the DYLD_FORCE_FLAT_NAMESPACE, but some errors loading the shared // libraries in Chromium were noticed when doing so. // Instead we create a dylib containing a __DATA,__interpose section that // associates library functions with their wrappers. When this dylib is // preloaded before an executable using DYLD_INSERT_LIBRARIES, it routes all // the calls to interposed functions done through stubs to the wrapper // functions. // As it's decided at compile time which functions are to be intercepted on Mac, // INTERCEPT_FUNCTION() is effectively a no-op on this system. #if defined(__APPLE__) #include // For __DARWIN_ALIAS_C(). // Just a pair of pointers. struct interpose_substitution { - const uptr replacement; - const uptr original; + const __sanitizer::uptr replacement; + const __sanitizer::uptr original; }; // For a function foo() create a global pair of pointers { wrap_foo, foo } in // the __DATA,__interpose section. // As a result all the calls to foo() will be routed to wrap_foo() at runtime. #define INTERPOSER(func_name) __attribute__((used)) \ const interpose_substitution substitution_##func_name[] \ __attribute__((section("__DATA, __interpose"))) = { \ { reinterpret_cast(WRAP(func_name)), \ reinterpret_cast(func_name) } \ } // For a function foo() and a wrapper function bar() create a global pair // of pointers { bar, foo } in the __DATA,__interpose section. // As a result all the calls to foo() will be routed to bar() at runtime. #define INTERPOSER_2(func_name, wrapper_name) __attribute__((used)) \ const interpose_substitution substitution_##func_name[] \ __attribute__((section("__DATA, __interpose"))) = { \ { reinterpret_cast(wrapper_name), \ reinterpret_cast(func_name) } \ } # define WRAP(x) wrap_##x # define WRAPPER_NAME(x) "wrap_"#x # define INTERCEPTOR_ATTRIBUTE # define DECLARE_WRAPPER(ret_type, func, ...) #elif defined(_WIN32) # define WRAP(x) __asan_wrap_##x # define WRAPPER_NAME(x) "__asan_wrap_"#x # define INTERCEPTOR_ATTRIBUTE __declspec(dllexport) # define DECLARE_WRAPPER(ret_type, func, ...) \ extern "C" ret_type func(__VA_ARGS__); # define DECLARE_WRAPPER_WINAPI(ret_type, func, ...) \ extern "C" __declspec(dllimport) ret_type __stdcall func(__VA_ARGS__); #elif defined(__FreeBSD__) # define WRAP(x) __interceptor_ ## x # define WRAPPER_NAME(x) "__interceptor_" #x # define INTERCEPTOR_ATTRIBUTE __attribute__((visibility("default"))) // FreeBSD's dynamic linker (incompliantly) gives non-weak symbols higher // priority than weak ones so weak aliases won't work for indirect calls // in position-independent (-fPIC / -fPIE) mode. # define DECLARE_WRAPPER(ret_type, func, ...) \ extern "C" ret_type func(__VA_ARGS__) \ __attribute__((alias("__interceptor_" #func), visibility("default"))); #else # define WRAP(x) __interceptor_ ## x # define WRAPPER_NAME(x) "__interceptor_" #x # define INTERCEPTOR_ATTRIBUTE __attribute__((visibility("default"))) # define DECLARE_WRAPPER(ret_type, func, ...) \ extern "C" ret_type func(__VA_ARGS__) \ __attribute__((weak, alias("__interceptor_" #func), visibility("default"))); #endif #if !defined(__APPLE__) # define PTR_TO_REAL(x) real_##x # define REAL(x) __interception::PTR_TO_REAL(x) # define FUNC_TYPE(x) x##_f # define DECLARE_REAL(ret_type, func, ...) \ typedef ret_type (*FUNC_TYPE(func))(__VA_ARGS__); \ namespace __interception { \ extern FUNC_TYPE(func) PTR_TO_REAL(func); \ } +# define ASSIGN_REAL(dst, src) REAL(dst) = REAL(src) #else // __APPLE__ # define REAL(x) x # define DECLARE_REAL(ret_type, func, ...) \ extern "C" ret_type func(__VA_ARGS__); +# define ASSIGN_REAL(x, y) #endif // __APPLE__ #define DECLARE_REAL_AND_INTERCEPTOR(ret_type, func, ...) \ DECLARE_REAL(ret_type, func, __VA_ARGS__) \ extern "C" ret_type WRAP(func)(__VA_ARGS__); // Generally, you don't need to use DEFINE_REAL by itself, as INTERCEPTOR // macros does its job. In exceptional cases you may need to call REAL(foo) // without defining INTERCEPTOR(..., foo, ...). For example, if you override // foo with an interceptor for other function. #if !defined(__APPLE__) # define DEFINE_REAL(ret_type, func, ...) \ typedef ret_type (*FUNC_TYPE(func))(__VA_ARGS__); \ namespace __interception { \ FUNC_TYPE(func) PTR_TO_REAL(func); \ } #else # define DEFINE_REAL(ret_type, func, ...) #endif #if !defined(__APPLE__) #define INTERCEPTOR(ret_type, func, ...) \ DEFINE_REAL(ret_type, func, __VA_ARGS__) \ DECLARE_WRAPPER(ret_type, func, __VA_ARGS__) \ extern "C" \ INTERCEPTOR_ATTRIBUTE \ ret_type WRAP(func)(__VA_ARGS__) // We don't need INTERCEPTOR_WITH_SUFFIX on non-Darwin for now. #define INTERCEPTOR_WITH_SUFFIX(ret_type, func, ...) \ INTERCEPTOR(ret_type, func, __VA_ARGS__) #else // __APPLE__ #define INTERCEPTOR_ZZZ(suffix, ret_type, func, ...) \ extern "C" ret_type func(__VA_ARGS__) suffix; \ extern "C" ret_type WRAP(func)(__VA_ARGS__); \ INTERPOSER(func); \ extern "C" INTERCEPTOR_ATTRIBUTE ret_type WRAP(func)(__VA_ARGS__) #define INTERCEPTOR(ret_type, func, ...) \ INTERCEPTOR_ZZZ(/*no symbol variants*/, ret_type, func, __VA_ARGS__) #define INTERCEPTOR_WITH_SUFFIX(ret_type, func, ...) \ INTERCEPTOR_ZZZ(__DARWIN_ALIAS_C(func), ret_type, func, __VA_ARGS__) // Override |overridee| with |overrider|. #define OVERRIDE_FUNCTION(overridee, overrider) \ INTERPOSER_2(overridee, WRAP(overrider)) #endif #if defined(_WIN32) # define INTERCEPTOR_WINAPI(ret_type, func, ...) \ typedef ret_type (__stdcall *FUNC_TYPE(func))(__VA_ARGS__); \ namespace __interception { \ FUNC_TYPE(func) PTR_TO_REAL(func); \ } \ extern "C" \ INTERCEPTOR_ATTRIBUTE \ ret_type __stdcall WRAP(func)(__VA_ARGS__) #endif // ISO C++ forbids casting between pointer-to-function and pointer-to-object, // so we use casting via an integral type __interception::uptr, // assuming that system is POSIX-compliant. Using other hacks seem // challenging, as we don't even pass function type to // INTERCEPT_FUNCTION macro, only its name. namespace __interception { #if defined(_WIN64) typedef unsigned long long uptr; // NOLINT #else typedef unsigned long uptr; // NOLINT #endif // _WIN64 } // namespace __interception #define INCLUDED_FROM_INTERCEPTION_LIB #if defined(__linux__) || defined(__FreeBSD__) # include "interception_linux.h" # define INTERCEPT_FUNCTION(func) INTERCEPT_FUNCTION_LINUX_OR_FREEBSD(func) # define INTERCEPT_FUNCTION_VER(func, symver) \ INTERCEPT_FUNCTION_VER_LINUX_OR_FREEBSD(func, symver) #elif defined(__APPLE__) # include "interception_mac.h" # define INTERCEPT_FUNCTION(func) INTERCEPT_FUNCTION_MAC(func) # define INTERCEPT_FUNCTION_VER(func, symver) \ INTERCEPT_FUNCTION_VER_MAC(func, symver) #else // defined(_WIN32) # include "interception_win.h" # define INTERCEPT_FUNCTION(func) INTERCEPT_FUNCTION_WIN(func) # define INTERCEPT_FUNCTION_VER(func, symver) \ INTERCEPT_FUNCTION_VER_WIN(func, symver) #endif #undef INCLUDED_FROM_INTERCEPTION_LIB #endif // INTERCEPTION_H Index: projects/clang400-import/contrib/compiler-rt/lib/interception/interception_win.cc =================================================================== --- projects/clang400-import/contrib/compiler-rt/lib/interception/interception_win.cc (revision 311696) +++ projects/clang400-import/contrib/compiler-rt/lib/interception/interception_win.cc (revision 311697) @@ -1,912 +1,1006 @@ //===-- interception_linux.cc -----------------------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // This file is a part of AddressSanitizer, an address sanity checker. // // Windows-specific interception methods. // // This file is implementing several hooking techniques to intercept calls // to functions. The hooks are dynamically installed by modifying the assembly // code. // // The hooking techniques are making assumptions on the way the code is // generated and are safe under these assumptions. // // On 64-bit architecture, there is no direct 64-bit jump instruction. To allow // arbitrary branching on the whole memory space, the notion of trampoline // region is used. A trampoline region is a memory space withing 2G boundary // where it is safe to add custom assembly code to build 64-bit jumps. // // Hooking techniques // ================== // // 1) Detour // // The Detour hooking technique is assuming the presence of an header with // padding and an overridable 2-bytes nop instruction (mov edi, edi). The // nop instruction can safely be replaced by a 2-bytes jump without any need // to save the instruction. A jump to the target is encoded in the function // header and the nop instruction is replaced by a short jump to the header. // // head: 5 x nop head: jmp // func: mov edi, edi --> func: jmp short // [...] real: [...] // // This technique is only implemented on 32-bit architecture. // Most of the time, Windows API are hookable with the detour technique. // // 2) Redirect Jump // // The redirect jump is applicable when the first instruction is a direct // jump. The instruction is replaced by jump to the hook. // // func: jmp