Index: projects/clang500-import/contrib/compiler-rt/include/sanitizer/common_interface_defs.h =================================================================== --- projects/clang500-import/contrib/compiler-rt/include/sanitizer/common_interface_defs.h (revision 317284) +++ projects/clang500-import/contrib/compiler-rt/include/sanitizer/common_interface_defs.h (revision 317285) @@ -1,196 +1,198 @@ //===-- 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. + // At most `max_number_of_contexts` contexts (stack traces) is printed. // Experimental feature currently available only with asan on Linux/x86_64. - void __sanitizer_print_memory_profile(size_t top_percent); + void __sanitizer_print_memory_profile(size_t top_percent, + size_t max_number_of_contexts); // 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, 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/clang500-import/contrib/compiler-rt/include/sanitizer/coverage_interface.h =================================================================== --- projects/clang500-import/contrib/compiler-rt/include/sanitizer/coverage_interface.h (revision 317284) +++ projects/clang500-import/contrib/compiler-rt/include/sanitizer/coverage_interface.h (revision 317285) @@ -1,71 +1,42 @@ //===-- 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); - - // 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/clang500-import/contrib/compiler-rt/include/sanitizer/tsan_interface.h =================================================================== --- projects/clang500-import/contrib/compiler-rt/include/sanitizer/tsan_interface.h (nonexistent) +++ projects/clang500-import/contrib/compiler-rt/include/sanitizer/tsan_interface.h (revision 317285) @@ -0,0 +1,121 @@ +//===-- tsan_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 ThreadSanitizer (TSan), a race detector. +// +// Public interface header for TSan. +//===----------------------------------------------------------------------===// +#ifndef SANITIZER_TSAN_INTERFACE_H +#define SANITIZER_TSAN_INTERFACE_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +// __tsan_release establishes a happens-before relation with a preceding +// __tsan_acquire on the same address. +void __tsan_acquire(void *addr); +void __tsan_release(void *addr); + +// Annotations for custom mutexes. +// The annotations allow to get better reports (with sets of locked mutexes), +// detect more types of bugs (e.g. mutex misuses, races between lock/unlock and +// destruction and potential deadlocks) and improve precision and performance +// (by ignoring individual atomic operations in mutex code). However, the +// downside is that annotated mutex code itself is not checked for correctness. + +// Mutex creation flags are passed to __tsan_mutex_create annotation. +// If mutex has no constructor and __tsan_mutex_create is not called, +// the flags may be passed to __tsan_mutex_pre_lock/__tsan_mutex_post_lock +// annotations. + +// Mutex has static storage duration and no-op constructor and destructor. +// This effectively makes tsan ignore destroy annotation. +const unsigned __tsan_mutex_linker_init = 1 << 0; +// Mutex is write reentrant. +const unsigned __tsan_mutex_write_reentrant = 1 << 1; +// Mutex is read reentrant. +const unsigned __tsan_mutex_read_reentrant = 1 << 2; + +// Mutex operation flags: + +// Denotes read lock operation. +const unsigned __tsan_mutex_read_lock = 1 << 3; +// Denotes try lock operation. +const unsigned __tsan_mutex_try_lock = 1 << 4; +// Denotes that a try lock operation has failed to acquire the mutex. +const unsigned __tsan_mutex_try_lock_failed = 1 << 5; +// Denotes that the lock operation acquires multiple recursion levels. +// Number of levels is passed in recursion parameter. +// This is useful for annotation of e.g. Java builtin monitors, +// for which wait operation releases all recursive acquisitions of the mutex. +const unsigned __tsan_mutex_recursive_lock = 1 << 6; +// Denotes that the unlock operation releases all recursion levels. +// Number of released levels is returned and later must be passed to +// the corresponding __tsan_mutex_post_lock annotation. +const unsigned __tsan_mutex_recursive_unlock = 1 << 7; + +// Annotate creation of a mutex. +// Supported flags: mutex creation flags. +void __tsan_mutex_create(void *addr, unsigned flags); + +// Annotate destruction of a mutex. +// Supported flags: none. +void __tsan_mutex_destroy(void *addr, unsigned flags); + +// Annotate start of lock operation. +// Supported flags: +// - __tsan_mutex_read_lock +// - __tsan_mutex_try_lock +// - all mutex creation flags +void __tsan_mutex_pre_lock(void *addr, unsigned flags); + +// Annotate end of lock operation. +// Supported flags: +// - __tsan_mutex_read_lock (must match __tsan_mutex_pre_lock) +// - __tsan_mutex_try_lock (must match __tsan_mutex_pre_lock) +// - __tsan_mutex_try_lock_failed +// - __tsan_mutex_recursive_lock +// - all mutex creation flags +void __tsan_mutex_post_lock(void *addr, unsigned flags, int recursion); + +// Annotate start of unlock operation. +// Supported flags: +// - __tsan_mutex_read_lock +// - __tsan_mutex_recursive_unlock +int __tsan_mutex_pre_unlock(void *addr, unsigned flags); + +// Annotate end of unlock operation. +// Supported flags: +// - __tsan_mutex_read_lock (must match __tsan_mutex_pre_unlock) +void __tsan_mutex_post_unlock(void *addr, unsigned flags); + +// Annotate start/end of notify/signal/broadcast operation. +// Supported flags: none. +void __tsan_mutex_pre_signal(void *addr, unsigned flags); +void __tsan_mutex_post_signal(void *addr, unsigned flags); + +// Annotate start/end of a region of code where lock/unlock/signal operation +// diverts to do something else unrelated to the mutex. This can be used to +// annotate, for example, calls into cooperative scheduler or contention +// profiling code. +// These annotations must be called only from within +// __tsan_mutex_pre/post_lock, __tsan_mutex_pre/post_unlock, +// __tsan_mutex_pre/post_signal regions. +// Supported flags: none. +void __tsan_mutex_pre_divert(void *addr, unsigned flags); +void __tsan_mutex_post_divert(void *addr, unsigned flags); + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // SANITIZER_TSAN_INTERFACE_H Property changes on: projects/clang500-import/contrib/compiler-rt/include/sanitizer/tsan_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/clang500-import/contrib/compiler-rt/include/xray/xray_interface.h =================================================================== --- projects/clang500-import/contrib/compiler-rt/include/xray/xray_interface.h (revision 317284) +++ projects/clang500-import/contrib/compiler-rt/include/xray/xray_interface.h (revision 317285) @@ -1,65 +1,82 @@ //===-- 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 }; +// Synchronize this with AsmPrinter::SledKind in LLVM. +enum XRayEntryType { + ENTRY = 0, + EXIT = 1, + TAIL = 2, + LOG_ARGS_ENTRY = 3, +}; // 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(); + +// Use XRay to log the first argument of each (instrumented) function call. +// When this function exits, all threads will have observed the effect and +// start logging their subsequent affected function calls (if patched). +// +// Returns 1 on success, 0 on error. +extern int __xray_set_handler_arg1(void (*)(int32_t, XRayEntryType, uint64_t)); + +// Disables the XRay handler used to log first arguments of function calls. +// Returns 1 on success, 0 on error. +extern int __xray_remove_handler_arg1(); } #endif Index: projects/clang500-import/contrib/compiler-rt/include/xray/xray_log_interface.h =================================================================== --- projects/clang500-import/contrib/compiler-rt/include/xray/xray_log_interface.h (nonexistent) +++ projects/clang500-import/contrib/compiler-rt/include/xray/xray_log_interface.h (revision 317285) @@ -0,0 +1,60 @@ +//===-- xray_log_interface.h ----------------------------------------------===// +// +// 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 function call tracing system. +// +// APIs for installing a new logging implementation. +//===----------------------------------------------------------------------===// +#ifndef XRAY_XRAY_LOG_INTERFACE_H +#define XRAY_XRAY_LOG_INTERFACE_H + +#include "xray/xray_interface.h" +#include + +extern "C" { + +enum XRayLogInitStatus { + XRAY_LOG_UNINITIALIZED = 0, + XRAY_LOG_INITIALIZING = 1, + XRAY_LOG_INITIALIZED = 2, + XRAY_LOG_FINALIZING = 3, + XRAY_LOG_FINALIZED = 4, +}; + +enum XRayLogFlushStatus { + XRAY_LOG_NOT_FLUSHING = 0, + XRAY_LOG_FLUSHING = 1, + XRAY_LOG_FLUSHED = 2, +}; + +struct XRayLogImpl { + XRayLogInitStatus (*log_init)(size_t, size_t, void *, size_t); + XRayLogInitStatus (*log_finalize)(); + void (*handle_arg0)(int32_t, XRayEntryType); + XRayLogFlushStatus (*flush_log)(); +}; + +void __xray_set_log_impl(XRayLogImpl Impl); +XRayLogInitStatus __xray_log_init(size_t BufferSize, size_t MaxBuffers, + void *Args, size_t ArgsSize); +XRayLogInitStatus __xray_log_finalize(); +XRayLogFlushStatus __xray_log_flushLog(); + +} // extern "C" + +namespace __xray { +// Options used by the LLVM XRay FDR implementation. +struct FDRLoggingOptions { + bool ReportErrors = false; + int Fd = -1; +}; + +} // namespace __xray + +#endif // XRAY_XRAY_LOG_INTERFACE_H Property changes on: projects/clang500-import/contrib/compiler-rt/include/xray/xray_log_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/clang500-import/contrib/compiler-rt/include/xray/xray_records.h =================================================================== --- projects/clang500-import/contrib/compiler-rt/include/xray/xray_records.h (revision 317284) +++ projects/clang500-import/contrib/compiler-rt/include/xray/xray_records.h (revision 317285) @@ -1,80 +1,99 @@ //===-- 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, + FDR_LOG = 1, }; +// FDR mode use of the union field in the XRayFileHeader. +struct alignas(16) FdrAdditionalHeaderData { + uint64_t ThreadBufferSize; +}; + +static_assert(sizeof(FdrAdditionalHeaderData) == 16, + "FdrAdditionalHeaderData != 16 bytes"); + // 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; + + union { + char FreeForm[16]; + // The current civiltime timestamp, as retrived from 'clock_gettime'. This + // allows readers of the file to determine when the file was created or + // written down. + struct timespec TS; + + struct FdrAdditionalHeaderData FdrData; + }; } __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 Index: projects/clang500-import/contrib/compiler-rt/lib/asan/asan_globals_win.h =================================================================== --- projects/clang500-import/contrib/compiler-rt/lib/asan/asan_globals_win.h (revision 317284) +++ projects/clang500-import/contrib/compiler-rt/lib/asan/asan_globals_win.h (nonexistent) @@ -1,34 +0,0 @@ -//===-- 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/clang500-import/contrib/compiler-rt/lib/asan/asan_globals_win.h ___________________________________________________________________ Deleted: svn:eol-style ## -1 +0,0 ## -native \ No newline at end of property Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Deleted: svn:mime-type ## -1 +0,0 ## -text/plain \ No newline at end of property Index: projects/clang500-import/contrib/compiler-rt/lib/asan/asan.syms.extra =================================================================== --- projects/clang500-import/contrib/compiler-rt/lib/asan/asan.syms.extra (revision 317284) +++ projects/clang500-import/contrib/compiler-rt/lib/asan/asan.syms.extra (revision 317285) @@ -1,3 +1,4 @@ __asan_* __lsan_* __ubsan_* +__sancov_* Index: projects/clang500-import/contrib/compiler-rt/lib/asan/asan_allocator.cc =================================================================== --- projects/clang500-import/contrib/compiler-rt/lib/asan/asan_allocator.cc (revision 317284) +++ projects/clang500-import/contrib/compiler-rt/lib/asan/asan_allocator.cc (revision 317285) @@ -1,972 +1,996 @@ //===-- 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); 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, (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, options.release_to_os_interval_ms); SharedInitCode(options); } void RePoisonChunk(uptr chunk) { // This could be 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 && ac->chunk_state == CHUNK_ALLOCATED) { // Looks like a valid AsanChunk in use, poison redzones only. 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 is either not an AsanChunk or freed or quarantined AsanChunk. // In either case, poison everything. 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.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.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); + + Flags &fl = *flags(); + if (fl.max_free_fill_size > 0) { + // We have to skip the chunk header, it contains free_context_id. + uptr scribble_start = (uptr)m + kChunkHeaderSize + kChunkHeader2Size; + if (m->UsedSize() >= kChunkHeader2Size) { // Skip Header2 in user area. + uptr size_to_fill = m->UsedSize() - kChunkHeader2Size; + size_to_fill = Min(size_to_fill, (uptr)fl.max_free_fill_size); + REAL(memset)((void *)scribble_start, fl.free_fill_byte, size_to_fill); + } + } + // 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); + // On Windows, uninstrumented DLLs may allocate memory before ASan hooks + // malloc. Don't report an invalid free in this case. + if (SANITIZER_WINDOWS && + !get_allocator().PointerIsMine(ptr)) { + if (!IsSystemHeapAddress(p)) + ReportFreeNotMalloced(p, stack); + return; + } + 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, 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.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() const { return chunk_ && chunk_->chunk_state != CHUNK_AVAILABLE; } bool AsanChunkView::IsAllocated() const { return chunk_ && chunk_->chunk_state == CHUNK_ALLOCATED; } 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() const { return chunk_->alloc_context_id; } u32 AsanChunkView::GetFreeStackId() const { return chunk_->free_context_id; } StackTrace AsanChunkView::GetAllocStack() const { return GetStackTraceFromId(GetAllocStackId()); } 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; + if (flags()->allocator_frees_and_returns_null_on_realloc_zero) { + instance.Deallocate(p, 0, stack, FROM_MALLOC); + return nullptr; + } + // Allocate a size of 1 if we shouldn't free() on Realloc to 0 + size = 1; } 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) { +SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_malloc_hook, + void *ptr, uptr size) { (void)ptr; (void)size; } -SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE -void __sanitizer_free_hook(void *ptr) { + +SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_free_hook, void *ptr) { (void)ptr; } -} // extern "C" #endif Index: projects/clang500-import/contrib/compiler-rt/lib/asan/asan_descriptions.cc =================================================================== --- projects/clang500-import/contrib/compiler-rt/lib/asan/asan_descriptions.cc (revision 317284) +++ projects/clang500-import/contrib/compiler-rt/lib/asan/asan_descriptions.cc (revision 317285) @@ -1,486 +1,489 @@ //===-- 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 (var.line > 0) { + str.append(" (line %d)", var.line); + } 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 Index: projects/clang500-import/contrib/compiler-rt/lib/asan/asan_errors.cc =================================================================== --- projects/clang500-import/contrib/compiler-rt/lib/asan/asan_errors.cc (revision 317284) +++ projects/clang500-import/contrib/compiler-rt/lib/asan/asan_errors.cc (revision 317285) @@ -1,503 +1,516 @@ //===-- 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); } +static void MaybeReportNonExecRegion(uptr pc) { +#if SANITIZER_FREEBSD || SANITIZER_LINUX + MemoryMappingLayout proc_maps(/*cache_enabled*/ true); + uptr start, end, protection; + while (proc_maps.Next(&start, &end, nullptr, nullptr, 0, &protection)) { + if (pc >= start && pc < end && + !(protection & MemoryMappingLayout::kProtectionExecute)) + Report("Hint: PC is at a non-executable region. Maybe a wild jump?\n"); + } +#endif +} + void ErrorDeadlySignal::Print() { Decorator d; Printf("%s", d.Warning()); - const char *description = DescribeSignalOrException(signo); + const char *description = __sanitizer::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"); } + MaybeReportNonExecRegion(pc); 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 Index: projects/clang500-import/contrib/compiler-rt/lib/asan/asan_flags.cc =================================================================== --- projects/clang500-import/contrib/compiler-rt/lib/asan/asan_flags.cc (revision 317284) +++ projects/clang500-import/contrib/compiler-rt/lib/asan/asan_flags.cc (revision 317285) @@ -1,194 +1,203 @@ //===-- 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.detect_leaks = 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 + if (SANITIZER_MAC) { + // Support macOS MallocScribble and MallocPreScribble: + // + if (GetEnv("MallocScribble")) { + f->max_free_fill_size = 0x1000; + } + if (GetEnv("MallocPreScribble")) { + f->malloc_fill_byte = 0xaa; + } + } + // 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 << 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->thread_local_quarantine_size_kb == 0 && f->quarantine_size_mb > 0) { Report("%s: thread_local_quarantine_size_kb can be set to 0 only when " "quarantine_size_mb is set to 0\n", SanitizerToolName); Die(); } 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 +SANITIZER_INTERFACE_WEAK_DEF(const char*, __asan_default_options, void) { + return ""; +} Index: projects/clang500-import/contrib/compiler-rt/lib/asan/asan_flags.inc =================================================================== --- projects/clang500-import/contrib/compiler-rt/lib/asan/asan_flags.inc (revision 317284) +++ projects/clang500-import/contrib/compiler-rt/lib/asan/asan_flags.inc (revision 317285) @@ -1,150 +1,163 @@ //===-- 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, max_free_fill_size, 0, + "ASan allocator flag. max_free_fill_size is the maximal amount of " + "bytes that will be filled with free_fill_byte during free.") ASAN_FLAG(int, malloc_fill_byte, 0xbe, "Value used to fill the newly allocated memory.") +ASAN_FLAG(int, free_fill_byte, 0x55, + "Value used to fill deallocated 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 && !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") +ASAN_FLAG(bool, allocator_frees_and_returns_null_on_realloc_zero, true, + "realloc(p, 0) is equivalent to free(p) by default (Same as the " + "POSIX standard). If set to false, realloc(p, 0) will return a " + "pointer to an allocated space which can not be used.") +ASAN_FLAG(bool, verify_asan_link_order, true, + "Check position of ASan runtime in library list (needs to be disabled" + " when other library has to be preloaded system-wide)") Index: projects/clang500-import/contrib/compiler-rt/lib/asan/asan_globals_win.cc =================================================================== --- projects/clang500-import/contrib/compiler-rt/lib/asan/asan_globals_win.cc (revision 317284) +++ projects/clang500-import/contrib/compiler-rt/lib/asan/asan_globals_win.cc (revision 317285) @@ -1,62 +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 +#ifdef SANITIZER_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 Index: projects/clang500-import/contrib/compiler-rt/lib/asan/asan_interceptors.cc =================================================================== --- projects/clang500-import/contrib/compiler-rt/lib/asan/asan_interceptors.cc (revision 317284) +++ projects/clang500-import/contrib/compiler-rt/lib/asan/asan_interceptors.cc (revision 317285) @@ -1,785 +1,787 @@ //===-- 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(); \ - } + do { \ + if (flags()->strict_init_order) \ + StopInitOrderChecking(); \ + CheckNoDeepBind(filename, flag); \ + } while (false) #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; \ } #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 void *__asan_memcpy(void *to, const void *from, uptr size) { ASAN_MEMCPY_IMPL(nullptr, to, from, size); } void *__asan_memset(void *block, int c, uptr size) { ASAN_MEMSET_IMPL(nullptr, block, c, size); } void *__asan_memmove(void *to, const void *from, uptr size) { ASAN_MEMMOVE_IMPL(nullptr, to, from, 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); was_called_once = true; InitializeCommonInterceptors(); // 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/clang500-import/contrib/compiler-rt/lib/asan/asan_interface.inc =================================================================== --- projects/clang500-import/contrib/compiler-rt/lib/asan/asan_interface.inc (nonexistent) +++ projects/clang500-import/contrib/compiler-rt/lib/asan/asan_interface.inc (revision 317285) @@ -0,0 +1,167 @@ +//===-- asan_interface.inc ------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// Asan interface list. +//===----------------------------------------------------------------------===// +INTERFACE_FUNCTION(__asan_addr_is_in_fake_stack) +INTERFACE_FUNCTION(__asan_address_is_poisoned) +INTERFACE_FUNCTION(__asan_after_dynamic_init) +INTERFACE_FUNCTION(__asan_alloca_poison) +INTERFACE_FUNCTION(__asan_allocas_unpoison) +INTERFACE_FUNCTION(__asan_before_dynamic_init) +INTERFACE_FUNCTION(__asan_describe_address) +INTERFACE_FUNCTION(__asan_exp_load1) +INTERFACE_FUNCTION(__asan_exp_load2) +INTERFACE_FUNCTION(__asan_exp_load4) +INTERFACE_FUNCTION(__asan_exp_load8) +INTERFACE_FUNCTION(__asan_exp_load16) +INTERFACE_FUNCTION(__asan_exp_loadN) +INTERFACE_FUNCTION(__asan_exp_store1) +INTERFACE_FUNCTION(__asan_exp_store2) +INTERFACE_FUNCTION(__asan_exp_store4) +INTERFACE_FUNCTION(__asan_exp_store8) +INTERFACE_FUNCTION(__asan_exp_store16) +INTERFACE_FUNCTION(__asan_exp_storeN) +INTERFACE_FUNCTION(__asan_get_alloc_stack) +INTERFACE_FUNCTION(__asan_get_current_fake_stack) +INTERFACE_FUNCTION(__asan_get_free_stack) +INTERFACE_FUNCTION(__asan_get_report_access_size) +INTERFACE_FUNCTION(__asan_get_report_access_type) +INTERFACE_FUNCTION(__asan_get_report_address) +INTERFACE_FUNCTION(__asan_get_report_bp) +INTERFACE_FUNCTION(__asan_get_report_description) +INTERFACE_FUNCTION(__asan_get_report_pc) +INTERFACE_FUNCTION(__asan_get_report_sp) +INTERFACE_FUNCTION(__asan_get_shadow_mapping) +INTERFACE_FUNCTION(__asan_handle_no_return) +INTERFACE_FUNCTION(__asan_init) +INTERFACE_FUNCTION(__asan_load_cxx_array_cookie) +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_load1_noabort) +INTERFACE_FUNCTION(__asan_load2_noabort) +INTERFACE_FUNCTION(__asan_load4_noabort) +INTERFACE_FUNCTION(__asan_load8_noabort) +INTERFACE_FUNCTION(__asan_load16_noabort) +INTERFACE_FUNCTION(__asan_loadN_noabort) +INTERFACE_FUNCTION(__asan_locate_address) +INTERFACE_FUNCTION(__asan_memcpy) +INTERFACE_FUNCTION(__asan_memmove) +INTERFACE_FUNCTION(__asan_memset) +INTERFACE_FUNCTION(__asan_poison_cxx_array_cookie) +INTERFACE_FUNCTION(__asan_poison_intra_object_redzone) +INTERFACE_FUNCTION(__asan_poison_memory_region) +INTERFACE_FUNCTION(__asan_poison_stack_memory) +INTERFACE_FUNCTION(__asan_print_accumulated_stats) +INTERFACE_FUNCTION(__asan_region_is_poisoned) +INTERFACE_FUNCTION(__asan_register_globals) +INTERFACE_FUNCTION(__asan_register_image_globals) +INTERFACE_FUNCTION(__asan_report_error) +INTERFACE_FUNCTION(__asan_report_exp_load1) +INTERFACE_FUNCTION(__asan_report_exp_load2) +INTERFACE_FUNCTION(__asan_report_exp_load4) +INTERFACE_FUNCTION(__asan_report_exp_load8) +INTERFACE_FUNCTION(__asan_report_exp_load16) +INTERFACE_FUNCTION(__asan_report_exp_load_n) +INTERFACE_FUNCTION(__asan_report_exp_store1) +INTERFACE_FUNCTION(__asan_report_exp_store2) +INTERFACE_FUNCTION(__asan_report_exp_store4) +INTERFACE_FUNCTION(__asan_report_exp_store8) +INTERFACE_FUNCTION(__asan_report_exp_store16) +INTERFACE_FUNCTION(__asan_report_exp_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_report_load1_noabort) +INTERFACE_FUNCTION(__asan_report_load2_noabort) +INTERFACE_FUNCTION(__asan_report_load4_noabort) +INTERFACE_FUNCTION(__asan_report_load8_noabort) +INTERFACE_FUNCTION(__asan_report_load16_noabort) +INTERFACE_FUNCTION(__asan_report_load_n_noabort) +INTERFACE_FUNCTION(__asan_report_present) +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_store1_noabort) +INTERFACE_FUNCTION(__asan_report_store2_noabort) +INTERFACE_FUNCTION(__asan_report_store4_noabort) +INTERFACE_FUNCTION(__asan_report_store8_noabort) +INTERFACE_FUNCTION(__asan_report_store16_noabort) +INTERFACE_FUNCTION(__asan_report_store_n_noabort) +INTERFACE_FUNCTION(__asan_set_death_callback) +INTERFACE_FUNCTION(__asan_set_error_report_callback) +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_stack_free_0) +INTERFACE_FUNCTION(__asan_stack_free_1) +INTERFACE_FUNCTION(__asan_stack_free_2) +INTERFACE_FUNCTION(__asan_stack_free_3) +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) +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_store1) +INTERFACE_FUNCTION(__asan_store2) +INTERFACE_FUNCTION(__asan_store4) +INTERFACE_FUNCTION(__asan_store8) +INTERFACE_FUNCTION(__asan_store16) +INTERFACE_FUNCTION(__asan_storeN) +INTERFACE_FUNCTION(__asan_store1_noabort) +INTERFACE_FUNCTION(__asan_store2_noabort) +INTERFACE_FUNCTION(__asan_store4_noabort) +INTERFACE_FUNCTION(__asan_store8_noabort) +INTERFACE_FUNCTION(__asan_store16_noabort) +INTERFACE_FUNCTION(__asan_storeN_noabort) +INTERFACE_FUNCTION(__asan_unpoison_intra_object_redzone) +INTERFACE_FUNCTION(__asan_unpoison_memory_region) +INTERFACE_FUNCTION(__asan_unpoison_stack_memory) +INTERFACE_FUNCTION(__asan_unregister_globals) +INTERFACE_FUNCTION(__asan_unregister_image_globals) +INTERFACE_FUNCTION(__asan_version_mismatch_check_v8) +INTERFACE_FUNCTION(__sanitizer_finish_switch_fiber) +INTERFACE_FUNCTION(__sanitizer_print_stack_trace) +INTERFACE_FUNCTION(__sanitizer_ptr_cmp) +INTERFACE_FUNCTION(__sanitizer_ptr_sub) +INTERFACE_FUNCTION(__sanitizer_start_switch_fiber) +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_WEAK_FUNCTION(__asan_default_options) +INTERFACE_WEAK_FUNCTION(__asan_default_suppressions) +INTERFACE_WEAK_FUNCTION(__asan_on_error) Property changes on: projects/clang500-import/contrib/compiler-rt/lib/asan/asan_interface.inc ___________________________________________________________________ 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/clang500-import/contrib/compiler-rt/lib/asan/asan_interface_internal.h =================================================================== --- projects/clang500-import/contrib/compiler-rt/lib/asan/asan_interface_internal.h (revision 317284) +++ projects/clang500-import/contrib/compiler-rt/lib/asan/asan_interface_internal.h (revision 317285) @@ -1,247 +1,250 @@ //===-- 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(); + void __asan_on_error(); SANITIZER_INTERFACE_ATTRIBUTE void __asan_print_accumulated_stats(); SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE - /* OPTIONAL */ const char* __asan_default_options(); + 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); + + SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE + const char* __asan_default_suppressions(); } // extern "C" #endif // ASAN_INTERFACE_INTERNAL_H Index: projects/clang500-import/contrib/compiler-rt/lib/asan/asan_internal.h =================================================================== --- projects/clang500-import/contrib/compiler-rt/lib/asan/asan_internal.h (revision 317284) +++ projects/clang500-import/contrib/compiler-rt/lib/asan/asan_internal.h (revision 317285) @@ -1,148 +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_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); +// Returns whether an address is a valid allocated system heap block. +// 'addr' must point to the beginning of the block. +bool IsSystemHeapAddress(uptr addr); // 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); // 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 kAsanHeapFreeMagic = 0xfd; const int kAsanStackLeftRedzoneMagic = 0xf1; const int kAsanStackMidRedzoneMagic = 0xf2; const int kAsanStackRightRedzoneMagic = 0xf3; 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/clang500-import/contrib/compiler-rt/lib/asan/asan_linux.cc =================================================================== --- projects/clang500-import/contrib/compiler-rt/lib/asan/asan_linux.cc (revision 317284) +++ projects/clang500-import/contrib/compiler-rt/lib/asan/asan_linux.cc (revision 317285) @@ -1,176 +1,177 @@ //===-- asan_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 details. //===----------------------------------------------------------------------===// #include "sanitizer_common/sanitizer_platform.h" #if SANITIZER_FREEBSD || SANITIZER_LINUX #include "asan_interceptors.h" #include "asan_internal.h" #include "asan_thread.h" #include "sanitizer_common/sanitizer_flags.h" #include "sanitizer_common/sanitizer_freebsd.h" #include "sanitizer_common/sanitizer_libc.h" #include "sanitizer_common/sanitizer_procmaps.h" #include #include #include #include #include #include #include #include #include #include #include #if SANITIZER_FREEBSD #include #endif #if SANITIZER_ANDROID || SANITIZER_FREEBSD #include extern "C" void* _DYNAMIC; #else #include #include #endif // x86-64 FreeBSD 9.2 and older define 'ucontext_t' incorrectly in // 32-bit mode. #if SANITIZER_FREEBSD && (SANITIZER_WORDSIZE == 32) && \ __FreeBSD_version <= 902001 // v9.2 #define ucontext_t xucontext_t #endif typedef enum { ASAN_RT_VERSION_UNDEFINED = 0, ASAN_RT_VERSION_DYNAMIC, ASAN_RT_VERSION_STATIC, } asan_rt_version_t; // FIXME: perhaps also store abi version here? extern "C" { SANITIZER_INTERFACE_ATTRIBUTE asan_rt_version_t __asan_rt_version; } namespace __asan { void InitializePlatformInterceptors() {} void InitializePlatformExceptionHandlers() {} +bool IsSystemHeapAddress (uptr addr) { return false; } void *AsanDoesNotSupportStaticLinkage() { // This will fail to link with -static. return &_DYNAMIC; // defined in link.h } void AsanApplyToGlobals(globals_op_fptr op, const void *needle) { UNIMPLEMENTED(); } #if SANITIZER_ANDROID // FIXME: should we do anything for Android? void AsanCheckDynamicRTPrereqs() {} void AsanCheckIncompatibleRT() {} #else static int FindFirstDSOCallback(struct dl_phdr_info *info, size_t size, void *data) { // Continue until the first dynamic library is found if (!info->dlpi_name || info->dlpi_name[0] == 0) return 0; // Ignore vDSO if (internal_strncmp(info->dlpi_name, "linux-", sizeof("linux-") - 1) == 0) return 0; *(const char **)data = info->dlpi_name; return 1; } static bool IsDynamicRTName(const char *libname) { return internal_strstr(libname, "libclang_rt.asan") || internal_strstr(libname, "libasan.so"); } static void ReportIncompatibleRT() { Report("Your application is linked against incompatible ASan runtimes.\n"); Die(); } void AsanCheckDynamicRTPrereqs() { - if (!ASAN_DYNAMIC) + if (!ASAN_DYNAMIC || !flags()->verify_asan_link_order) return; // Ensure that dynamic RT is the first DSO in the list const char *first_dso_name = nullptr; dl_iterate_phdr(FindFirstDSOCallback, &first_dso_name); if (first_dso_name && !IsDynamicRTName(first_dso_name)) { Report("ASan runtime does not come first in initial library list; " "you should either link runtime to your application or " "manually preload it with LD_PRELOAD.\n"); Die(); } } void AsanCheckIncompatibleRT() { if (ASAN_DYNAMIC) { if (__asan_rt_version == ASAN_RT_VERSION_UNDEFINED) { __asan_rt_version = ASAN_RT_VERSION_DYNAMIC; } else if (__asan_rt_version != ASAN_RT_VERSION_DYNAMIC) { ReportIncompatibleRT(); } } else { if (__asan_rt_version == ASAN_RT_VERSION_UNDEFINED) { // Ensure that dynamic runtime is not present. We should detect it // as early as possible, otherwise ASan interceptors could bind to // the functions in dynamic ASan runtime instead of the functions in // system libraries, causing crashes later in ASan initialization. MemoryMappingLayout proc_maps(/*cache_enabled*/true); char filename[128]; while (proc_maps.Next(nullptr, nullptr, nullptr, filename, sizeof(filename), nullptr)) { if (IsDynamicRTName(filename)) { Report("Your application is linked against " "incompatible ASan runtimes.\n"); Die(); } } __asan_rt_version = ASAN_RT_VERSION_STATIC; } else if (__asan_rt_version != ASAN_RT_VERSION_STATIC) { ReportIncompatibleRT(); } } } #endif // SANITIZER_ANDROID #if !SANITIZER_ANDROID void ReadContextStack(void *context, uptr *stack, uptr *ssize) { ucontext_t *ucp = (ucontext_t*)context; *stack = (uptr)ucp->uc_stack.ss_sp; *ssize = ucp->uc_stack.ss_size; } #else void ReadContextStack(void *context, uptr *stack, uptr *ssize) { UNIMPLEMENTED(); } #endif void *AsanDlSymNext(const char *sym) { return dlsym(RTLD_NEXT, sym); } } // namespace __asan #endif // SANITIZER_FREEBSD || SANITIZER_LINUX Index: projects/clang500-import/contrib/compiler-rt/lib/asan/asan_mac.cc =================================================================== --- projects/clang500-import/contrib/compiler-rt/lib/asan/asan_mac.cc (revision 317284) +++ projects/clang500-import/contrib/compiler-rt/lib/asan/asan_mac.cc (revision 317285) @@ -1,287 +1,289 @@ //===-- 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 IsSystemHeapAddress (uptr addr) { return false; } // 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); + asanThreadRegistry().StartThread(t->tid(), GetTid(), + /* workerthread */ true, 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/clang500-import/contrib/compiler-rt/lib/asan/asan_malloc_win.cc =================================================================== --- projects/clang500-import/contrib/compiler-rt/lib/asan/asan_malloc_win.cc (revision 317284) +++ projects/clang500-import/contrib/compiler-rt/lib/asan/asan_malloc_win.cc (revision 317285) @@ -1,252 +1,252 @@ //===-- 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 *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!"); + UNREACHABLE("_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/clang500-import/contrib/compiler-rt/lib/asan/asan_mapping.h =================================================================== --- projects/clang500-import/contrib/compiler-rt/lib/asan/asan_mapping.h (revision 317284) +++ projects/clang500-import/contrib/compiler-rt/lib/asan/asan_mapping.h (revision 317285) @@ -1,337 +1,336 @@ //===-- 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 #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 __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 __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) || (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 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/clang500-import/contrib/compiler-rt/lib/asan/asan_memory_profile.cc =================================================================== --- projects/clang500-import/contrib/compiler-rt/lib/asan/asan_memory_profile.cc (revision 317284) +++ projects/clang500-import/contrib/compiler-rt/lib/asan/asan_memory_profile.cc (revision 317285) @@ -1,118 +1,127 @@ //===-- 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 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_++; } } - void Print(uptr top_percent) { + void Print(uptr top_percent, uptr max_number_of_contexts) { InternalSort(&allocations_, allocations_.size(), [](const AllocationSite &a, const AllocationSite &b) { return a.total_size > b.total_size; }); CHECK(total_allocated_user_size_); uptr total_shown = 0; 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", + "showing top %zd%% (at most %zd unique contexts)\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++) { + total_quarantined_count_ + total_other_count_, top_percent, + max_number_of_contexts); + for (uptr i = 0; i < Min(allocations_.size(), max_number_of_contexts); + i++) { auto &a = allocations_[i]; Printf("%zd byte(s) (%zd%%) in %zd allocation(s)\n", a.total_size, 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_user_size_ > top_percent) break; } } private: 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) { 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)); + uptr *Arg = reinterpret_cast(argument); + hp.Print(Arg[0], Arg[1]); } } // namespace __asan +#endif // CAN_SANITIZE_LEAKS + extern "C" { SANITIZER_INTERFACE_ATTRIBUTE -void __sanitizer_print_memory_profile(uptr top_percent) { - __sanitizer::StopTheWorld(__asan::MemoryProfileCB, (void*)top_percent); +void __sanitizer_print_memory_profile(uptr top_percent, + uptr max_number_of_contexts) { +#if CAN_SANITIZE_LEAKS + uptr Arg[2]; + Arg[0] = top_percent; + Arg[1] = max_number_of_contexts; + __sanitizer::StopTheWorld(__asan::MemoryProfileCB, Arg); +#endif // CAN_SANITIZE_LEAKS } } // extern "C" - -#endif // CAN_SANITIZE_LEAKS Index: projects/clang500-import/contrib/compiler-rt/lib/asan/asan_posix.cc =================================================================== --- projects/clang500-import/contrib/compiler-rt/lib/asan/asan_posix.cc (revision 317284) +++ projects/clang500-import/contrib/compiler-rt/lib/asan/asan_posix.cc (revision 317285) @@ -1,135 +1,122 @@ //===-- 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 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/clang500-import/contrib/compiler-rt/lib/asan/asan_report.cc =================================================================== --- projects/clang500-import/contrib/compiler-rt/lib/asan/asan_report.cc (revision 317284) +++ projects/clang500-import/contrib/compiler-rt/lib/asan/asan_report.cc (revision 317285) @@ -1,496 +1,501 @@ //===-- 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]; 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); } // ---------------------- Helper functions ----------------------- {{{1 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 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); } } // ---------------------- Address Descriptions ------------------- {{{1 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". + // where alloc_i looks like "offset size len ObjectName" + // or "offset size len ObjectName:line". 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}; + char *colon_pos = internal_strchr(p, ':'); + uptr line = 0; + uptr name_len = len; + if (colon_pos != nullptr && colon_pos < p + len) { + name_len = colon_pos - p; + line = (uptr)internal_simple_strtoll(colon_pos + 1, nullptr, 10); + } + StackVarDescr var = {beg, size, p, name_len, line}; vars->push_back(var); p += len; } return true; } // -------------------- Different kinds of reports ----------------- {{{1 // Use ScopedInErrorReport to run common actions just before and // immediately after printing error report. class ScopedInErrorReport { public: explicit ScopedInErrorReport(bool fatal = false) { halt_on_error_ = fatal || flags()->halt_on_error; if (lock_.TryLock()) { 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(); } ~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(); if (common_flags()->print_module_map == 2) PrintModuleMap(); // 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() { // 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(/*fatal*/ true); ErrorStackOverflow error(GetCurrentTidOrInvalid(), sig); in_report.ReportError(error); } 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; ErrorDoubleFree error(GetCurrentTidOrInvalid(), free_stack, addr); in_report.ReportError(error); } void ReportNewDeleteSizeMismatch(uptr addr, uptr delete_size, BufferedStackTrace *free_stack) { ScopedInErrorReport in_report; ErrorNewDeleteSizeMismatch error(GetCurrentTidOrInvalid(), free_stack, addr, delete_size); in_report.ReportError(error); } void ReportFreeNotMalloced(uptr addr, BufferedStackTrace *free_stack) { ScopedInErrorReport in_report; ErrorFreeNotMalloced error(GetCurrentTidOrInvalid(), free_stack, addr); in_report.ReportError(error); } void ReportAllocTypeMismatch(uptr addr, BufferedStackTrace *free_stack, AllocType alloc_type, AllocType dealloc_type) { ScopedInErrorReport in_report; ErrorAllocTypeMismatch error(GetCurrentTidOrInvalid(), free_stack, addr, alloc_type, dealloc_type); in_report.ReportError(error); } void ReportMallocUsableSizeNotOwned(uptr addr, BufferedStackTrace *stack) { ScopedInErrorReport in_report; ErrorMallocUsableSizeNotOwned error(GetCurrentTidOrInvalid(), stack, addr); in_report.ReportError(error); } void ReportSanitizerGetAllocatedSizeNotOwned(uptr addr, BufferedStackTrace *stack) { ScopedInErrorReport in_report; 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; 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; 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; 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; 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) { ScopedInErrorReport in_report; 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(); 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(); } 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; // 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; 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(); PrintAddressDescription(addr, 1, ""); asanThreadRegistry().Unlock(); } int __asan_report_present() { return ScopedInErrorReport::CurrentError().kind != kErrorKindInvalid; } uptr __asan_get_report_pc() { if (ScopedInErrorReport::CurrentError().kind == kErrorKindGeneric) return ScopedInErrorReport::CurrentError().Generic.pc; return 0; } uptr __asan_get_report_bp() { if (ScopedInErrorReport::CurrentError().kind == kErrorKindGeneric) return ScopedInErrorReport::CurrentError().Generic.bp; return 0; } uptr __asan_get_report_sp() { if (ScopedInErrorReport::CurrentError().kind == kErrorKindGeneric) return ScopedInErrorReport::CurrentError().Generic.sp; return 0; } uptr __asan_get_report_address() { 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() { if (ScopedInErrorReport::CurrentError().kind == kErrorKindGeneric) return ScopedInErrorReport::CurrentError().Generic.is_write; return 0; } uptr __asan_get_report_access_size() { if (ScopedInErrorReport::CurrentError().kind == kErrorKindGeneric) return ScopedInErrorReport::CurrentError().Generic.access_size; return 0; } const char *__asan_get_report_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 +SANITIZER_INTERFACE_WEAK_DEF(void, __asan_on_error, void) {} Index: projects/clang500-import/contrib/compiler-rt/lib/asan/asan_report.h =================================================================== --- projects/clang500-import/contrib/compiler-rt/lib/asan/asan_report.h (revision 317284) +++ projects/clang500-import/contrib/compiler-rt/lib/asan/asan_report.h (revision 317285) @@ -1,81 +1,82 @@ //===-- 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; + uptr line; }; // 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); 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). bool ParseFrameDescription(const char *frame_descr, InternalMmapVector *vars); // 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(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/clang500-import/contrib/compiler-rt/lib/asan/asan_suppressions.cc =================================================================== --- projects/clang500-import/contrib/compiler-rt/lib/asan/asan_suppressions.cc (revision 317284) +++ projects/clang500-import/contrib/compiler-rt/lib/asan/asan_suppressions.cc (revision 317285) @@ -1,111 +1,105 @@ //===-- asan_suppressions.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. // // Issue suppression and suppression-related functions. //===----------------------------------------------------------------------===// #include "asan_suppressions.h" #include "asan_stack.h" #include "sanitizer_common/sanitizer_placement_new.h" #include "sanitizer_common/sanitizer_suppressions.h" #include "sanitizer_common/sanitizer_symbolizer.h" namespace __asan { ALIGNED(64) static char suppression_placeholder[sizeof(SuppressionContext)]; static SuppressionContext *suppression_ctx = nullptr; static const char kInterceptorName[] = "interceptor_name"; static const char kInterceptorViaFunction[] = "interceptor_via_fun"; static const char kInterceptorViaLibrary[] = "interceptor_via_lib"; static const char kODRViolation[] = "odr_violation"; static const char *kSuppressionTypes[] = { kInterceptorName, kInterceptorViaFunction, kInterceptorViaLibrary, kODRViolation}; -extern "C" { -#if SANITIZER_SUPPORTS_WEAK_HOOKS -SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE -const char *__asan_default_suppressions(); -#else -// No week hooks, provide empty implementation. -const char *__asan_default_suppressions() { return ""; } -#endif // SANITIZER_SUPPORTS_WEAK_HOOKS -} // extern "C" +SANITIZER_INTERFACE_WEAK_DEF(const char *, __asan_default_suppressions, void) { + return ""; +} void InitializeSuppressions() { CHECK_EQ(nullptr, suppression_ctx); suppression_ctx = new (suppression_placeholder) // NOLINT SuppressionContext(kSuppressionTypes, ARRAY_SIZE(kSuppressionTypes)); suppression_ctx->ParseFromFile(flags()->suppressions); if (&__asan_default_suppressions) suppression_ctx->Parse(__asan_default_suppressions()); } bool IsInterceptorSuppressed(const char *interceptor_name) { CHECK(suppression_ctx); Suppression *s; // Match "interceptor_name" suppressions. return suppression_ctx->Match(interceptor_name, kInterceptorName, &s); } bool HaveStackTraceBasedSuppressions() { CHECK(suppression_ctx); return suppression_ctx->HasSuppressionType(kInterceptorViaFunction) || suppression_ctx->HasSuppressionType(kInterceptorViaLibrary); } bool IsODRViolationSuppressed(const char *global_var_name) { CHECK(suppression_ctx); Suppression *s; // Match "odr_violation" suppressions. return suppression_ctx->Match(global_var_name, kODRViolation, &s); } bool IsStackTraceSuppressed(const StackTrace *stack) { if (!HaveStackTraceBasedSuppressions()) return false; CHECK(suppression_ctx); Symbolizer *symbolizer = Symbolizer::GetOrInit(); Suppression *s; for (uptr i = 0; i < stack->size && stack->trace[i]; i++) { uptr addr = stack->trace[i]; if (suppression_ctx->HasSuppressionType(kInterceptorViaLibrary)) { // Match "interceptor_via_lib" suppressions. if (const char *module_name = symbolizer->GetModuleNameForPc(addr)) if (suppression_ctx->Match(module_name, kInterceptorViaLibrary, &s)) return true; } if (suppression_ctx->HasSuppressionType(kInterceptorViaFunction)) { SymbolizedStack *frames = symbolizer->SymbolizePC(addr); CHECK(frames); for (SymbolizedStack *cur = frames; cur; cur = cur->next) { const char *function_name = cur->info.function; if (!function_name) { continue; } // Match "interceptor_via_fun" suppressions. if (suppression_ctx->Match(function_name, kInterceptorViaFunction, &s)) { frames->ClearAll(); return true; } } frames->ClearAll(); } } return false; } } // namespace __asan Index: projects/clang500-import/contrib/compiler-rt/lib/asan/asan_thread.cc =================================================================== --- projects/clang500-import/contrib/compiler-rt/lib/asan/asan_thread.cc (revision 317284) +++ projects/clang500-import/contrib/compiler-rt/lib/asan/asan_thread.cc (revision 317285) @@ -1,468 +1,472 @@ //===-- 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, 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) { + tid_t os_id, atomic_uintptr_t *signal_thread_is_registered) { Init(); - asanThreadRegistry().StartThread(tid(), os_id, nullptr); + asanThreadRegistry().StartThread(tid(), os_id, /*workerthread*/ false, + 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. + uptr mem_ptr = RoundDownTo(aligned_addr, SHADOW_GRANULARITY); u8 *shadow_ptr = (u8*)MemToShadow(aligned_addr); u8 *shadow_bottom = (u8*)MemToShadow(bottom); while (shadow_ptr >= shadow_bottom && *shadow_ptr != kAsanStackLeftRedzoneMagic) { shadow_ptr--; + mem_ptr -= SHADOW_GRANULARITY; } while (shadow_ptr >= shadow_bottom && *shadow_ptr == kAsanStackLeftRedzoneMagic) { shadow_ptr--; + mem_ptr -= SHADOW_GRANULARITY; } if (shadow_ptr < shadow_bottom) { return false; } - uptr* ptr = (uptr*)SHADOW_TO_MEM((uptr)(shadow_ptr + 1)); + uptr* ptr = (uptr*)(mem_ptr + SHADOW_GRANULARITY); 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 (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::AsanThread *GetAsanThreadByOsIDLocked(tid_t 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, +bool GetThreadRangesLocked(tid_t 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 ForEachExtraStackRange(tid_t 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, 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, (uptr*)bottom_old, (uptr*)size_old); } } Index: projects/clang500-import/contrib/compiler-rt/lib/asan/asan_thread.h =================================================================== --- projects/clang500-import/contrib/compiler-rt/lib/asan/asan_thread.h (revision 317284) +++ projects/clang500-import/contrib/compiler-rt/lib/asan/asan_thread.h (revision 317285) @@ -1,206 +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, + thread_return_t ThreadStart(tid_t 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, 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/clang500-import/contrib/compiler-rt/lib/asan/asan_win.cc =================================================================== --- projects/clang500-import/contrib/compiler-rt/lib/asan/asan_win.cc (revision 317284) +++ projects/clang500-import/contrib/compiler-rt/lib/asan/asan_win.cc (revision 317285) @@ -1,376 +1,341 @@ //===-- 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" +#include "sanitizer_common/sanitizer_win.h" +#include "sanitizer_common/sanitizer_win_defs.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; } 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 interceptors ---------------- {{{ +static LPTOP_LEVEL_EXCEPTION_FILTER default_seh_handler; +static LPTOP_LEVEL_EXCEPTION_FILTER user_seh_handler; + +extern "C" SANITIZER_INTERFACE_ATTRIBUTE +long __asan_unhandled_exception_filter(EXCEPTION_POINTERS *info) { + EXCEPTION_RECORD *exception_record = info->ExceptionRecord; + CONTEXT *context = info->ContextRecord; + + // FIXME: Handle EXCEPTION_STACK_OVERFLOW here. + + SignalContext sig = SignalContext::Create(exception_record, context); + ReportDeadlySignal(exception_record->ExceptionCode, sig); + UNREACHABLE("returned from reporting deadly signal"); +} + +// Wrapper SEH Handler. If the exception should be handled by asan, we call +// __asan_unhandled_exception_filter, otherwise, we execute the user provided +// exception handler or the default. +static long WINAPI SEHHandler(EXCEPTION_POINTERS *info) { + DWORD exception_code = info->ExceptionRecord->ExceptionCode; + if (__sanitizer::IsHandledDeadlyException(exception_code)) + return __asan_unhandled_exception_filter(info); + if (user_seh_handler) + return user_seh_handler(info); + // Bubble out to the default exception filter. + if (default_seh_handler) + return default_seh_handler(info); + return EXCEPTION_CONTINUE_SEARCH; +} + +INTERCEPTOR_WINAPI(LPTOP_LEVEL_EXCEPTION_FILTER, SetUnhandledExceptionFilter, + LPTOP_LEVEL_EXCEPTION_FILTER ExceptionFilter) { + CHECK(REAL(SetUnhandledExceptionFilter)); + if (ExceptionFilter == &SEHHandler || common_flags()->allow_user_segv_handler) + return REAL(SetUnhandledExceptionFilter)(ExceptionFilter); + // We record the user provided exception handler to be called for all the + // exceptions unhandled by asan. + Swap(ExceptionFilter, user_seh_handler); + return ExceptionFilter; +} + 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 __asan { void InitializePlatformInterceptors() { ASAN_INTERCEPT_FUNC(CreateThread); + ASAN_INTERCEPT_FUNC(SetUnhandledExceptionFilter); #ifdef _WIN64 ASAN_INTERCEPT_FUNC(__C_specific_handler); #else ASAN_INTERCEPT_FUNC(_except_handler3); ASAN_INTERCEPT_FUNC(_except_handler4); #endif // 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) { 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; - -// 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; +bool IsSystemHeapAddress(uptr addr) { + return ::HeapValidate(GetProcessHeap(), 0, (void*)addr) != FALSE; } -// 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; // 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() +WIN_FORCE_LINK(__asan_dso_reg_hook) // }}} } // namespace __asan #endif // SANITIZER_WINDOWS Index: projects/clang500-import/contrib/compiler-rt/lib/asan/asan_win_dll_thunk.cc =================================================================== --- projects/clang500-import/contrib/compiler-rt/lib/asan/asan_win_dll_thunk.cc (revision 317284) +++ projects/clang500-import/contrib/compiler-rt/lib/asan/asan_win_dll_thunk.cc (revision 317285) @@ -1,483 +1,151 @@ //===-- 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 building asan_dll_thunk.lib -// Using #ifdef rather than relying on Makefiles etc. -// simplifies the build procedure. -#ifdef ASAN_DLL_THUNK +#ifdef SANITIZER_DLL_THUNK #include "asan_init_version.h" -#include "asan_globals_win.h" #include "interception/interception.h" +#include "sanitizer_common/sanitizer_win_defs.h" +#include "sanitizer_common/sanitizer_win_dll_thunk.h" #include "sanitizer_common/sanitizer_platform_interceptors.h" -#ifdef _M_IX86 -#define WINAPI __stdcall -#else -#define WINAPI -#endif +// ASan own interface functions. +#define INTERFACE_FUNCTION(Name) INTERCEPT_SANITIZER_FUNCTION(Name) +#define INTERFACE_WEAK_FUNCTION(Name) INTERCEPT_SANITIZER_WEAK_FUNCTION(Name) +#include "asan_interface.inc" -// ---------- Function interception helper functions and macros ----------- {{{1 -extern "C" { -void *WINAPI GetModuleHandleA(const char *module_name); -void *WINAPI GetProcAddress(void *module, const char *proc_name); -void abort(); -} +// Memory allocation functions. +INTERCEPT_WRAP_V_W(free) +INTERCEPT_WRAP_V_W(_free_base) +INTERCEPT_WRAP_V_WW(_free_dbg) -using namespace __sanitizer; +INTERCEPT_WRAP_W_W(malloc) +INTERCEPT_WRAP_W_W(_malloc_base) +INTERCEPT_WRAP_W_WWWW(_malloc_dbg) -static uptr getRealProcAddressOrDie(const char *name) { - uptr ret = - __interception::InternalGetProcAddress((void *)GetModuleHandleA(0), name); - if (!ret) - abort(); - return ret; -} +INTERCEPT_WRAP_W_WW(calloc) +INTERCEPT_WRAP_W_WW(_calloc_base) +INTERCEPT_WRAP_W_WWWWW(_calloc_dbg) +INTERCEPT_WRAP_W_WWW(_calloc_impl) -// 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(). +INTERCEPT_WRAP_W_WW(realloc) +INTERCEPT_WRAP_W_WW(_realloc_base) +INTERCEPT_WRAP_W_WWW(_realloc_dbg) +INTERCEPT_WRAP_W_WWW(_recalloc) +INTERCEPT_WRAP_W_WWW(_recalloc_base) -// 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(); } -}; +INTERCEPT_WRAP_W_W(_msize) +INTERCEPT_WRAP_W_W(_expand) +INTERCEPT_WRAP_W_W(_expand_dbg) -// 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 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 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 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 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 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 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 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 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 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 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 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_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_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(strtok); 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 +#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 -// 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? +// Window specific functions not included in asan_interface.inc. +INTERCEPT_WRAP_W_V(__asan_should_detect_stack_use_after_return) +INTERCEPT_WRAP_W_V(__asan_get_shadow_memory_dynamic_address) +INTERCEPT_WRAP_W_W(__asan_unhandled_exception_filter) -// In DLLs, the callbacks are expected to return 0, -// otherwise CRT initialization fails. -static int call_asan_init() { - __asan_init(); +using namespace __sanitizer; + +extern "C" { +int __asan_option_detect_stack_use_after_return; +uptr __asan_shadow_memory_dynamic_address; +} // extern "C" + +static int asan_dll_thunk_init() { + typedef void (*fntype)(); + static fntype fn = 0; + // asan_dll_thunk_init is expected to be called by only one thread. + if (fn) return 0; + + // Ensure all interception was executed. + __dll_thunk_init(); + + fn = (fntype) dllThunkGetRealAddrOrDie("__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(); + +#ifndef _WIN64 + INTERCEPT_FUNCTION(_except_handler4); +#endif + // In DLLs, the callbacks are expected to return 0, + // otherwise CRT initialization fails. return 0; } + #pragma section(".CRT$XIB", long, read) // NOLINT -__declspec(allocate(".CRT$XIB")) int (*__asan_preinit)() = call_asan_init; +__declspec(allocate(".CRT$XIB")) int (*__asan_preinit)() = asan_dll_thunk_init; static void WINAPI asan_thread_init(void *mod, unsigned long reason, - void *reserved) { - if (reason == /*DLL_PROCESS_ATTACH=*/1) __asan_init(); + void *reserved) { + if (reason == /*DLL_PROCESS_ATTACH=*/1) asan_dll_thunk_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() +WIN_FORCE_LINK(__asan_dso_reg_hook) -#endif // ASAN_DLL_THUNK +#endif // SANITIZER_DLL_THUNK Index: projects/clang500-import/contrib/compiler-rt/lib/asan/asan_win_dynamic_runtime_thunk.cc =================================================================== --- projects/clang500-import/contrib/compiler-rt/lib/asan/asan_win_dynamic_runtime_thunk.cc (revision 317284) +++ projects/clang500-import/contrib/compiler-rt/lib/asan/asan_win_dynamic_runtime_thunk.cc (revision 317285) @@ -1,127 +1,131 @@ //===-- 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: +// - creating weak aliases to default implementation imported from asan dll. // - forwarding the detect_stack_use_after_return runtime option // - working around deficiencies of the MD runtime // - installing a custom SEH handler // //===----------------------------------------------------------------------===// -// 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" +#ifdef SANITIZER_DYNAMIC_RUNTIME_THUNK +#define SANITIZER_IMPORT_INTERFACE 1 +#include "sanitizer_common/sanitizer_win_defs.h" #define WIN32_LEAN_AND_MEAN #include +// Define weak alias for all weak functions imported from asan dll. +#define INTERFACE_FUNCTION(Name) +#define INTERFACE_WEAK_FUNCTION(Name) WIN_WEAK_IMPORT_DEF(Name) +#include "asan_interface.inc" + // 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 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; __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; //////////////////////////////////////////////////////////////////////////////// // 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() +WIN_FORCE_LINK(__asan_dso_reg_hook) -#endif // ASAN_DYNAMIC_RUNTIME_THUNK +#endif // SANITIZER_DYNAMIC_RUNTIME_THUNK Index: projects/clang500-import/contrib/compiler-rt/lib/asan/asan_win_weak_interception.cc =================================================================== --- projects/clang500-import/contrib/compiler-rt/lib/asan/asan_win_weak_interception.cc (nonexistent) +++ projects/clang500-import/contrib/compiler-rt/lib/asan/asan_win_weak_interception.cc (revision 317285) @@ -0,0 +1,23 @@ +//===-- asan_win_weak_interception.cc -------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// This module should be included in Address Sanitizer when it is implemented as +// a shared library on Windows (dll), in order to delegate the calls of weak +// functions to the implementation in the main executable when a strong +// definition is provided. +//===----------------------------------------------------------------------===// +#ifdef SANITIZER_DYNAMIC +#include "sanitizer_common/sanitizer_win_weak_interception.h" +#include "asan_interface_internal.h" +// Check if strong definitions for weak functions are present in the main +// executable. If that is the case, override dll functions to point to strong +// implementations. +#define INTERFACE_FUNCTION(Name) +#define INTERFACE_WEAK_FUNCTION(Name) INTERCEPT_SANITIZER_WEAK_FUNCTION(Name) +#include "asan_interface.inc" +#endif // SANITIZER_DYNAMIC Property changes on: projects/clang500-import/contrib/compiler-rt/lib/asan/asan_win_weak_interception.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/clang500-import/contrib/compiler-rt/lib/builtins/arm/addsf3.S =================================================================== --- projects/clang500-import/contrib/compiler-rt/lib/builtins/arm/addsf3.S (nonexistent) +++ projects/clang500-import/contrib/compiler-rt/lib/builtins/arm/addsf3.S (revision 317285) @@ -0,0 +1,277 @@ +/*===-- addsf3.S - Adds two single precision floating pointer numbers-----===// + * + * 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 __addsf3 (single precision floating pointer number + * addition with the IEEE-754 default rounding (to nearest, ties to even) + * function for the ARM Thumb1 ISA. + * + *===----------------------------------------------------------------------===*/ + +#include "../assembly.h" +#define significandBits 23 +#define typeWidth 32 + + .syntax unified + .text + .thumb + .p2align 2 + +DEFINE_AEABI_FUNCTION_ALIAS(__aeabi_fadd, __addsf3) + +DEFINE_COMPILERRT_THUMB_FUNCTION(__addsf3) + push {r4, r5, r6, r7, lr} + // Get the absolute value of a and b. + lsls r2, r0, #1 + lsls r3, r1, #1 + lsrs r2, r2, #1 /* aAbs */ + beq LOCAL_LABEL(a_zero_nan_inf) + lsrs r3, r3, #1 /* bAbs */ + beq LOCAL_LABEL(zero_nan_inf) + + // Detect if a or b is infinity or Nan. + lsrs r6, r2, #(significandBits) + lsrs r7, r3, #(significandBits) + cmp r6, #0xFF + beq LOCAL_LABEL(zero_nan_inf) + cmp r7, #0xFF + beq LOCAL_LABEL(zero_nan_inf) + + // Swap Rep and Abs so that a and aAbs has the larger absolute value. + cmp r2, r3 + bhs LOCAL_LABEL(no_swap) + movs r4, r0 + movs r5, r2 + movs r0, r1 + movs r2, r3 + movs r1, r4 + movs r3, r5 +LOCAL_LABEL(no_swap): + + // Get the significands and shift them to give us round, guard and sticky. + lsls r4, r0, #(typeWidth - significandBits) + lsrs r4, r4, #(typeWidth - significandBits - 3) /* aSignificand << 3 */ + lsls r5, r1, #(typeWidth - significandBits) + lsrs r5, r5, #(typeWidth - significandBits - 3) /* bSignificand << 3 */ + + // Get the implicitBit. + movs r6, #1 + lsls r6, r6, #(significandBits + 3) + + // Get aExponent and set implicit bit if necessary. + lsrs r2, r2, #(significandBits) + beq LOCAL_LABEL(a_done_implicit_bit) + orrs r4, r6 +LOCAL_LABEL(a_done_implicit_bit): + + // Get bExponent and set implicit bit if necessary. + lsrs r3, r3, #(significandBits) + beq LOCAL_LABEL(b_done_implicit_bit) + orrs r5, r6 +LOCAL_LABEL(b_done_implicit_bit): + + // Get the difference in exponents. + subs r6, r2, r3 + beq LOCAL_LABEL(done_align) + + // If b is denormal, then a must be normal as align > 0, and we only need to + // right shift bSignificand by (align - 1) bits. + cmp r3, #0 + bne 1f + subs r6, r6, #1 +1: + + // No longer needs bExponent. r3 is dead here. + // Set sticky bits of b: sticky = bSignificand << (typeWidth - align). + movs r3, #(typeWidth) + subs r3, r3, r6 + movs r7, r5 + lsls r7, r3 + beq 1f + movs r7, #1 +1: + + // bSignificand = bSignificand >> align | sticky; + lsrs r5, r6 + orrs r5, r7 + bne LOCAL_LABEL(done_align) + movs r5, #1 // sticky; b is known to be non-zero. + +LOCAL_LABEL(done_align): + // isSubtraction = (aRep ^ bRep) >> 31; + movs r7, r0 + eors r7, r1 + lsrs r7, #31 + bne LOCAL_LABEL(do_substraction) + + // Same sign, do Addition. + + // aSignificand += bSignificand; + adds r4, r4, r5 + + // Check carry bit. + movs r6, #1 + lsls r6, r6, #(significandBits + 3 + 1) + movs r7, r4 + ands r7, r6 + beq LOCAL_LABEL(form_result) + // If the addition carried up, we need to right-shift the result and + // adjust the exponent. + movs r7, r4 + movs r6, #1 + ands r7, r6 // sticky = aSignificand & 1; + lsrs r4, #1 + orrs r4, r7 // result Significand + adds r2, #1 // result Exponent + // If we have overflowed the type, return +/- infinity. + cmp r2, 0xFF + beq LOCAL_LABEL(ret_inf) + +LOCAL_LABEL(form_result): + // Shift the sign, exponent and significand into place. + lsrs r0, #(typeWidth - 1) + lsls r0, #(typeWidth - 1) // Get Sign. + lsls r2, #(significandBits) + orrs r0, r2 + movs r1, r4 + lsls r4, #(typeWidth - significandBits - 3) + lsrs r4, #(typeWidth - significandBits) + orrs r0, r4 + + // Final rounding. The result may overflow to infinity, but that is the + // correct result in that case. + // roundGuardSticky = aSignificand & 0x7; + movs r2, #0x7 + ands r1, r2 + // if (roundGuardSticky > 0x4) result++; + + cmp r1, #0x4 + blt LOCAL_LABEL(done_round) + beq 1f + adds r0, #1 + pop {r4, r5, r6, r7, pc} +1: + + // if (roundGuardSticky == 0x4) result += result & 1; + movs r1, r0 + lsrs r1, #1 + bcc LOCAL_LABEL(done_round) + adds r0, r0, #1 +LOCAL_LABEL(done_round): + pop {r4, r5, r6, r7, pc} + +LOCAL_LABEL(do_substraction): + subs r4, r4, r5 // aSignificand -= bSignificand; + beq LOCAL_LABEL(ret_zero) + movs r6, r4 + cmp r2, 0 + beq LOCAL_LABEL(form_result) // if a's exp is 0, no need to normalize. + // If partial cancellation occured, we need to left-shift the result + // and adjust the exponent: + lsrs r6, r6, #(significandBits + 3) + bne LOCAL_LABEL(form_result) + + push {r0, r1, r2, r3} + movs r0, r4 + bl __clzsi2 + movs r5, r0 + pop {r0, r1, r2, r3} + // shift = rep_clz(aSignificand) - rep_clz(implicitBit << 3); + subs r5, r5, #(typeWidth - significandBits - 3 - 1) + // aSignificand <<= shift; aExponent -= shift; + lsls r4, r5 + subs r2, r2, r5 + bgt LOCAL_LABEL(form_result) + + // Do normalization if aExponent <= 0. + movs r6, #1 + subs r6, r6, r2 // 1 - aExponent; + movs r2, #0 // aExponent = 0; + movs r3, #(typeWidth) // bExponent is dead. + subs r3, r3, r6 + movs r7, r4 + lsls r7, r3 // stickyBit = (bool)(aSignificant << (typeWidth - align)) + beq 1f + movs r7, #1 +1: + lsrs r4, r6 /* aSignificand >> shift */ + orrs r4, r7 + b LOCAL_LABEL(form_result) + +LOCAL_LABEL(ret_zero): + movs r0, #0 + pop {r4, r5, r6, r7, pc} + + +LOCAL_LABEL(a_zero_nan_inf): + lsrs r3, r3, #1 + +LOCAL_LABEL(zero_nan_inf): + // Here r2 has aAbs, r3 has bAbs + movs r4, #0xFF + lsls r4, r4, #(significandBits) // Make +inf. + + cmp r2, r4 + bhi LOCAL_LABEL(a_is_nan) + cmp r3, r4 + bhi LOCAL_LABEL(b_is_nan) + + cmp r2, r4 + bne LOCAL_LABEL(a_is_rational) + // aAbs is INF. + eors r1, r0 // aRep ^ bRep. + movs r6, #1 + lsls r6, r6, #(typeWidth - 1) // get sign mask. + cmp r1, r6 // if they only differ on sign bit, it's -INF + INF + beq LOCAL_LABEL(a_is_nan) + pop {r4, r5, r6, r7, pc} + +LOCAL_LABEL(a_is_rational): + cmp r3, r4 + bne LOCAL_LABEL(b_is_rational) + movs r0, r1 + pop {r4, r5, r6, r7, pc} + +LOCAL_LABEL(b_is_rational): + // either a or b or both are zero. + adds r4, r2, r3 + beq LOCAL_LABEL(both_zero) + cmp r2, #0 // is absA 0 ? + beq LOCAL_LABEL(ret_b) + pop {r4, r5, r6, r7, pc} + +LOCAL_LABEL(both_zero): + ands r0, r1 // +0 + -0 = +0 + pop {r4, r5, r6, r7, pc} + +LOCAL_LABEL(ret_b): + movs r0, r1 + +LOCAL_LABEL(ret): + pop {r4, r5, r6, r7, pc} + +LOCAL_LABEL(b_is_nan): + movs r0, r1 +LOCAL_LABEL(a_is_nan): + movs r1, #1 + lsls r1, r1, #(significandBits -1) // r1 is quiet bit. + orrs r0, r1 + pop {r4, r5, r6, r7, pc} + +LOCAL_LABEL(ret_inf): + movs r4, #0xFF + lsls r4, r4, #(significandBits) + orrs r0, r4 + lsrs r0, r0, #(significandBits) + lsls r0, r0, #(significandBits) + pop {r4, r5, r6, r7, pc} + + +END_COMPILERRT_FUNCTION(__addsf3) + +NO_EXEC_STACK_DIRECTIVE Property changes on: projects/clang500-import/contrib/compiler-rt/lib/builtins/arm/addsf3.S ___________________________________________________________________ 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/clang500-import/contrib/compiler-rt/lib/builtins/arm/aeabi_cdcmp.S =================================================================== --- projects/clang500-import/contrib/compiler-rt/lib/builtins/arm/aeabi_cdcmp.S (revision 317284) +++ projects/clang500-import/contrib/compiler-rt/lib/builtins/arm/aeabi_cdcmp.S (revision 317285) @@ -1,98 +1,135 @@ //===-- aeabi_cdcmp.S - EABI cdcmp* 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" #if __BYTE_ORDER__ != __ORDER_LITTLE_ENDIAN__ #error big endian support not implemented #endif #define APSR_Z (1 << 30) #define APSR_C (1 << 29) // void __aeabi_cdcmpeq(double a, double b) { // if (isnan(a) || isnan(b)) { // Z = 0; C = 1; // } else { // __aeabi_cdcmple(a, b); // } // } .syntax unified .p2align 2 DEFINE_COMPILERRT_FUNCTION(__aeabi_cdcmpeq) push {r0-r3, lr} bl __aeabi_cdcmpeq_check_nan cmp r0, #1 +#if __ARM_ARCH_ISA_THUMB == 1 + beq 1f + // NaN has been ruled out, so __aeabi_cdcmple can't trap + mov r0, sp + ldm r0, {r0-r3} + bl __aeabi_cdcmple + pop {r0-r3, pc} +1: + // Z = 0, C = 1 + movs r0, #0xF + lsls r0, r0, #31 + pop {r0-r3, pc} +#else pop {r0-r3, lr} // NaN has been ruled out, so __aeabi_cdcmple can't trap bne __aeabi_cdcmple msr CPSR_f, #APSR_C JMP(lr) +#endif END_COMPILERRT_FUNCTION(__aeabi_cdcmpeq) // void __aeabi_cdcmple(double a, double b) { // if (__aeabi_dcmplt(a, b)) { // Z = 0; C = 0; // } else if (__aeabi_dcmpeq(a, b)) { // Z = 1; C = 1; // } else { // Z = 0; C = 1; // } // } .syntax unified .p2align 2 DEFINE_COMPILERRT_FUNCTION(__aeabi_cdcmple) // Per the RTABI, this function must preserve r0-r11. // Save lr in the same instruction for compactness push {r0-r3, lr} bl __aeabi_dcmplt cmp r0, #1 +#if __ARM_ARCH_ISA_THUMB == 1 + bne 1f + // Z = 0, C = 0 + movs r0, #1 + lsls r0, r0, #1 + pop {r0-r3, pc} +1: + mov r0, sp + ldm r0, {r0-r3} + bl __aeabi_dcmpeq + cmp r0, #1 + bne 2f + // Z = 1, C = 1 + movs r0, #2 + lsls r0, r0, #31 + pop {r0-r3, pc} +2: + // Z = 0, C = 1 + movs r0, #0xF + lsls r0, r0, #31 + pop {r0-r3, pc} +#else moveq ip, #0 beq 1f ldm sp, {r0-r3} bl __aeabi_dcmpeq cmp r0, #1 moveq ip, #(APSR_C | APSR_Z) movne ip, #(APSR_C) 1: msr CPSR_f, ip pop {r0-r3} POP_PC() +#endif END_COMPILERRT_FUNCTION(__aeabi_cdcmple) // int __aeabi_cdrcmple(double a, double b) { // return __aeabi_cdcmple(b, a); // } .syntax unified .p2align 2 DEFINE_COMPILERRT_FUNCTION(__aeabi_cdrcmple) // Swap r0 and r2 mov ip, r0 mov r0, r2 mov r2, ip // Swap r1 and r3 mov ip, r1 mov r1, r3 mov r3, ip b __aeabi_cdcmple END_COMPILERRT_FUNCTION(__aeabi_cdrcmple) NO_EXEC_STACK_DIRECTIVE Index: projects/clang500-import/contrib/compiler-rt/lib/builtins/arm/aeabi_cfcmp.S =================================================================== --- projects/clang500-import/contrib/compiler-rt/lib/builtins/arm/aeabi_cfcmp.S (revision 317284) +++ projects/clang500-import/contrib/compiler-rt/lib/builtins/arm/aeabi_cfcmp.S (revision 317285) @@ -1,93 +1,130 @@ //===-- aeabi_cfcmp.S - EABI cfcmp* 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" #if __BYTE_ORDER__ != __ORDER_LITTLE_ENDIAN__ #error big endian support not implemented #endif #define APSR_Z (1 << 30) #define APSR_C (1 << 29) // void __aeabi_cfcmpeq(float a, float b) { // if (isnan(a) || isnan(b)) { // Z = 0; C = 1; // } else { // __aeabi_cfcmple(a, b); // } // } .syntax unified .p2align 2 DEFINE_COMPILERRT_FUNCTION(__aeabi_cfcmpeq) push {r0-r3, lr} bl __aeabi_cfcmpeq_check_nan cmp r0, #1 +#if __ARM_ARCH_ISA_THUMB == 1 + beq 1f + // NaN has been ruled out, so __aeabi_cfcmple can't trap + mov r0, sp + ldm r0, {r0-r3} + bl __aeabi_cfcmple + pop {r0-r3, pc} +1: + // Z = 0, C = 1 + movs r0, #0xF + lsls r0, r0, #31 + pop {r0-r3, pc} +#else pop {r0-r3, lr} // NaN has been ruled out, so __aeabi_cfcmple can't trap bne __aeabi_cfcmple msr CPSR_f, #APSR_C JMP(lr) +#endif END_COMPILERRT_FUNCTION(__aeabi_cfcmpeq) // void __aeabi_cfcmple(float a, float b) { // if (__aeabi_fcmplt(a, b)) { // Z = 0; C = 0; // } else if (__aeabi_fcmpeq(a, b)) { // Z = 1; C = 1; // } else { // Z = 0; C = 1; // } // } .syntax unified .p2align 2 DEFINE_COMPILERRT_FUNCTION(__aeabi_cfcmple) // Per the RTABI, this function must preserve r0-r11. // Save lr in the same instruction for compactness push {r0-r3, lr} bl __aeabi_fcmplt cmp r0, #1 +#if __ARM_ARCH_ISA_THUMB == 1 + bne 1f + // Z = 0, C = 0 + movs r0, #1 + lsls r0, r0, #1 + pop {r0-r3, pc} +1: + mov r0, sp + ldm r0, {r0-r3} + bl __aeabi_fcmpeq + cmp r0, #1 + bne 2f + // Z = 1, C = 1 + movs r0, #2 + lsls r0, r0, #31 + pop {r0-r3, pc} +2: + // Z = 0, C = 1 + movs r0, #0xF + lsls r0, r0, #31 + pop {r0-r3, pc} +#else moveq ip, #0 beq 1f ldm sp, {r0-r3} bl __aeabi_fcmpeq cmp r0, #1 moveq ip, #(APSR_C | APSR_Z) movne ip, #(APSR_C) 1: msr CPSR_f, ip pop {r0-r3} POP_PC() +#endif END_COMPILERRT_FUNCTION(__aeabi_cfcmple) // int __aeabi_cfrcmple(float a, float b) { // return __aeabi_cfcmple(b, a); // } .syntax unified .p2align 2 DEFINE_COMPILERRT_FUNCTION(__aeabi_cfrcmple) // Swap r0 and r1 mov ip, r0 mov r0, r1 mov r1, ip b __aeabi_cfcmple END_COMPILERRT_FUNCTION(__aeabi_cfrcmple) NO_EXEC_STACK_DIRECTIVE Index: projects/clang500-import/contrib/compiler-rt/lib/builtins/arm/aeabi_dcmp.S =================================================================== --- projects/clang500-import/contrib/compiler-rt/lib/builtins/arm/aeabi_dcmp.S (revision 317284) +++ projects/clang500-import/contrib/compiler-rt/lib/builtins/arm/aeabi_dcmp.S (revision 317285) @@ -1,43 +1,43 @@ //===-- aeabi_dcmp.S - EABI dcmp* 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" // int __aeabi_dcmp{eq,lt,le,ge,gt}(double a, double b) { // int result = __{eq,lt,le,ge,gt}df2(a, b); // if (result {==,<,<=,>=,>} 0) { // return 1; // } else { // return 0; // } // } #define DEFINE_AEABI_DCMP(cond) \ .syntax unified SEPARATOR \ .p2align 2 SEPARATOR \ DEFINE_COMPILERRT_FUNCTION(__aeabi_dcmp ## cond) \ push { r4, lr } SEPARATOR \ bl SYMBOL_NAME(__ ## cond ## df2) SEPARATOR \ cmp r0, #0 SEPARATOR \ b ## cond 1f SEPARATOR \ - mov r0, #0 SEPARATOR \ + movs r0, #0 SEPARATOR \ pop { r4, pc } SEPARATOR \ 1: SEPARATOR \ - mov r0, #1 SEPARATOR \ + movs r0, #1 SEPARATOR \ pop { r4, pc } SEPARATOR \ END_COMPILERRT_FUNCTION(__aeabi_dcmp ## cond) DEFINE_AEABI_DCMP(eq) DEFINE_AEABI_DCMP(lt) DEFINE_AEABI_DCMP(le) DEFINE_AEABI_DCMP(ge) DEFINE_AEABI_DCMP(gt) NO_EXEC_STACK_DIRECTIVE Index: projects/clang500-import/contrib/compiler-rt/lib/builtins/arm/aeabi_idivmod.S =================================================================== --- projects/clang500-import/contrib/compiler-rt/lib/builtins/arm/aeabi_idivmod.S (revision 317284) +++ projects/clang500-import/contrib/compiler-rt/lib/builtins/arm/aeabi_idivmod.S (revision 317285) @@ -1,58 +1,58 @@ //===-- 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 .syntax unified .text #if defined(USE_THUMB_PROLOGUE) .thumb #endif .p2align 2 #if defined(USE_THUMB_PROLOGUE) DEFINE_COMPILERRT_THUMB_FUNCTION(__aeabi_idivmod) #else DEFINE_COMPILERRT_FUNCTION(__aeabi_idivmod) #endif #if defined(USE_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 + muls r2, r0, r2 // r2 = quot * denom subs r1, r1, r2 JMP (r3) #else // defined(USE_THUMB_1) 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 // defined(USE_THUMB_1) END_COMPILERRT_FUNCTION(__aeabi_idivmod) NO_EXEC_STACK_DIRECTIVE Index: projects/clang500-import/contrib/compiler-rt/lib/builtins/arm/aeabi_ldivmod.S =================================================================== --- projects/clang500-import/contrib/compiler-rt/lib/builtins/arm/aeabi_ldivmod.S (revision 317284) +++ projects/clang500-import/contrib/compiler-rt/lib/builtins/arm/aeabi_ldivmod.S (revision 317285) @@ -1,46 +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} + push {r6, lr} sub sp, sp, #16 - add r12, sp, #8 - str r12, [sp] + add r6, sp, #8 + str r6, [sp] #if defined(__MINGW32__) - mov r12, r0 - mov r0, r2 - mov r2, r12 - mov r12, r1 - mov r1, r3 - mov r3, r12 + movs r6, r0 + movs r0, r2 + movs r2, r6 + movs r6, r1 + movs r1, r3 + movs r3, r6 #endif bl SYMBOL_NAME(__divmoddi4) ldr r2, [sp, #8] ldr r3, [sp, #12] add sp, sp, #16 - pop {r11, pc} + pop {r6, pc} END_COMPILERRT_FUNCTION(__aeabi_ldivmod) NO_EXEC_STACK_DIRECTIVE Index: projects/clang500-import/contrib/compiler-rt/lib/builtins/arm/aeabi_memset.S =================================================================== --- projects/clang500-import/contrib/compiler-rt/lib/builtins/arm/aeabi_memset.S (revision 317284) +++ projects/clang500-import/contrib/compiler-rt/lib/builtins/arm/aeabi_memset.S (revision 317285) @@ -1,37 +1,37 @@ //===-- aeabi_memset.S - EABI memset 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" // void __aeabi_memset(void *dest, size_t n, int c) { memset(dest, c, n); } // void __aeabi_memclr(void *dest, size_t n) { __aeabi_memset(dest, n, 0); } .syntax unified .p2align 2 DEFINE_COMPILERRT_FUNCTION(__aeabi_memset) mov r3, r1 mov r1, r2 mov r2, r3 b memset END_COMPILERRT_FUNCTION(__aeabi_memset) DEFINE_AEABI_FUNCTION_ALIAS(__aeabi_memset4, __aeabi_memset) DEFINE_AEABI_FUNCTION_ALIAS(__aeabi_memset8, __aeabi_memset) DEFINE_COMPILERRT_FUNCTION(__aeabi_memclr) mov r2, r1 - mov r1, #0 + movs r1, #0 b memset END_COMPILERRT_FUNCTION(__aeabi_memclr) DEFINE_AEABI_FUNCTION_ALIAS(__aeabi_memclr4, __aeabi_memclr) DEFINE_AEABI_FUNCTION_ALIAS(__aeabi_memclr8, __aeabi_memclr) NO_EXEC_STACK_DIRECTIVE Index: projects/clang500-import/contrib/compiler-rt/lib/builtins/arm/aeabi_uidivmod.S =================================================================== --- projects/clang500-import/contrib/compiler-rt/lib/builtins/arm/aeabi_uidivmod.S (revision 317284) +++ projects/clang500-import/contrib/compiler-rt/lib/builtins/arm/aeabi_uidivmod.S (revision 317285) @@ -1,64 +1,64 @@ //===-- 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 .text #if defined(USE_THUMB_PROLOGUE) .thumb #endif .p2align 2 #if defined(USE_THUMB_PROLOGUE) DEFINE_COMPILERRT_THUMB_FUNCTION(__aeabi_uidivmod) #else DEFINE_COMPILERRT_FUNCTION(__aeabi_uidivmod) #endif #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 + muls r2, r0, r2 // 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/clang500-import/contrib/compiler-rt/lib/builtins/arm/aeabi_uldivmod.S =================================================================== --- projects/clang500-import/contrib/compiler-rt/lib/builtins/arm/aeabi_uldivmod.S (revision 317284) +++ projects/clang500-import/contrib/compiler-rt/lib/builtins/arm/aeabi_uldivmod.S (revision 317285) @@ -1,46 +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} + push {r6, lr} sub sp, sp, #16 - add r12, sp, #8 - str r12, [sp] + add r6, sp, #8 + str r6, [sp] #if defined(__MINGW32__) - mov r12, r0 - mov r0, r2 - mov r2, r12 - mov r12, r1 - mov r1, r3 - mov r3, r12 + movs r6, r0 + movs r0, r2 + movs r2, r6 + movs r6, r1 + movs r1, r3 + movs r3, r6 #endif bl SYMBOL_NAME(__udivmoddi4) ldr r2, [sp, #8] ldr r3, [sp, #12] add sp, sp, #16 - pop {r11, pc} + pop {r6, pc} END_COMPILERRT_FUNCTION(__aeabi_uldivmod) NO_EXEC_STACK_DIRECTIVE Index: projects/clang500-import/contrib/compiler-rt/lib/builtins/arm/comparesf2.S =================================================================== --- projects/clang500-import/contrib/compiler-rt/lib/builtins/arm/comparesf2.S (revision 317284) +++ projects/clang500-import/contrib/compiler-rt/lib/builtins/arm/comparesf2.S (revision 317285) @@ -1,310 +1,310 @@ //===-- 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 .text #if defined(USE_THUMB_PROLOGUE) .thumb #endif @ int __eqsf2(float a, float b) .p2align 2 #if defined(USE_THUMB_PROLOGUE) DEFINE_COMPILERRT_THUMB_FUNCTION(__eqsf2) #else DEFINE_COMPILERRT_FUNCTION(__eqsf2) #endif #if defined(COMPILER_RT_ARMHF_TARGET) vmov r0, s0 vmov r1, s1 #endif // Make copies of a and b with the sign bit shifted off the top. These will // be used to detect zeros and NaNs. #if __ARM_ARCH_ISA_THUMB == 1 push {r6, lr} lsls r2, r0, #1 lsls r3, r1, #1 #else mov r2, r0, lsl #1 mov r3, r1, lsl #1 #endif // 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. #if defined(USE_THUMB_1) lsrs r6, r3, #1 - orrs r6, r2, r6 + orrs r6, r2 #else orrs r12, r2, r3, lsr #1 #endif // 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. #if defined(USE_THUMB_1) beq 1f movs r6, r0 eors r6, r1 1: #else it ne eorsne r12, r0, r1 #endif // 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. #if defined(USE_THUMB_1) bmi 1f subs r0, r2, r3 1: #else it pl subspl r0, r2, r3 #endif // 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. #if defined(USE_THUMB_1) bhs 1f // Here if a and b have the same sign and absA < absB, the result is thus // b < 0 ? 1 : -1. Same if a and b have the opposite sign (ignoring Nan). movs r0, #1 lsrs r1, #31 bne LOCAL_LABEL(CHECK_NAN) negs r0, r0 b LOCAL_LABEL(CHECK_NAN) 1: #else it lo mvnlo r0, r1, asr #31 #endif // 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. #if defined(USE_THUMB_1) bls 1f // Here both have the same sign and absA > absB. movs r0, #1 lsrs r1, #31 beq LOCAL_LABEL(CHECK_NAN) negs r0, r0 1: #else it hi movhi r0, r1, asr #31 #endif // 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. // For Thumb-1, r0 contains -1 if a < b, 0 if a > b and 0 if a == b. #if defined(USE_THUMB_1) it ne orrne r0, r0, #1 #endif // Finally, we need to deal with NaNs. If either argument is NaN, replace // the value in r0 with 1. #if defined(USE_THUMB_1) LOCAL_LABEL(CHECK_NAN): movs r6, #0xff lsls r6, #24 cmp r2, r6 bhi 1f cmp r3, r6 1: bls 2f movs r0, #1 2: pop {r6, pc} #else cmp r2, #0xff000000 ite ls cmpls r3, #0xff000000 movhi r0, #1 JMP(lr) #endif END_COMPILERRT_FUNCTION(__eqsf2) DEFINE_COMPILERRT_FUNCTION_ALIAS(__lesf2, __eqsf2) DEFINE_COMPILERRT_FUNCTION_ALIAS(__ltsf2, __eqsf2) DEFINE_COMPILERRT_FUNCTION_ALIAS(__nesf2, __eqsf2) @ int __gtsf2(float a, float b) .p2align 2 #if defined(USE_THUMB) DEFINE_COMPILERRT_THUMB_FUNCTION(__gtsf2) #else DEFINE_COMPILERRT_FUNCTION(__gtsf2) #endif // 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. #if defined(COMPILER_RT_ARMHF_TARGET) vmov r0, s0 vmov r1, s1 #endif #if defined(USE_THUMB_1) push {r6, lr} lsls r2, r0, #1 lsls r3, r1, #1 lsrs r6, r3, #1 - orrs r6, r2, r6 + orrs r6, r2 beq 1f movs r6, r0 eors r6, r1 1: bmi 2f subs r0, r2, r3 2: bhs 3f movs r0, #1 lsrs r1, #31 bne LOCAL_LABEL(CHECK_NAN_2) negs r0, r0 b LOCAL_LABEL(CHECK_NAN_2) 3: bls 4f movs r0, #1 lsrs r1, #31 beq LOCAL_LABEL(CHECK_NAN_2) negs r0, r0 4: LOCAL_LABEL(CHECK_NAN_2): movs r6, #0xff lsls r6, #24 cmp r2, r6 bhi 5f cmp r3, r6 5: bls 6f movs r0, #1 negs r0, r0 6: pop {r6, pc} #else 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) #endif END_COMPILERRT_FUNCTION(__gtsf2) DEFINE_COMPILERRT_FUNCTION_ALIAS(__gesf2, __gtsf2) @ int __unordsf2(float a, float b) .p2align 2 #if defined(USE_THUMB) DEFINE_COMPILERRT_THUMB_FUNCTION(__unordsf2) #else DEFINE_COMPILERRT_FUNCTION(__unordsf2) #endif #if defined(COMPILER_RT_ARMHF_TARGET) vmov r0, s0 vmov r1, s1 #endif // Return 1 for NaN values, 0 otherwise. lsls r2, r0, #1 lsls r3, r1, #1 movs r0, #0 #if defined(USE_THUMB_1) movs r1, #0xff lsls r1, #24 cmp r2, r1 bhi 1f cmp r3, r1 1: bls 2f movs r0, #1 2: #else cmp r2, #0xff000000 ite ls cmpls r3, #0xff000000 movhi r0, #1 #endif JMP(lr) END_COMPILERRT_FUNCTION(__unordsf2) #if defined(COMPILER_RT_ARMHF_TARGET) DEFINE_COMPILERRT_FUNCTION(__aeabi_fcmpum) vmov s0, r0 vmov s1, r1 b SYMBOL_NAME(__unordsf2) END_COMPILERRT_FUNCTION(__aeabi_fcmpum) #else DEFINE_AEABI_FUNCTION_ALIAS(__aeabi_fcmpun, __unordsf2) #endif NO_EXEC_STACK_DIRECTIVE Index: projects/clang500-import/contrib/compiler-rt/lib/builtins/arm/udivsi3.S =================================================================== --- projects/clang500-import/contrib/compiler-rt/lib/builtins/arm/udivsi3.S (revision 317284) +++ projects/clang500-import/contrib/compiler-rt/lib/builtins/arm/udivsi3.S (revision 317285) @@ -1,267 +1,269 @@ /*===-- 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 defined(USE_THUMB_PROLOGUE) .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 defined(USE_THUMB_PROLOGUE) 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 + +LOCAL_LABEL(divby0): + mov r0, #0 +# ifdef __ARM_EABI__ + b __aeabi_idiv0 +# else + JMP(lr) +# endif + +#else /* ! __ARM_ARCH_EXT_IDIV__ */ cmp r1, #1 bcc LOCAL_LABEL(divby0) #if defined(USE_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 defined(USE_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. */ # 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 defined(USE_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 /* No CLZ Feature */ # if defined(USE_THUMB_2) # error THUMB mode requires CLZ or UDIV # endif # if defined(USE_THUMB_1) # define BLOCK_SIZE 10 # else # define BLOCK_SIZE 12 # endif mov r2, r0 # if defined(USE_THUMB_1) mov ip, r0 adr r0, LOCAL_LABEL(div0block) adds r0, #1 # else adr ip, LOCAL_LABEL(div0block) # endif lsrs r3, r2, #16 cmp r3, r1 # if defined(USE_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 * BLOCK_SIZE) # endif lsrs r3, r2, #8 cmp r3, r1 # if defined(USE_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 * BLOCK_SIZE) # endif lsrs r3, r2, #4 cmp r3, r1 # if defined(USE_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 * BLOCK_SIZE) # endif lsrs r3, r2, #2 cmp r3, r1 # if defined(USE_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 * BLOCK_SIZE) # endif /* Last block, no need to update r2 or r3. */ # if defined(USE_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 * BLOCK_SIZE) movs r3, #0 JMP(ip) # 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__) + push {r7, lr} bl __aeabi_idiv0 // due to relocation limit, can't use b. -# endif + pop {r7, pc} +# else JMP(lr) +# endif #if defined(USE_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) -# endif -#endif END_COMPILERRT_FUNCTION(__udivsi3) NO_EXEC_STACK_DIRECTIVE Index: projects/clang500-import/contrib/compiler-rt/lib/builtins/clear_cache.c =================================================================== --- projects/clang500-import/contrib/compiler-rt/lib/builtins/clear_cache.c (revision 317284) +++ projects/clang500-import/contrib/compiler-rt/lib/builtins/clear_cache.c (revision 317285) @@ -1,172 +1,177 @@ /* ===-- 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__ +#if __i386__ || __x86_64__ || defined(_M_IX86) || defined(_M_X64) /* * 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__) + /* + * We used to include asm/unistd.h for the __ARM_NR_cacheflush define, but + * it also brought many other unused defines, as well as a dependency on + * kernel headers to be installed. + * + * This value is stable at least since Linux 3.13 and should remain so for + * compatibility reasons, warranting it's re-definition here. + */ + #define __ARM_NR_cacheflush 0x0f0002 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"(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/clang500-import/contrib/compiler-rt/lib/builtins/cpu_model.c =================================================================== --- projects/clang500-import/contrib/compiler-rt/lib/builtins/cpu_model.c (revision 317284) +++ projects/clang500-import/contrib/compiler-rt/lib/builtins/cpu_model.c (revision 317285) @@ -1,797 +1,804 @@ //===-- cpu_model.c - Support for __cpu_model builtin ------------*- 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 based on LLVM's lib/Support/Host.cpp. // It implements the operating system Host concept and builtin // __cpu_model for the compiler_rt library, for x86 only. // //===----------------------------------------------------------------------===// #if (defined(__i386__) || defined(_M_IX86) || \ defined(__x86_64__) || defined(_M_X64)) && \ (defined(__GNUC__) || defined(__clang__) || defined(_MSC_VER)) #include #define bool int #define true 1 #define false 0 #ifdef _MSC_VER #include #endif +#ifndef __has_attribute +#define __has_attribute(attr) 0 +#endif + enum VendorSignatures { SIG_INTEL = 0x756e6547 /* Genu */, SIG_AMD = 0x68747541 /* Auth */ }; enum ProcessorVendors { VENDOR_INTEL = 1, VENDOR_AMD, VENDOR_OTHER, VENDOR_MAX }; enum ProcessorTypes { INTEL_ATOM = 1, INTEL_CORE2, INTEL_COREI7, AMDFAM10H, AMDFAM15H, INTEL_i386, INTEL_i486, INTEL_PENTIUM, INTEL_PENTIUM_PRO, INTEL_PENTIUM_II, INTEL_PENTIUM_III, INTEL_PENTIUM_IV, INTEL_PENTIUM_M, INTEL_CORE_DUO, INTEL_XEONPHI, INTEL_X86_64, INTEL_NOCONA, INTEL_PRESCOTT, AMD_i486, AMDPENTIUM, AMDATHLON, AMDFAM14H, AMDFAM16H, CPU_TYPE_MAX }; enum ProcessorSubtypes { INTEL_COREI7_NEHALEM = 1, INTEL_COREI7_WESTMERE, INTEL_COREI7_SANDYBRIDGE, AMDFAM10H_BARCELONA, AMDFAM10H_SHANGHAI, AMDFAM10H_ISTANBUL, AMDFAM15H_BDVER1, AMDFAM15H_BDVER2, INTEL_PENTIUM_MMX, INTEL_CORE2_65, INTEL_CORE2_45, INTEL_COREI7_IVYBRIDGE, INTEL_COREI7_HASWELL, INTEL_COREI7_BROADWELL, INTEL_COREI7_SKYLAKE, INTEL_COREI7_SKYLAKE_AVX512, INTEL_ATOM_BONNELL, INTEL_ATOM_SILVERMONT, INTEL_KNIGHTS_LANDING, AMDPENTIUM_K6, AMDPENTIUM_K62, AMDPENTIUM_K63, AMDPENTIUM_GEODE, AMDATHLON_TBIRD, AMDATHLON_MP, AMDATHLON_XP, AMDATHLON_K8SSE3, AMDATHLON_OPTERON, AMDATHLON_FX, AMDATHLON_64, AMD_BTVER1, AMD_BTVER2, AMDFAM15H_BDVER3, AMDFAM15H_BDVER4, CPU_SUBTYPE_MAX }; enum ProcessorFeatures { FEATURE_CMOV = 0, FEATURE_MMX, FEATURE_POPCNT, FEATURE_SSE, FEATURE_SSE2, FEATURE_SSE3, FEATURE_SSSE3, FEATURE_SSE4_1, FEATURE_SSE4_2, FEATURE_AVX, FEATURE_AVX2, FEATURE_AVX512, FEATURE_AVX512SAVE, FEATURE_MOVBE, FEATURE_ADX, FEATURE_EM64T }; // The check below for i386 was copied from clang's cpuid.h (__get_cpuid_max). // Check motivated by bug reports for OpenSSL crashing on CPUs without CPUID // support. Consequently, for i386, the presence of CPUID is checked first // via the corresponding eflags bit. static bool isCpuIdSupported() { #if defined(__GNUC__) || defined(__clang__) #if defined(__i386__) int __cpuid_supported; __asm__(" pushfl\n" " popl %%eax\n" " movl %%eax,%%ecx\n" " xorl $0x00200000,%%eax\n" " pushl %%eax\n" " popfl\n" " pushfl\n" " popl %%eax\n" " movl $0,%0\n" " cmpl %%eax,%%ecx\n" " je 1f\n" " movl $1,%0\n" "1:" : "=r"(__cpuid_supported) : : "eax", "ecx"); if (!__cpuid_supported) return false; #endif return true; #endif return true; } // This code is copied from lib/Support/Host.cpp. // Changes to either file should be mirrored in the other. /// getX86CpuIDAndInfo - Execute the specified cpuid and return the 4 values in /// the specified arguments. If we can't run cpuid on the host, return true. static void getX86CpuIDAndInfo(unsigned value, unsigned *rEAX, unsigned *rEBX, unsigned *rECX, unsigned *rEDX) { #if defined(__GNUC__) || defined(__clang__) #if defined(__x86_64__) // gcc doesn't know cpuid would clobber ebx/rbx. Preseve it manually. __asm__("movq\t%%rbx, %%rsi\n\t" "cpuid\n\t" "xchgq\t%%rbx, %%rsi\n\t" : "=a"(*rEAX), "=S"(*rEBX), "=c"(*rECX), "=d"(*rEDX) : "a"(value)); #elif defined(__i386__) __asm__("movl\t%%ebx, %%esi\n\t" "cpuid\n\t" "xchgl\t%%ebx, %%esi\n\t" : "=a"(*rEAX), "=S"(*rEBX), "=c"(*rECX), "=d"(*rEDX) : "a"(value)); // pedantic #else returns to appease -Wunreachable-code (so we don't generate // postprocessed code that looks like "return true; return false;") #else assert(0 && "This method is defined only for x86."); #endif #elif defined(_MSC_VER) // The MSVC intrinsic is portable across x86 and x64. int registers[4]; __cpuid(registers, value); *rEAX = registers[0]; *rEBX = registers[1]; *rECX = registers[2]; *rEDX = registers[3]; #else assert(0 && "This method is defined only for GNUC, Clang or MSVC."); #endif } /// getX86CpuIDAndInfoEx - Execute the specified cpuid with subleaf and return /// the 4 values in the specified arguments. If we can't run cpuid on the host, /// return true. static void getX86CpuIDAndInfoEx(unsigned value, unsigned subleaf, unsigned *rEAX, unsigned *rEBX, unsigned *rECX, unsigned *rEDX) { #if defined(__x86_64__) || defined(_M_X64) #if defined(__GNUC__) || defined(__clang__) // gcc doesn't know cpuid would clobber ebx/rbx. Preserve it manually. // FIXME: should we save this for Clang? __asm__("movq\t%%rbx, %%rsi\n\t" "cpuid\n\t" "xchgq\t%%rbx, %%rsi\n\t" : "=a"(*rEAX), "=S"(*rEBX), "=c"(*rECX), "=d"(*rEDX) : "a"(value), "c"(subleaf)); #elif defined(_MSC_VER) int registers[4]; __cpuidex(registers, value, subleaf); *rEAX = registers[0]; *rEBX = registers[1]; *rECX = registers[2]; *rEDX = registers[3]; #else assert(0 && "This method is defined only for GNUC, Clang or MSVC."); #endif #elif defined(__i386__) || defined(_M_IX86) #if defined(__GNUC__) || defined(__clang__) __asm__("movl\t%%ebx, %%esi\n\t" "cpuid\n\t" "xchgl\t%%ebx, %%esi\n\t" : "=a"(*rEAX), "=S"(*rEBX), "=c"(*rECX), "=d"(*rEDX) : "a"(value), "c"(subleaf)); #elif defined(_MSC_VER) __asm { mov eax,value mov ecx,subleaf cpuid mov esi,rEAX mov dword ptr [esi],eax mov esi,rEBX mov dword ptr [esi],ebx mov esi,rECX mov dword ptr [esi],ecx mov esi,rEDX mov dword ptr [esi],edx } #else assert(0 && "This method is defined only for GNUC, Clang or MSVC."); #endif #else assert(0 && "This method is defined only for x86."); #endif } // Read control register 0 (XCR0). Used to detect features such as AVX. static bool getX86XCR0(unsigned *rEAX, unsigned *rEDX) { #if defined(__GNUC__) || defined(__clang__) // Check xgetbv; this uses a .byte sequence instead of the instruction // directly because older assemblers do not include support for xgetbv and // there is no easy way to conditionally compile based on the assembler used. __asm__(".byte 0x0f, 0x01, 0xd0" : "=a"(*rEAX), "=d"(*rEDX) : "c"(0)); return false; #elif defined(_MSC_FULL_VER) && defined(_XCR_XFEATURE_ENABLED_MASK) unsigned long long Result = _xgetbv(_XCR_XFEATURE_ENABLED_MASK); *rEAX = Result; *rEDX = Result >> 32; return false; #else return true; #endif } static void detectX86FamilyModel(unsigned EAX, unsigned *Family, unsigned *Model) { *Family = (EAX >> 8) & 0xf; // Bits 8 - 11 *Model = (EAX >> 4) & 0xf; // Bits 4 - 7 if (*Family == 6 || *Family == 0xf) { if (*Family == 0xf) // Examine extended family ID if family ID is F. *Family += (EAX >> 20) & 0xff; // Bits 20 - 27 // Examine extended model ID if family ID is 6 or F. *Model += ((EAX >> 16) & 0xf) << 4; // Bits 16 - 19 } } static void getIntelProcessorTypeAndSubtype(unsigned int Family, unsigned int Model, unsigned int Brand_id, unsigned int Features, unsigned *Type, unsigned *Subtype) { if (Brand_id != 0) return; switch (Family) { case 3: *Type = INTEL_i386; break; case 4: switch (Model) { case 0: // Intel486 DX processors case 1: // Intel486 DX processors case 2: // Intel486 SX processors case 3: // Intel487 processors, IntelDX2 OverDrive processors, // IntelDX2 processors case 4: // Intel486 SL processor case 5: // IntelSX2 processors case 7: // Write-Back Enhanced IntelDX2 processors case 8: // IntelDX4 OverDrive processors, IntelDX4 processors default: *Type = INTEL_i486; break; } case 5: switch (Model) { case 1: // Pentium OverDrive processor for Pentium processor (60, 66), // Pentium processors (60, 66) case 2: // Pentium OverDrive processor for Pentium processor (75, 90, // 100, 120, 133), Pentium processors (75, 90, 100, 120, 133, // 150, 166, 200) case 3: // Pentium OverDrive processors for Intel486 processor-based // systems *Type = INTEL_PENTIUM; break; case 4: // Pentium OverDrive processor with MMX technology for Pentium // processor (75, 90, 100, 120, 133), Pentium processor with // MMX technology (166, 200) *Type = INTEL_PENTIUM; *Subtype = INTEL_PENTIUM_MMX; break; default: *Type = INTEL_PENTIUM; break; } case 6: switch (Model) { case 0x01: // Pentium Pro processor *Type = INTEL_PENTIUM_PRO; break; case 0x03: // Intel Pentium II OverDrive processor, Pentium II processor, // model 03 case 0x05: // Pentium II processor, model 05, Pentium II Xeon processor, // model 05, and Intel Celeron processor, model 05 case 0x06: // Celeron processor, model 06 *Type = INTEL_PENTIUM_II; break; case 0x07: // Pentium III processor, model 07, and Pentium III Xeon // processor, model 07 case 0x08: // Pentium III processor, model 08, Pentium III Xeon processor, // model 08, and Celeron processor, model 08 case 0x0a: // Pentium III Xeon processor, model 0Ah case 0x0b: // Pentium III processor, model 0Bh *Type = INTEL_PENTIUM_III; break; case 0x09: // Intel Pentium M processor, Intel Celeron M processor model 09. case 0x0d: // Intel Pentium M processor, Intel Celeron M processor, model // 0Dh. All processors are manufactured using the 90 nm process. case 0x15: // Intel EP80579 Integrated Processor and Intel EP80579 // Integrated Processor with Intel QuickAssist Technology *Type = INTEL_PENTIUM_M; break; case 0x0e: // Intel Core Duo processor, Intel Core Solo processor, model // 0Eh. All processors are manufactured using the 65 nm process. *Type = INTEL_CORE_DUO; break; // yonah case 0x0f: // Intel Core 2 Duo processor, Intel Core 2 Duo mobile // processor, Intel Core 2 Quad processor, Intel Core 2 Quad // mobile processor, Intel Core 2 Extreme processor, Intel // Pentium Dual-Core processor, Intel Xeon processor, model // 0Fh. All processors are manufactured using the 65 nm process. case 0x16: // Intel Celeron processor model 16h. All processors are // manufactured using the 65 nm process *Type = INTEL_CORE2; // "core2" *Subtype = INTEL_CORE2_65; break; case 0x17: // Intel Core 2 Extreme processor, Intel Xeon processor, model // 17h. All processors are manufactured using the 45 nm process. // // 45nm: Penryn , Wolfdale, Yorkfield (XE) case 0x1d: // Intel Xeon processor MP. All processors are manufactured using // the 45 nm process. *Type = INTEL_CORE2; // "penryn" *Subtype = INTEL_CORE2_45; break; case 0x1a: // Intel Core i7 processor and Intel Xeon processor. All // processors are manufactured using the 45 nm process. case 0x1e: // Intel(R) Core(TM) i7 CPU 870 @ 2.93GHz. // As found in a Summer 2010 model iMac. case 0x1f: case 0x2e: // Nehalem EX *Type = INTEL_COREI7; // "nehalem" *Subtype = INTEL_COREI7_NEHALEM; break; case 0x25: // Intel Core i7, laptop version. case 0x2c: // Intel Core i7 processor and Intel Xeon processor. All // processors are manufactured using the 32 nm process. case 0x2f: // Westmere EX *Type = INTEL_COREI7; // "westmere" *Subtype = INTEL_COREI7_WESTMERE; break; case 0x2a: // Intel Core i7 processor. All processors are manufactured // using the 32 nm process. case 0x2d: *Type = INTEL_COREI7; //"sandybridge" *Subtype = INTEL_COREI7_SANDYBRIDGE; break; case 0x3a: case 0x3e: // Ivy Bridge EP *Type = INTEL_COREI7; // "ivybridge" *Subtype = INTEL_COREI7_IVYBRIDGE; break; // Haswell: case 0x3c: case 0x3f: case 0x45: case 0x46: *Type = INTEL_COREI7; // "haswell" *Subtype = INTEL_COREI7_HASWELL; break; // Broadwell: case 0x3d: case 0x47: case 0x4f: case 0x56: *Type = INTEL_COREI7; // "broadwell" *Subtype = INTEL_COREI7_BROADWELL; break; // Skylake: case 0x4e: *Type = INTEL_COREI7; // "skylake-avx512" *Subtype = INTEL_COREI7_SKYLAKE_AVX512; break; case 0x5e: *Type = INTEL_COREI7; // "skylake" *Subtype = INTEL_COREI7_SKYLAKE; break; case 0x1c: // Most 45 nm Intel Atom processors case 0x26: // 45 nm Atom Lincroft case 0x27: // 32 nm Atom Medfield case 0x35: // 32 nm Atom Midview case 0x36: // 32 nm Atom Midview *Type = INTEL_ATOM; *Subtype = INTEL_ATOM_BONNELL; break; // "bonnell" // Atom Silvermont codes from the Intel software optimization guide. case 0x37: case 0x4a: case 0x4d: case 0x5a: case 0x5d: case 0x4c: // really airmont *Type = INTEL_ATOM; *Subtype = INTEL_ATOM_SILVERMONT; break; // "silvermont" case 0x57: *Type = INTEL_XEONPHI; // knl *Subtype = INTEL_KNIGHTS_LANDING; break; default: // Unknown family 6 CPU, try to guess. if (Features & (1 << FEATURE_AVX512)) { *Type = INTEL_XEONPHI; // knl *Subtype = INTEL_KNIGHTS_LANDING; break; } if (Features & (1 << FEATURE_ADX)) { *Type = INTEL_COREI7; *Subtype = INTEL_COREI7_BROADWELL; break; } if (Features & (1 << FEATURE_AVX2)) { *Type = INTEL_COREI7; *Subtype = INTEL_COREI7_HASWELL; break; } if (Features & (1 << FEATURE_AVX)) { *Type = INTEL_COREI7; *Subtype = INTEL_COREI7_SANDYBRIDGE; break; } if (Features & (1 << FEATURE_SSE4_2)) { if (Features & (1 << FEATURE_MOVBE)) { *Type = INTEL_ATOM; *Subtype = INTEL_ATOM_SILVERMONT; } else { *Type = INTEL_COREI7; *Subtype = INTEL_COREI7_NEHALEM; } break; } if (Features & (1 << FEATURE_SSE4_1)) { *Type = INTEL_CORE2; // "penryn" *Subtype = INTEL_CORE2_45; break; } if (Features & (1 << FEATURE_SSSE3)) { if (Features & (1 << FEATURE_MOVBE)) { *Type = INTEL_ATOM; *Subtype = INTEL_ATOM_BONNELL; // "bonnell" } else { *Type = INTEL_CORE2; // "core2" *Subtype = INTEL_CORE2_65; } break; } if (Features & (1 << FEATURE_EM64T)) { *Type = INTEL_X86_64; break; // x86-64 } if (Features & (1 << FEATURE_SSE2)) { *Type = INTEL_PENTIUM_M; break; } if (Features & (1 << FEATURE_SSE)) { *Type = INTEL_PENTIUM_III; break; } if (Features & (1 << FEATURE_MMX)) { *Type = INTEL_PENTIUM_II; break; } *Type = INTEL_PENTIUM_PRO; break; } case 15: { switch (Model) { case 0: // Pentium 4 processor, Intel Xeon processor. All processors are // model 00h and manufactured using the 0.18 micron process. case 1: // Pentium 4 processor, Intel Xeon processor, Intel Xeon // processor MP, and Intel Celeron processor. All processors are // model 01h and manufactured using the 0.18 micron process. case 2: // Pentium 4 processor, Mobile Intel Pentium 4 processor - M, // Intel Xeon processor, Intel Xeon processor MP, Intel Celeron // processor, and Mobile Intel Celeron processor. All processors // are model 02h and manufactured using the 0.13 micron process. *Type = ((Features & (1 << FEATURE_EM64T)) ? INTEL_X86_64 : INTEL_PENTIUM_IV); break; case 3: // Pentium 4 processor, Intel Xeon processor, Intel Celeron D // processor. All processors are model 03h and manufactured using // the 90 nm process. case 4: // Pentium 4 processor, Pentium 4 processor Extreme Edition, // Pentium D processor, Intel Xeon processor, Intel Xeon // processor MP, Intel Celeron D processor. All processors are // model 04h and manufactured using the 90 nm process. case 6: // Pentium 4 processor, Pentium D processor, Pentium processor // Extreme Edition, Intel Xeon processor, Intel Xeon processor // MP, Intel Celeron D processor. All processors are model 06h // and manufactured using the 65 nm process. *Type = ((Features & (1 << FEATURE_EM64T)) ? INTEL_NOCONA : INTEL_PRESCOTT); break; default: *Type = ((Features & (1 << FEATURE_EM64T)) ? INTEL_X86_64 : INTEL_PENTIUM_IV); break; } } default: break; /*"generic"*/ } } static void getAMDProcessorTypeAndSubtype(unsigned int Family, unsigned int Model, unsigned int Features, unsigned *Type, unsigned *Subtype) { // FIXME: this poorly matches the generated SubtargetFeatureKV table. There // appears to be no way to generate the wide variety of AMD-specific targets // from the information returned from CPUID. switch (Family) { case 4: *Type = AMD_i486; case 5: *Type = AMDPENTIUM; switch (Model) { case 6: case 7: *Subtype = AMDPENTIUM_K6; break; // "k6" case 8: *Subtype = AMDPENTIUM_K62; break; // "k6-2" case 9: case 13: *Subtype = AMDPENTIUM_K63; break; // "k6-3" case 10: *Subtype = AMDPENTIUM_GEODE; break; // "geode" default: break; } case 6: *Type = AMDATHLON; switch (Model) { case 4: *Subtype = AMDATHLON_TBIRD; break; // "athlon-tbird" case 6: case 7: case 8: *Subtype = AMDATHLON_MP; break; // "athlon-mp" case 10: *Subtype = AMDATHLON_XP; break; // "athlon-xp" default: break; } case 15: *Type = AMDATHLON; if (Features & (1 << FEATURE_SSE3)) { *Subtype = AMDATHLON_K8SSE3; break; // "k8-sse3" } switch (Model) { case 1: *Subtype = AMDATHLON_OPTERON; break; // "opteron" case 5: *Subtype = AMDATHLON_FX; break; // "athlon-fx"; also opteron default: *Subtype = AMDATHLON_64; break; // "athlon64" } case 16: *Type = AMDFAM10H; // "amdfam10" switch (Model) { case 2: *Subtype = AMDFAM10H_BARCELONA; break; case 4: *Subtype = AMDFAM10H_SHANGHAI; break; case 8: *Subtype = AMDFAM10H_ISTANBUL; break; default: break; } case 20: *Type = AMDFAM14H; *Subtype = AMD_BTVER1; break; // "btver1"; case 21: *Type = AMDFAM15H; if (!(Features & (1 << FEATURE_AVX))) { // If no AVX support, provide a sane fallback. *Subtype = AMD_BTVER1; break; // "btver1" } if (Model >= 0x50 && Model <= 0x6f) { *Subtype = AMDFAM15H_BDVER4; break; // "bdver4"; 50h-6Fh: Excavator } if (Model >= 0x30 && Model <= 0x3f) { *Subtype = AMDFAM15H_BDVER3; break; // "bdver3"; 30h-3Fh: Steamroller } if (Model >= 0x10 && Model <= 0x1f) { *Subtype = AMDFAM15H_BDVER2; break; // "bdver2"; 10h-1Fh: Piledriver } if (Model <= 0x0f) { *Subtype = AMDFAM15H_BDVER1; break; // "bdver1"; 00h-0Fh: Bulldozer } break; case 22: *Type = AMDFAM16H; if (!(Features & (1 << FEATURE_AVX))) { // If no AVX support provide a sane fallback. *Subtype = AMD_BTVER1; break; // "btver1"; } *Subtype = AMD_BTVER2; break; // "btver2" default: break; // "generic" } } static unsigned getAvailableFeatures(unsigned int ECX, unsigned int EDX, unsigned MaxLeaf) { unsigned Features = 0; unsigned int EAX, EBX; Features |= (((EDX >> 23) & 1) << FEATURE_MMX); Features |= (((EDX >> 25) & 1) << FEATURE_SSE); Features |= (((EDX >> 26) & 1) << FEATURE_SSE2); Features |= (((ECX >> 0) & 1) << FEATURE_SSE3); Features |= (((ECX >> 9) & 1) << FEATURE_SSSE3); Features |= (((ECX >> 19) & 1) << FEATURE_SSE4_1); Features |= (((ECX >> 20) & 1) << FEATURE_SSE4_2); Features |= (((ECX >> 22) & 1) << FEATURE_MOVBE); // If CPUID indicates support for XSAVE, XRESTORE and AVX, and XGETBV // indicates that the AVX registers will be saved and restored on context // switch, then we have full AVX support. const unsigned AVXBits = (1 << 27) | (1 << 28); bool HasAVX = ((ECX & AVXBits) == AVXBits) && !getX86XCR0(&EAX, &EDX) && ((EAX & 0x6) == 0x6); bool HasAVX512Save = HasAVX && ((EAX & 0xe0) == 0xe0); bool HasLeaf7 = MaxLeaf >= 0x7; getX86CpuIDAndInfoEx(0x7, 0x0, &EAX, &EBX, &ECX, &EDX); bool HasADX = HasLeaf7 && ((EBX >> 19) & 1); bool HasAVX2 = HasAVX && HasLeaf7 && (EBX & 0x20); bool HasAVX512 = HasLeaf7 && HasAVX512Save && ((EBX >> 16) & 1); Features |= (HasAVX << FEATURE_AVX); Features |= (HasAVX2 << FEATURE_AVX2); Features |= (HasAVX512 << FEATURE_AVX512); Features |= (HasAVX512Save << FEATURE_AVX512SAVE); Features |= (HasADX << FEATURE_ADX); getX86CpuIDAndInfo(0x80000001, &EAX, &EBX, &ECX, &EDX); Features |= (((EDX >> 29) & 0x1) << FEATURE_EM64T); return Features; } -#ifdef HAVE_INIT_PRIORITY -#define CONSTRUCTOR_PRIORITY (101) +#if defined(HAVE_INIT_PRIORITY) +#define CONSTRUCTOR_ATTRIBUTE __attribute__((__constructor__ 101)) +#elif __has_attribute(__constructor__) +#define CONSTRUCTOR_ATTRIBUTE __attribute__((__constructor__)) #else -#define CONSTRUCTOR_PRIORITY +// FIXME: For MSVC, we should make a function pointer global in .CRT$X?? so that +// this runs during initialization. +#define CONSTRUCTOR_ATTRIBUTE #endif -int __cpu_indicator_init(void) - __attribute__((constructor CONSTRUCTOR_PRIORITY)); +int __cpu_indicator_init(void) CONSTRUCTOR_ATTRIBUTE; struct __processor_model { unsigned int __cpu_vendor; unsigned int __cpu_type; unsigned int __cpu_subtype; unsigned int __cpu_features[1]; } __cpu_model = {0, 0, 0, {0}}; /* A constructor function that is sets __cpu_model and __cpu_features with the right values. This needs to run only once. This constructor is given the highest priority and it should run before constructors without the priority set. However, it still runs after ifunc initializers and needs to be called explicitly there. */ -int __attribute__((constructor CONSTRUCTOR_PRIORITY)) +int CONSTRUCTOR_ATTRIBUTE __cpu_indicator_init(void) { unsigned int EAX, EBX, ECX, EDX; unsigned int MaxLeaf = 5; unsigned int Vendor; unsigned int Model, Family, Brand_id; unsigned int Features = 0; /* This function needs to run just once. */ if (__cpu_model.__cpu_vendor) return 0; if (!isCpuIdSupported()) return -1; /* Assume cpuid insn present. Run in level 0 to get vendor id. */ getX86CpuIDAndInfo(0, &MaxLeaf, &Vendor, &ECX, &EDX); if (MaxLeaf < 1) { __cpu_model.__cpu_vendor = VENDOR_OTHER; return -1; } getX86CpuIDAndInfo(1, &EAX, &EBX, &ECX, &EDX); detectX86FamilyModel(EAX, &Family, &Model); Brand_id = EBX & 0xff; /* Find available features. */ Features = getAvailableFeatures(ECX, EDX, MaxLeaf); __cpu_model.__cpu_features[0] = Features; if (Vendor == SIG_INTEL) { /* Get CPU type. */ getIntelProcessorTypeAndSubtype(Family, Model, Brand_id, Features, &(__cpu_model.__cpu_type), &(__cpu_model.__cpu_subtype)); __cpu_model.__cpu_vendor = VENDOR_INTEL; } else if (Vendor == SIG_AMD) { /* Get CPU type. */ getAMDProcessorTypeAndSubtype(Family, Model, Features, &(__cpu_model.__cpu_type), &(__cpu_model.__cpu_subtype)); __cpu_model.__cpu_vendor = VENDOR_AMD; } else __cpu_model.__cpu_vendor = VENDOR_OTHER; assert(__cpu_model.__cpu_vendor < VENDOR_MAX); assert(__cpu_model.__cpu_type < CPU_TYPE_MAX); assert(__cpu_model.__cpu_subtype < CPU_SUBTYPE_MAX); return 0; } #endif Index: projects/clang500-import/contrib/compiler-rt/lib/builtins/divtc3.c =================================================================== --- projects/clang500-import/contrib/compiler-rt/lib/builtins/divtc3.c (revision 317284) +++ projects/clang500-import/contrib/compiler-rt/lib/builtins/divtc3.c (revision 317285) @@ -1,60 +1,60 @@ /*===-- divtc3.c - Implement __divtc3 -------------------------------------=== * * 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 __divtc3 for the compiler_rt library. * *===----------------------------------------------------------------------=== */ #include "int_lib.h" #include "int_math.h" /* Returns: the quotient of (a + ib) / (c + id) */ -COMPILER_RT_ABI long double _Complex +COMPILER_RT_ABI Lcomplex __divtc3(long double __a, long double __b, long double __c, long double __d) { int __ilogbw = 0; long double __logbw = crt_logbl(crt_fmaxl(crt_fabsl(__c), crt_fabsl(__d))); if (crt_isfinite(__logbw)) { __ilogbw = (int)__logbw; __c = crt_scalbnl(__c, -__ilogbw); __d = crt_scalbnl(__d, -__ilogbw); } long double __denom = __c * __c + __d * __d; - long double _Complex z; - __real__ z = crt_scalbnl((__a * __c + __b * __d) / __denom, -__ilogbw); - __imag__ z = crt_scalbnl((__b * __c - __a * __d) / __denom, -__ilogbw); - if (crt_isnan(__real__ z) && crt_isnan(__imag__ z)) + Lcomplex z; + COMPLEX_REAL(z) = crt_scalbnl((__a * __c + __b * __d) / __denom, -__ilogbw); + COMPLEX_IMAGINARY(z) = crt_scalbnl((__b * __c - __a * __d) / __denom, -__ilogbw); + if (crt_isnan(COMPLEX_REAL(z)) && crt_isnan(COMPLEX_IMAGINARY(z))) { if ((__denom == 0.0) && (!crt_isnan(__a) || !crt_isnan(__b))) { - __real__ z = crt_copysignl(CRT_INFINITY, __c) * __a; - __imag__ z = crt_copysignl(CRT_INFINITY, __c) * __b; + COMPLEX_REAL(z) = crt_copysignl(CRT_INFINITY, __c) * __a; + COMPLEX_IMAGINARY(z) = crt_copysignl(CRT_INFINITY, __c) * __b; } else if ((crt_isinf(__a) || crt_isinf(__b)) && crt_isfinite(__c) && crt_isfinite(__d)) { __a = crt_copysignl(crt_isinf(__a) ? 1.0 : 0.0, __a); __b = crt_copysignl(crt_isinf(__b) ? 1.0 : 0.0, __b); - __real__ z = CRT_INFINITY * (__a * __c + __b * __d); - __imag__ z = CRT_INFINITY * (__b * __c - __a * __d); + COMPLEX_REAL(z) = CRT_INFINITY * (__a * __c + __b * __d); + COMPLEX_IMAGINARY(z) = CRT_INFINITY * (__b * __c - __a * __d); } else if (crt_isinf(__logbw) && __logbw > 0.0 && crt_isfinite(__a) && crt_isfinite(__b)) { __c = crt_copysignl(crt_isinf(__c) ? 1.0 : 0.0, __c); __d = crt_copysignl(crt_isinf(__d) ? 1.0 : 0.0, __d); - __real__ z = 0.0 * (__a * __c + __b * __d); - __imag__ z = 0.0 * (__b * __c - __a * __d); + COMPLEX_REAL(z) = 0.0 * (__a * __c + __b * __d); + COMPLEX_IMAGINARY(z) = 0.0 * (__b * __c - __a * __d); } } return z; } Index: projects/clang500-import/contrib/compiler-rt/lib/builtins/int_lib.h =================================================================== --- projects/clang500-import/contrib/compiler-rt/lib/builtins/int_lib.h (revision 317284) +++ projects/clang500-import/contrib/compiler-rt/lib/builtins/int_lib.h (revision 317285) @@ -1,159 +1,157 @@ /* ===-- 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) +# if defined(COMPILER_RT_ARMHF_TARGET) || (!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 +# define COMPILER_RT_ABI # else -# define COMPILER_RT_ABI __attribute__((pcs("aapcs"))) +# 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) { unsigned long trailing_zero = 0; if (_BitScanForward(&trailing_zero, value)) return trailing_zero; return 32; } uint32_t __inline __builtin_clz(uint32_t value) { 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) { 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/clang500-import/contrib/compiler-rt/lib/builtins/os_version_check.c =================================================================== --- projects/clang500-import/contrib/compiler-rt/lib/builtins/os_version_check.c (nonexistent) +++ projects/clang500-import/contrib/compiler-rt/lib/builtins/os_version_check.c (revision 317285) @@ -0,0 +1,178 @@ +/* ===-- os_version_check.c - OS version checking -------------------------=== + * + * 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 function __isOSVersionAtLeast, used by + * Objective-C's @available + * + * ===----------------------------------------------------------------------=== + */ + +#ifdef __APPLE__ + +#include +#include +#include +#include +#include +#include +#include +#include + +/* These three variables hold the host's OS version. */ +static int32_t GlobalMajor, GlobalMinor, GlobalSubminor; +static dispatch_once_t DispatchOnceCounter; + +/* Find and parse the SystemVersion.plist file. */ +static void parseSystemVersionPList(void *Unused) { + (void)Unused; + /* Load CoreFoundation dynamically */ + const void *NullAllocator = dlsym(RTLD_DEFAULT, "kCFAllocatorNull"); + if (!NullAllocator) + return; + const CFAllocatorRef kCFAllocatorNull = + *(const CFAllocatorRef *)NullAllocator; + typeof(CFDataCreateWithBytesNoCopy) *CFDataCreateWithBytesNoCopyFunc = + (typeof(CFDataCreateWithBytesNoCopy) *)dlsym( + RTLD_DEFAULT, "CFDataCreateWithBytesNoCopy"); + if (!CFDataCreateWithBytesNoCopyFunc) + return; + typeof(CFPropertyListCreateWithData) *CFPropertyListCreateWithDataFunc = + (typeof(CFPropertyListCreateWithData) *)dlsym( + RTLD_DEFAULT, "CFPropertyListCreateWithData"); + /* CFPropertyListCreateWithData was introduced only in macOS 10.6+, so it + * will be NULL on earlier OS versions. */ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" + typeof(CFPropertyListCreateFromXMLData) *CFPropertyListCreateFromXMLDataFunc = + (typeof(CFPropertyListCreateFromXMLData) *)dlsym( + RTLD_DEFAULT, "CFPropertyListCreateFromXMLData"); +#pragma clang diagnostic pop + /* CFPropertyListCreateFromXMLDataFunc is deprecated in macOS 10.10, so it + * might be NULL in future OS versions. */ + if (!CFPropertyListCreateWithDataFunc && !CFPropertyListCreateFromXMLDataFunc) + return; + typeof(CFStringCreateWithCStringNoCopy) *CFStringCreateWithCStringNoCopyFunc = + (typeof(CFStringCreateWithCStringNoCopy) *)dlsym( + RTLD_DEFAULT, "CFStringCreateWithCStringNoCopy"); + if (!CFStringCreateWithCStringNoCopyFunc) + return; + typeof(CFDictionaryGetValue) *CFDictionaryGetValueFunc = + (typeof(CFDictionaryGetValue) *)dlsym(RTLD_DEFAULT, + "CFDictionaryGetValue"); + if (!CFDictionaryGetValueFunc) + return; + typeof(CFGetTypeID) *CFGetTypeIDFunc = + (typeof(CFGetTypeID) *)dlsym(RTLD_DEFAULT, "CFGetTypeID"); + if (!CFGetTypeIDFunc) + return; + typeof(CFStringGetTypeID) *CFStringGetTypeIDFunc = + (typeof(CFStringGetTypeID) *)dlsym(RTLD_DEFAULT, "CFStringGetTypeID"); + if (!CFStringGetTypeIDFunc) + return; + typeof(CFStringGetCString) *CFStringGetCStringFunc = + (typeof(CFStringGetCString) *)dlsym(RTLD_DEFAULT, "CFStringGetCString"); + if (!CFStringGetCStringFunc) + return; + typeof(CFRelease) *CFReleaseFunc = + (typeof(CFRelease) *)dlsym(RTLD_DEFAULT, "CFRelease"); + if (!CFReleaseFunc) + return; + + char *PListPath = "/System/Library/CoreServices/SystemVersion.plist"; + +#if TARGET_OS_SIMULATOR + char *PListPathPrefix = getenv("IPHONE_SIMULATOR_ROOT"); + if (!PListPathPrefix) + return; + char FullPath[strlen(PListPathPrefix) + strlen(PListPath) + 1]; + strcpy(FullPath, PListPathPrefix); + strcat(FullPath, PListPath); + PListPath = FullPath; +#endif + FILE *PropertyList = fopen(PListPath, "r"); + if (!PropertyList) + return; + + /* Dynamically allocated stuff. */ + CFDictionaryRef PListRef = NULL; + CFDataRef FileContentsRef = NULL; + UInt8 *PListBuf = NULL; + + fseek(PropertyList, 0, SEEK_END); + long PListFileSize = ftell(PropertyList); + if (PListFileSize < 0) + goto Fail; + rewind(PropertyList); + + PListBuf = malloc((size_t)PListFileSize); + if (!PListBuf) + goto Fail; + + size_t NumRead = fread(PListBuf, 1, (size_t)PListFileSize, PropertyList); + if (NumRead != (size_t)PListFileSize) + goto Fail; + + /* Get the file buffer into CF's format. We pass in a null allocator here * + * because we free PListBuf ourselves */ + FileContentsRef = (*CFDataCreateWithBytesNoCopyFunc)( + NULL, PListBuf, (CFIndex)NumRead, kCFAllocatorNull); + if (!FileContentsRef) + goto Fail; + + if (CFPropertyListCreateWithDataFunc) + PListRef = (*CFPropertyListCreateWithDataFunc)( + NULL, FileContentsRef, kCFPropertyListImmutable, NULL, NULL); + else + PListRef = (*CFPropertyListCreateFromXMLDataFunc)( + NULL, FileContentsRef, kCFPropertyListImmutable, NULL); + if (!PListRef) + goto Fail; + + CFStringRef ProductVersion = (*CFStringCreateWithCStringNoCopyFunc)( + NULL, "ProductVersion", kCFStringEncodingASCII, kCFAllocatorNull); + if (!ProductVersion) + goto Fail; + CFTypeRef OpaqueValue = (*CFDictionaryGetValueFunc)(PListRef, ProductVersion); + (*CFReleaseFunc)(ProductVersion); + if (!OpaqueValue || + (*CFGetTypeIDFunc)(OpaqueValue) != (*CFStringGetTypeIDFunc)()) + goto Fail; + + char VersionStr[32]; + if (!(*CFStringGetCStringFunc)((CFStringRef)OpaqueValue, VersionStr, + sizeof(VersionStr), kCFStringEncodingUTF8)) + goto Fail; + sscanf(VersionStr, "%d.%d.%d", &GlobalMajor, &GlobalMinor, &GlobalSubminor); + +Fail: + if (PListRef) + (*CFReleaseFunc)(PListRef); + if (FileContentsRef) + (*CFReleaseFunc)(FileContentsRef); + free(PListBuf); + fclose(PropertyList); +} + +int32_t __isOSVersionAtLeast(int32_t Major, int32_t Minor, int32_t Subminor) { + /* Populate the global version variables, if they haven't already. */ + dispatch_once_f(&DispatchOnceCounter, NULL, parseSystemVersionPList); + + if (Major < GlobalMajor) return 1; + if (Major > GlobalMajor) return 0; + if (Minor < GlobalMinor) return 1; + if (Minor > GlobalMinor) return 0; + return Subminor <= GlobalSubminor; +} + +#else + +/* Silence an empty translation unit warning. */ +typedef int unused; + +#endif Property changes on: projects/clang500-import/contrib/compiler-rt/lib/builtins/os_version_check.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/clang500-import/contrib/compiler-rt/lib/builtins/x86_64/floatdidf.c =================================================================== --- projects/clang500-import/contrib/compiler-rt/lib/builtins/x86_64/floatdidf.c (revision 317284) +++ projects/clang500-import/contrib/compiler-rt/lib/builtins/x86_64/floatdidf.c (revision 317285) @@ -1,16 +1,16 @@ /* This file is distributed under the University of Illinois Open Source * License. See LICENSE.TXT for details. */ /* double __floatdidf(di_int a); */ -#ifdef __x86_64__ +#if defined(__x86_64__) || defined(_M_X64) #include "../int_lib.h" double __floatdidf(int64_t a) { return (double)a; } #endif /* __x86_64__ */ Index: projects/clang500-import/contrib/compiler-rt/lib/builtins/x86_64/floatdisf.c =================================================================== --- projects/clang500-import/contrib/compiler-rt/lib/builtins/x86_64/floatdisf.c (revision 317284) +++ projects/clang500-import/contrib/compiler-rt/lib/builtins/x86_64/floatdisf.c (revision 317285) @@ -1,14 +1,14 @@ /* This file is distributed under the University of Illinois Open Source * License. See LICENSE.TXT for details. */ -#ifdef __x86_64__ +#if defined(__x86_64__) || defined(_M_X64) #include "../int_lib.h" float __floatdisf(int64_t a) { return (float)a; } #endif /* __x86_64__ */ Index: projects/clang500-import/contrib/compiler-rt/lib/cfi/cfi.cc =================================================================== --- projects/clang500-import/contrib/compiler-rt/lib/cfi/cfi.cc (revision 317284) +++ projects/clang500-import/contrib/compiler-rt/lib/cfi/cfi.cc (revision 317285) @@ -1,422 +1,430 @@ //===-------- 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; + uptr strtab = 0, symtab = 0, strsz = 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; + else if (p->d_tag == DT_STRSZ) + strsz = 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) + if (strtab >= beg && strtab + strsz < 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) { + // There is no reliable way to find the end of the symbol table. In + // lld-produces files, there are other sections between symtab and strtab. + // Stop looking when the symbol name is not inside strtab. + if (p->st_name >= strsz) break; char *name = (char*)(strtab + p->st_name); if (strcmp(name, "__cfi_check") == 0) { - assert(p->st_info == ELF32_ST_INFO(STB_GLOBAL, STT_FUNC)); + assert(p->st_info == ELF32_ST_INFO(STB_GLOBAL, STT_FUNC) || + p->st_info == ELF32_ST_INFO(STB_WEAK, 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/clang500-import/contrib/compiler-rt/lib/dfsan/done_abilist.txt =================================================================== --- projects/clang500-import/contrib/compiler-rt/lib/dfsan/done_abilist.txt (revision 317284) +++ projects/clang500-import/contrib/compiler-rt/lib/dfsan/done_abilist.txt (revision 317285) @@ -1,314 +1,300 @@ 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/clang500-import/contrib/compiler-rt/lib/esan/esan_interceptors.cpp =================================================================== --- projects/clang500-import/contrib/compiler-rt/lib/esan/esan_interceptors.cpp (revision 317284) +++ projects/clang500-import/contrib/compiler-rt/lib/esan/esan_interceptors.cpp (revision 317285) @@ -1,561 +1,547 @@ //===-- 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 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. // 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. // 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. 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; // 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/clang500-import/contrib/compiler-rt/lib/interception/interception_win.cc =================================================================== --- projects/clang500-import/contrib/compiler-rt/lib/interception/interception_win.cc (revision 317284) +++ projects/clang500-import/contrib/compiler-rt/lib/interception/interception_win.cc (revision 317285) @@ -1,1006 +1,1008 @@ //===-- 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